工作需要,寫了服務器端的支付和退款功能,包含微信和支付寶,網上也有很多demo可以借鑒,我把我的代碼放出來,寫的比較簡單,有問題的歡迎指正,大家一起學習。
微信支付需要調用微信的統一下單接口,而支付寶不用。
我寫的時候微信和支付寶都單獨寫了一個工具類,來調用支付,給前端返回需要的數據。
ps:支付是可以不需要服務器端的,不過為了安全一點點,所以前端需要調起支付的字段都直接從服務器端返回,前端拿到字段直接調起支付就可以了。
1
2
3
4
5
6
7
8
9
|
map<string,string> map = new hashmap<string,string>(); switch (record.getchecktype()) { case 10 : map = alipay.prepay(record.getamount(),out_trade_no); return responsedata.ok(map); case 20 : map = wxpay.prepay(record.getamount(),out_trade_no); return responsedata.ok(map); } |
10是支付寶支付,20是微信支付,map里存放前端需要的字段,直接返回給手機端
其中out_trade_no這個是商戶自己生成的唯一訂單號
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
|
public class wxpay { private static string url = string.format( "https://api.mch.weixin.qq.com/pay/unifiedorder" ); //統一下單 public static map<string,string> prepay(bigdecimal amount,string out_trade_no){ string entity = genproductargs(amount,out_trade_no); byte [] buf = util.httppost(url, entity); string content = new string(buf); map<string,string> xml=decodexml(content); return getrep(xml); } private static map<string, string> getrep(map<string, string> xml) { random random = new random(); list<namevaluepair> signparams = new linkedlist<namevaluepair>(); signparams.add( new basicnamevaluepair( "appid" , constants.app_id_wx)); signparams.add( new basicnamevaluepair( "noncestr" , md5.getmessagedigest(string.valueof(random.nextint( 10000 )).getbytes()))); // signparams.add(new basicnamevaluepair("package", "prepay_id="+xml.get("prepay_id"))); signparams.add( new basicnamevaluepair( "package" , "sign=wxpay" )); signparams.add( new basicnamevaluepair( "partnerid" , constants.mch_id)); signparams.add( new basicnamevaluepair( "prepayid" , xml.get( "prepay_id" ))); signparams.add( new basicnamevaluepair( "timestamp" , string.valueof(system.currenttimemillis() / 1000 ))); xml.put( "sign" , genpackagesign(signparams)); for ( int i = 0 ; i < signparams.size(); i++) { xml.put(signparams.get(i).getname(),signparams.get(i).getvalue()); } return removeelements(xml); } private static map<string, string> removeelements(map<string, string> xml) { xml.remove( "appid" ); xml.remove( "mch_id" ); xml.remove( "nonce_str" ); xml.remove( "trade_type" ); //xml.remove("partnerid"); xml.remove( "prepay_id" ); xml.remove( "result_code" ); xml.remove( "return_code" ); xml.remove( "return_msg" ); return xml; } private static string genproductargs(bigdecimal amount,string out_trade_no) { stringbuffer xml = new stringbuffer(); string noncestr = gennoncestr(); xml.append( "</xml>" ); list<namevaluepair> packageparams = new linkedlist<namevaluepair>(); packageparams.add( new basicnamevaluepair( "appid" , constants.app_id_wx)); packageparams.add( new basicnamevaluepair( "body" , "app pay test" )); packageparams.add( new basicnamevaluepair( "mch_id" , constants.mch_id)); packageparams.add( new basicnamevaluepair( "nonce_str" , noncestr)); packageparams.add( new basicnamevaluepair( "notify_url" , "填寫服務器的支付回調路徑" )); packageparams.add( new basicnamevaluepair( "out_trade_no" ,out_trade_no)); packageparams.add( new basicnamevaluepair( "spbill_create_ip" , "127.0.0.1" )); packageparams.add( new basicnamevaluepair( "total_fee" , string.valueof(amount.movepointright( 2 )))); // packageparams.add(new basicnamevaluepair("total_fee", "1")); packageparams.add( new basicnamevaluepair( "trade_type" , "app" )); string sign = genpackagesign(packageparams); packageparams.add( new basicnamevaluepair( "sign" , sign)); string xmlstring =toxml(packageparams); return xmlstring; } public static string gennoncestr() { random random = new random(); return md5.getmessagedigest(string.valueof(random.nextint( 10000 )).getbytes()); } public static string genpackagesign(list<namevaluepair> params) { stringbuilder sb = new stringbuilder(); for ( int i = 0 ; i < params.size(); i++) { sb.append(params.get(i).getname()); sb.append( '=' ); sb.append(params.get(i).getvalue()); sb.append( '&' ); } sb.append( "key=" ); sb.append(constants.api_key); string packagesign = md5.getmessagedigest(sb.tostring().getbytes()).touppercase(); return packagesign; } public static string toxml(list<namevaluepair> params) { stringbuilder sb = new stringbuilder(); sb.append( "<xml>" ); for ( int i = 0 ; i < params.size(); i++) { sb.append( "<" +params.get(i).getname()+ ">" ); sb.append(params.get(i).getvalue()); sb.append( "</" +params.get(i).getname()+ ">" ); } sb.append( "</xml>" ); return sb.tostring(); } } |
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
|
public class alipay { public static map<string,string> prepay(bigdecimal payableamount,string out_trade_no){ //string orderinfo = getorderinfo("訂單付款", "訂單付款",out_trade_no,"0.01"); string orderinfo = getorderinfo( "訂單付款" , "訂單付款" ,out_trade_no,string.valueof(payableamount)); string sign = sign(orderinfo); try { /** * 僅需對sign 做url編碼 */ sign = urlencoder.encode(sign, "utf-8" ); } catch (unsupportedencodingexception e) { e.printstacktrace(); } /** * 完整的符合支付寶參數規范的訂單信息 */ final string payinfo = orderinfo + "&sign=\"" + sign + "\"&" + getsigntype(); map<string,string> map = new hashmap<string, string>(); map.put( "payinfo" , payinfo); return map; } private static string getorderinfo(string subject, string body,string out_trade_no,string price) { // 簽約合作者身份id string orderinfo = "partner=" + "\"" + constants.partner + "\"" ; // 簽約賣家支付寶賬號 orderinfo += "&seller_id=" + "\"" + constants.seller + "\"" ; // 商戶網站唯一訂單號 orderinfo += "&out_trade_no=" + "\"" + out_trade_no + "\"" ; // 商品名稱 orderinfo += "&subject=" + "\"" + subject + "\"" ; // 商品詳情 orderinfo += "&body=" + "\"" + body + "\"" ; // 商品金額 orderinfo += "&total_fee=" + "\"" + price + "\"" ; // 服務器異步通知頁面路徑 orderinfo += "¬ify_url=" + "\"" + "填寫服務器的支付回調路徑" + "\"" ; // 服務接口名稱, 固定值 orderinfo += "&service=\"mobile.securitypay.pay\"" ; // 支付類型, 固定值 orderinfo += "&payment_type=\"1\"" ; // 參數編碼, 固定值 orderinfo += "&_input_charset=\"utf-8\"" ; // 設置未付款交易的超時時間 // 默認30分鐘,一旦超時,該筆交易就會自動被關閉。 // 取值范圍:1m~15d。 // m-分鐘,h-小時,d-天,1c-當天(無論交易何時創建,都在0點關閉)。 // 該參數數值不接受小數點,如1.5h,可轉換為90m。 orderinfo += "&it_b_pay=\"30m\"" ; // extern_token為經過快登授權獲取到的alipay_open_id,帶上此參數用戶將使用授權的賬戶進行支付 // orderinfo += "&extern_token=" + "\"" + extern_token + "\""; // 支付寶處理完請求后,當前頁面跳轉到商戶指定頁面的路徑,可空 orderinfo += "&return_url=\"m.alipay.com\"" ; // 調用銀行卡支付,需配置此參數,參與簽名, 固定值 (需要簽約《無線銀行卡快捷支付》才能使用) // orderinfo += "&paymethod=\"expressgateway\""; return orderinfo; } private static string sign(string content) { return signutils.sign(content, constants.rsa_private); } private static string getsigntype() { return "sign_type=\"rsa\"" ; } } |
退款部分
支付寶
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
string strresponse = null ; alipaytraderefundresponse response = null ; try { alipayclient alipayclient = new defaultalipayclient(url,constants.appid_alipay,constants.rsa_private, "json" , "utf-8" ,constants.rsa_public); alipaytraderefundrequest request = new alipaytraderefundrequest(); refundinfo alidata = new refundinfo(); alidata.setout_trade_no(out_trade_no); alidata.setrefund_amount(refund_amount); request.setbizcontent(json.tojsonstring(alidata)); response = alipayclient.sdkexecute(request); if (response.issuccess()) { strresponse= "退款成功" ; } else { strresponse= "退款失敗" ; } return strresponse; } catch (exception e) { strresponse= "退款出錯" ; } return strresponse; |
微信
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
|
public class wxrefund { private static final string url = "https://api.mch.weixin.qq.com/secapi/pay/refund" ; /** * 微信退款 * @param out_trade_no 商戶訂單號 * @param total_fee 總金額 * @param refund_fee 退款金額 * @return */ public static string dorefund(string out_trade_no, int total_fee, int refund_fee) { inputstream instream = null ; keystore keystore = null ; closeablehttpresponse response = null ; closeablehttpclient httpclient = null ; stringbuilder text = new stringbuilder(); string key = constants.mch_id; try { /** * 注意pkcs12證書 是從微信商戶平臺-》賬戶設置-》 api安全 中下載的 */ keystore = keystore.getinstance( "pkcs12" ); instream = wxrefund. class .getresourceasstream( "/apiclient_cert.p12" ); //p12文件 /** * 此處要改 */ keystore.load(instream, key.tochararray()); // 這里寫密碼..默認是mchid /** * 此處要改 */ sslcontext sslcontext = sslcontexts.custom().loadkeymaterial(keystore, key.tochararray()) // 這里也是寫密碼的 .build(); // allow tlsv1 protocol only sslconnectionsocketfactory sslsf = new sslconnectionsocketfactory(sslcontext, new string[] { "tlsv1" }, null , sslconnectionsocketfactory.browser_compatible_hostname_verifier); httpclient = httpclients.custom().setsslsocketfactory(sslsf).build(); //=======================證書配置完成======================== httppost httppost = new httppost(url); string xmlstring = getrefunargs(out_trade_no,total_fee,refund_fee); httppost.setentity( new stringentity(xmlstring)); httppost.setheader( "accept" , "application/json" ); httppost.setheader( "content-type" , "application/json" ); response = httpclient.execute(httppost); httpentity entity = response.getentity(); if (entity != null ) { bufferedreader bufferedreader = new bufferedreader( new inputstreamreader(entity.getcontent())); string str; while ((str = bufferedreader.readline()) != null ) { text.append(str); } } entityutils.consume(entity); } catch (exception e){ } finally { if (instream != null ){ try { instream.close(); } catch (ioexception e) { e.printstacktrace(); } } if (response != null ){ try { response.close(); } catch (ioexception e) { e.printstacktrace(); } } if (httpclient != null ){ try { httpclient.close(); } catch (ioexception e) { e.printstacktrace(); } } } map<string,string> map = wxpay.decodexml(text.tostring()); string return_msg = map.get( "return_msg" ); if ( "ok" .equals(return_msg) && "success" .equals(map.get( "return_code" ))) { return "退款成功" ; } return return_msg; } //設置請求參數的值 private static string getrefunargs(string out_trade_no, int total_fee, int refund_fee) { string nonce_str = wxpay.gennoncestr(); list<namevaluepair> packageparams = new linkedlist<namevaluepair>(); packageparams.add( new basicnamevaluepair( "appid" , constants.app_id_wx)); packageparams.add( new basicnamevaluepair( "mch_id" , constants.mch_id)); packageparams.add( new basicnamevaluepair( "nonce_str" , nonce_str)); packageparams.add( new basicnamevaluepair( "op_user_id" , constants.mch_id)); packageparams.add( new basicnamevaluepair( "out_refund_no" ,out_trade_no)); packageparams.add( new basicnamevaluepair( "out_trade_no" ,out_trade_no)); packageparams.add( new basicnamevaluepair( "refund_fee" , string.valueof(refund_fee))); packageparams.add( new basicnamevaluepair( "total_fee" , string.valueof(total_fee))); string sign = wxpay.genpackagesign(packageparams); packageparams.add( new basicnamevaluepair( "sign" , sign)); return wxpay.toxml(packageparams); } } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:https://blog.csdn.net/l269327509/article/details/53518401