最近項(xiàng)目需要微信支付,然后看了下微信公眾號(hào)支付,,雖然不難,但是細(xì)節(jié)還是需要注意的,用了大半天時(shí)間寫(xiě)了個(gè)demo,并且完整的測(cè)試了一下支付流程,下面分享一下微信公眾號(hào)支付的經(jīng)驗(yàn)。
一、配置公眾號(hào)微信支付
需要我們配置微信公眾號(hào)支付地址和測(cè)試白名單。
比如:支付JS頁(yè)面的地址為 http://www.xxx.com/shop/pay/
那此處配置www.xxx.com/shop/pay/
二、開(kāi)發(fā)流程
借用微信公眾號(hào)支付api(地址 http://pay.weixin.qq.com/wiki/doc/api/index.PHP?chapter=7_4),我們需要開(kāi)發(fā)的為紅色標(biāo)記出的。如下:
三、向微信服務(wù)器端下訂單
調(diào)用統(tǒng)一下單接口,這樣就能獲取微信支付的prepay_id(http://pay.weixin.qq.com/wiki/doc/api/index.php?chapter=9_1)。
在調(diào)用該接口前有幾個(gè)字段是H5支付必須填寫(xiě)的openid
3.1 獲取openid
可以通過(guò)網(wǎng)頁(yè)授權(quán)形式(http://mp.weixin.qq.com/wiki/17/c0f37d5704f0b64713d5d2c37b468d75.html)
在微信中發(fā)送如下鏈接
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=要跳轉(zhuǎn)的下訂單的url&response_type=code&scope=snsapi_base&state=123#wechat_redirect
3.2 下訂單獲取prepay_id
代碼如下,實(shí)際上是通過(guò)post發(fā)送一個(gè)xml 文件,獲取微信服務(wù)器端發(fā)送過(guò)來(lái)的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" , "測(cè)試" ); paraMapput( "body" , "測(cè)試購(gòu)買(mǎi)支付" ); 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); // 統(tǒng)一下單 https://apimchweixinqqcom/pay/unifiedorder String url = "https://apimchweixinqqcom/pay/unifiedorder" ; String xml = ArrayToXml(paraMap); String xmlStr = HttpKitpost(url, xml); // 預(yù)付商品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轉(zhuǎn)成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設(shè)置要解析的xml數(shù)據(jù) 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支付其實(shí)很簡(jiǎn)單,只需要調(diào)用微信內(nèi)嵌瀏覽器的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>測(cè)試支付</title> <link href= "/css/csscss?v=0" rel= "stylesheet" type= "text/css" > </head> <body> <div class = "index_box" > <div class = "apply_name" >微信js支付測(cè)試</div> <div class = "branch_con" > <ul> <li><span class = "name" >測(cè)試支付信息</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, //公眾號(hào)名稱(chēng),由商戶(hù)傳入 "timeStamp" : timeStamp, //時(shí)間戳,自1970年以來(lái)的秒數(shù) "nonceStr" : nonceStr, //隨機(jī)串 "package" : "prepay_id=" + pg, "paySign" : paySign //微信簽名 }, function(res){ if (reserr_msg == "get_brand_wcpay_request:ok" ) { alert( "支付成功" ); } // 使用以上方式判斷前端返回,微信團(tuán)隊(duì)鄭重提示:reserr_msg將在用戶(hù)支付成功后返回 ok,但并不保證它絕對(duì)可靠。 } ); } 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> |
效果如下
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://blog.csdn.net/u014351782/article/details/52186932