1. 程式人生 > >java版+支付寶支付和微信支付(一)

java版+支付寶支付和微信支付(一)

最近公司在做支付模組,在接入過程中遇到了很多坑,費了不少事,現在分享一下接入方法,也記錄一下,以後可能還用的到。用的是支付寶的即時到帳支付功能和微信的掃碼支付功能,相比起來,個人感覺支付寶的文件和接入方式都比微信的容易理解和操作,也不用自己寫頁面,接入起來比較方便,畢竟是支付起家的,比微信支付少很多坑,下面就分別介紹著兩種支付的接入方法。

支付寶支付

1、申請簽約

申請方式在開放平臺的文件上有詳細說明,這裡就不再贅述。

2、接入支付介面

在得到PID和祕鑰後就可以接入介面了,首先在開放平臺中下載官方的demo(java+MD5版本),支付寶的demo做的非常好,下載下來直接配置下jdk就可以運行了。如果遇到Java compiler level does not match錯誤,說明你用的eclipse或myeclipse的jdk編譯版本與demo的JDK編譯版本不一致,修改下jdk編譯版本就可以了。其實就用到了4個類,如下圖 專案目錄

  可以選擇把支付功能單獨做一個專案,在其他專案呼叫介面就可以支付,也可以整合到自己的專案裡,為了好維護我整合到自己的專案裡了。把這四個類放到自己的專案中,引入相應的jar包

2.1、demo中類的說明

AlipayConfig.java類主要是配置引數資訊的類

  1. package com.fahai.pay.alipay;

  2. import com.fahai.utils.ProInfoUtil;

  3. /* *

  4. *類名:AlipayConfig

  5. *功能:基礎配置類

  6. *詳細:設定帳戶有關資訊及返回路徑

  7. *版本:3.4

  8. *修改日期:2016-03-08

  9. *說明:

  10. *以下程式碼只是為了方便商戶測試而提供的樣例程式碼,商戶可以根據自己網站的需要,按照技術文件編寫,並非一定要使用該程式碼。

  11. *該程式碼僅供學習和研究支付寶介面使用,只是提供一個參考。

  12. */

  13. public class AlipayConfig {

  14. //↓↓↓↓↓↓↓↓↓↓請在這裡配置您的基本資訊↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

  15. // 合作身份者ID,簽約賬號,以2088開頭由16位純數字組成的字串,檢視地址:https://b.alipay.com/order/pidAndKey.htm

  16. public static String partner = "你自己的PID";

  17. // 收款支付寶賬號,以2088開頭由16位純數字組成的字串,一般情況下收款賬號就是簽約賬號

  18. public static String seller_id = partner;

  19. // MD5金鑰,安全檢驗碼,由數字和字母組成的32位字串,檢視地址:https://b.alipay.com/order/pidAndKey.htm

  20. public static String key = "你自己的MD5祕鑰";

  21. // 伺服器非同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問

  22. //非同步通知頁面,就是接受支付寶支付結果返回資訊的Controller,可以處理自己的支付後的邏輯

  23. //測試環境

  24. public static String notify_url = ProInfoUtil.getInstance().getProperty("project_url")+"order/pay/aliPayOrder";

  25. // 頁面跳轉同步通知頁面路徑 需http://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問

  26. //同步跳轉的頁面,就是支付寶支付成功後頁面跳轉的url

  27. public static String return_url = ProInfoUtil.getInstance().getProperty("project_url")+"order/pay/payResponse";

  28. // 簽名方式

  29. public static String sign_type = "MD5";

  30. // 除錯用,建立TXT日誌資料夾路徑,見AlipayCore.java類中的logResult(String sWord)列印方法。

  31. public static String log_path = "C:\\";

  32. // 字元編碼格式 目前支援 gbk 或 utf-8

  33. public static String input_charset = "utf-8";

  34. // 支付型別 ,無需修改

  35. public static String payment_type = "1";

  36. // 呼叫的介面名,無需修改

  37. public static String service = "create_direct_pay_by_user";

  38. //↑↑↑↑↑↑↑↑↑↑請在這裡配置您的基本資訊↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

  39. //↓↓↓↓↓↓↓↓↓↓ 請在這裡配置防釣魚資訊,如果沒開通防釣魚功能,為空即可 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓

  40. // 防釣魚時間戳 若要使用請呼叫類檔案submit中的query_timestamp函式

  41. public static String anti_phishing_key = "";

  42. // 客戶端的IP地址 非區域網的外網IP地址,如:221.0.0.1

  43. public static String exter_invoke_ip = "";

  44. //↑↑↑↑↑↑↑↑↑↑請在這裡配置防釣魚資訊,如果沒開通防釣魚功能,為空即可 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑

  45. }

  • 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
  • 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

AlipayCore.java是整理引數的工具類

  1. package com.alipay.util;

  2. import java.io.File;

  3. import java.io.FileWriter;

  4. import java.io.IOException;

  5. import java.util.ArrayList;

  6. import java.util.Collections;

  7. import java.util.HashMap;

  8. import java.util.List;

  9. import java.util.Map;

  10. import org.apache.commons.codec.digest.DigestUtils;

  11. import org.apache.commons.httpclient.methods.multipart.FilePartSource;

  12. import org.apache.commons.httpclient.methods.multipart.PartSource;

  13. import com.alipay.config.AlipayConfig;

  14. /* *

  15. *類名:AlipayFunction

  16. *功能:支付寶介面公用函式類

  17. *詳細:該類是請求、通知返回兩個檔案所呼叫的公用函式核心處理檔案,不需要修改

  18. *版本:3.3

  19. *日期:2012-08-14

  20. *說明:

  21. *以下程式碼只是為了方便商戶測試而提供的樣例程式碼,商戶可以根據自己網站的需要,按照技術文件編寫,並非一定要使用該程式碼。

  22. *該程式碼僅供學習和研究支付寶介面使用,只是提供一個參考。

  23. */

  24. public class AlipayCore {

  25. /**

  26. * 除去陣列中的空值和簽名引數

  27. * @param sArray 簽名引數組

  28. * @return 去掉空值與簽名引數後的新簽名引數組

  29. */

  30. public static Map<String, String> paraFilter(Map<String, String> sArray) {

  31. Map<String, String> result = new HashMap<String, String>();

  32. if (sArray == null || sArray.size() <= 0) {

  33. return result;

  34. }

  35. for (String key : sArray.keySet()) {

  36. String value = sArray.get(key);

  37. if (value == null || value.equals("") || key.equalsIgnoreCase("sign")

  38. || key.equalsIgnoreCase("sign_type")) {

  39. continue;

  40. }

  41. result.put(key, value);

  42. }

  43. return result;

  44. }

  45. /**

  46. * 把陣列所有元素排序,並按照“引數=引數值”的模式用“&”字元拼接成字串

  47. * @param params 需要排序並參與字元拼接的引數組

  48. * @return 拼接後字串

  49. */

  50. public static String createLinkString(Map<String, String> params) {

  51. List<String> keys = new ArrayList<String>(params.keySet());

  52. Collections.sort(keys);

  53. String prestr = "";

  54. for (int i = 0; i < keys.size(); i++) {

  55. String key = keys.get(i);

  56. String value = params.get(key);

  57. if (i == keys.size() - 1) {//拼接時,不包括最後一個&字元

  58. prestr = prestr + key + "=" + value;

  59. } else {

  60. prestr = prestr + key + "=" + value + "&";

  61. }

  62. }

  63. return prestr;

  64. }

  65. /**

  66. * 寫日誌,方便測試(看網站需求,也可以改成把記錄存入資料庫)

  67. * @param sWord 要寫入日誌裡的文字內容

  68. */

  69. public static void logResult(String sWord) {

  70. FileWriter writer = null;

  71. try {

  72. writer = new FileWriter(AlipayConfig.log_path + "alipay_log_" + System.currentTimeMillis()+".txt");

  73. writer.write(sWord);

  74. } catch (Exception e) {

  75. e.printStackTrace();

  76. } finally {

  77. if (writer != null) {

  78. try {

  79. writer.close();

  80. } catch (IOException e) {

  81. e.printStackTrace();

  82. }

  83. }

  84. }

  85. }

  86. /**

  87. * 生成檔案摘要

  88. * @param strFilePath 檔案路徑

  89. * @param file_digest_type 摘要演算法

  90. * @return 檔案摘要結果

  91. */

  92. public static String getAbstract(String strFilePath, String file_digest_type) throws IOException {

  93. PartSource file = new FilePartSource(new File(strFilePath));

  94. if(file_digest_type.equals("MD5")){

  95. return DigestUtils.md5Hex(file.createInputStream());

  96. }

  97. else if(file_digest_type.equals("SHA")) {

  98. return DigestUtils.sha256Hex(file.createInputStream());

  99. }

  100. else {

  101. return "";

  102. }

  103. }

  104. }

  • 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
  • 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

AlipayNotify.java是驗證簽名的類

  1. package com.alipay.util;

  2. import java.io.BufferedReader;

  3. import java.io.InputStreamReader;

  4. import java.net.HttpURLConnection;

  5. import java.net.URL;

  6. import java.util.Map;

  7. import com.alipay.config.AlipayConfig;

  8. import com.alipay.sign.MD5;

  9. /* *

  10. *類名:AlipayNotify

  11. *功能:支付寶通知處理類

  12. *詳細:處理支付寶各介面通知返回

  13. *版本:3.3

  14. *日期:2012-08-17

  15. *說明:

  16. *以下程式碼只是為了方便商戶測試而提供的樣例程式碼,商戶可以根據自己網站的需要,按照技術文件編寫,並非一定要使用該程式碼。

  17. *該程式碼僅供學習和研究支付寶介面使用,只是提供一個參考

  18. *************************注意*************************

  19. *除錯通知返回時,可檢視或改寫log日誌的寫入TXT裡的資料,來檢查通知返回是否正常

  20. */

  21. public class AlipayNotify {

  22. /**

  23. * 支付寶訊息驗證地址

  24. */

  25. private static final String HTTPS_VERIFY_URL = "https://mapi.alipay.com/gateway.do?service=notify_verify&";

  26. /**

  27. * 驗證訊息是否是支付寶發出的合法訊息

  28. * @param params 通知返回來的引數陣列

  29. * @return 驗證結果

  30. */

  31. public static boolean verify(Map<String, String> params) {

  32. //判斷responsetTxt是否為true,isSign是否為true

  33. //responsetTxt的結果不是true,與伺服器設定問題、合作身份者ID、notify_id一分鐘失效有關

  34. //isSign不是true,與安全校驗碼、請求時的引數格式(如:帶自定義引數等)、編碼格式有關

  35. String responseTxt = "false";

  36. if(params.get("notify_id") != null) {

  37. String notify_id = params.get("notify_id");

  38. responseTxt = verifyResponse(notify_id);

  39. }

  40. String sign = "";

  41. if(params.get("sign") != null) {sign = params.get("sign");}

  42. boolean isSign = getSignVeryfy(params, sign);

  43. //寫日誌記錄(若要除錯,請取消下面兩行註釋)

  44. //String sWord = "responseTxt=" + responseTxt + "\n isSign=" + isSign + "\n 返回回來的引數:" + AlipayCore.createLinkString(params);

  45. //AlipayCore.logResult(sWord);

  46. if (isSign && responseTxt.equals("true")) {

  47. return true;

  48. } else {

  49. return false;

  50. }

  51. }

  52. /**

  53. * 根據反饋回來的資訊,生成簽名結果

  54. * @param Params 通知返回來的引數陣列

  55. * @param sign 比對的簽名結果

  56. * @return 生成的簽名結果

  57. */

  58. private static boolean getSignVeryfy(Map<String, String> Params, String sign) {

  59. //過濾空值、sign與sign_type引數

  60. Map<String, String> sParaNew = AlipayCore.paraFilter(Params);

  61. //獲取待簽名字串

  62. String preSignStr = AlipayCore.createLinkString(sParaNew);

  63. //獲得簽名驗證結果

  64. boolean isSign = false;

  65. if(AlipayConfig.sign_type.equals("MD5") ) {

  66. isSign = MD5.verify(preSignStr, sign, AlipayConfig.key, AlipayConfig.input_charset);

  67. }

  68. return isSign;

  69. }

  70. /**

  71. * 獲取遠端伺服器ATN結果,驗證返回URL

  72. * @param notify_id 通知校驗ID

  73. * @return 伺服器ATN結果

  74. * 驗證結果集:

  75. * invalid命令引數不對 出現這個錯誤,請檢測返回處理中partner和key是否為空

  76. * true 返回正確資訊

  77. * false 請檢查防火牆或者是伺服器阻止埠問題以及驗證時間是否超過一分鐘

  78. */

  79. private static String verifyResponse(String notify_id) {

  80. //獲取遠端伺服器ATN結果,驗證是否是支付寶伺服器發來的請求

  81. String partner = AlipayConfig.partner;

  82. String veryfy_url = HTTPS_VERIFY_URL + "partner=" + partner + "&notify_id=" + notify_id;

  83. return checkUrl(veryfy_url);

  84. }

  85. /**

  86. * 獲取遠端伺服器ATN結果

  87. * @param urlvalue 指定URL路徑地址

  88. * @return 伺服器ATN結果

  89. * 驗證結果集:

  90. * invalid命令引數不對 出現這個錯誤,請檢測返回處理中partner和key是否為空

  91. * true 返回正確資訊

  92. * false 請檢查防火牆或者是伺服器阻止埠問題以及驗證時間是否超過一分鐘

  93. */

  94. private static String checkUrl(String urlvalue) {

  95. String inputLine = "";

  96. try {

  97. URL url = new URL(urlvalue);

  98. HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();

  99. BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection

  100. .getInputStream()));

  101. inputLine = in.readLine().toString();

  102. } catch (Exception e) {

  103. e.printStackTrace();

  104. inputLine = "";

  105. }

  106. return inputLine;

  107. }

  108. }

  • 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
  • 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

AlipaySubmit.java模擬form表單請求支付寶支付介面的類

  1. package com.alipay.util;

  2. import java.io.IOException;

  3. import java.net.MalformedURLException;

  4. import java.net.URL;

  5. import java.util.ArrayList;

  6. import java.util.List;

  7. import java.util.Map;

  8. import org.dom4j.Document;

  9. import org.dom4j.DocumentException;

  10. import org.dom4j.Node;

  11. import org.dom4j.io.SAXReader;

  12. import com.alipay.config.AlipayConfig;

  13. import com.alipay.sign.MD5;

  14. /* *

  15. *類名:AlipaySubmit

  16. *功能:支付寶各介面請求提交類

  17. *詳細:構造支付寶各介面表單HTML文字,獲取遠端HTTP資料

  18. *版本:3.3

  19. *日期:2012-08-13

  20. *說明:

  21. *以下程式碼只是為了方便商戶測試而提供的樣例程式碼,商戶可以根據自己網站的需要,按照技術文件編寫,並非一定要使用該程式碼。

  22. *該程式碼僅供學習和研究支付寶介面使用,只是提供一個參考。

  23. */

  24. public class AlipaySubmit {

  25. /**

  26. * 支付寶提供給商戶的服務接入閘道器URL(新)

  27. */

  28. private static final String ALIPAY_GATEWAY_NEW = "https://mapi.alipay.com/gateway.do?";

  29. /**

  30. * 生成簽名結果

  31. * @param sPara 要簽名的陣列

  32. * @return 簽名結果字串

  33. */

  34. public static String buildRequestMysign(Map<String, String> sPara) {

  35. String prestr = AlipayCore.createLinkString(sPara); //把陣列所有元素,按照“引數=引數值”的模式用“&”字元拼接成字串

  36. String mysign = "";

  37. if(AlipayConfig.sign_type.equals("MD5") ) {

  38. mysign = MD5.sign(prestr, AlipayConfig.key, AlipayConfig.input_charset);

  39. }

  40. return mysign;

  41. }

  42. /**

  43. * 生成要請求給支付寶的引數陣列

  44. * @param sParaTemp 請求前的引數陣列

  45. * @return 要請求的引數陣列

  46. */

  47. private static Map<String, String> buildRequestPara(Map<String, String> sParaTemp) {

  48. //除去陣列中的空值和簽名引數

  49. Map<String, String> sPara = AlipayCore.paraFilter(sParaTemp);

  50. //生成簽名結果

  51. String mysign = buildRequestMysign(sPara);

  52. //簽名結果與簽名方式加入請求提交引數組中

  53. sPara.put("sign", mysign);

  54. sPara.put("sign_type", AlipayConfig.sign_type);

  55. return sPara;

  56. }

  57. /**

  58. * 建立請求,以表單HTML形式構造(預設)

  59. * @param sParaTemp 請求引數陣列

  60. * @param strMethod 提交方式。兩個值可選:post、get

  61. * @param strButtonName 確認按鈕顯示文字

  62. * @return 提交表單HTML文字

  63. */

  64. public static String buildRequest(Map<String, String> sParaTemp, String strMethod, String strButtonName) {

  65. //待請求引數陣列

  66. Map<String, String> sPara = buildRequestPara(sParaTemp);

  67. List<String> keys = new ArrayList<String>(sPara.keySet());

  68. StringBuffer sbHtml = new StringBuffer();

  69. sbHtml.append("<form id=\"alipaysubmit\" name=\"alipaysubmit\" action=\"" + ALIPAY_GATEWAY_NEW

  70. + "_input_charset=" + AlipayConfig.input_charset + "\" method=\"" + strMethod

  71. + "\">");

  72. for (int i = 0; i < keys.size(); i++) {

  73. String name = (String) keys.get(i);

  74. String value = (String) sPara.get(name);

  75. sbHtml.append("<input type=\"hidden\" name=\"" + name + "\" value=\"" + value + "\"/>");

  76. }

  77. //submit按鈕控制元件請不要含有name屬性

  78. sbHtml.append("<input type=\"submit\" value=\"" + strButtonName + "\" style=\"display:none;\"></form>");

  79. sbHtml.append("<script>document.forms['alipaysubmit'].submit();</script>");

  80. return sbHtml.toString();

  81. }

  82. /**

  83. * 用於防釣魚,呼叫介面query_timestamp來獲取時間戳的處理函式

  84. * 注意:遠端解析XML出錯,與伺服器是否支援SSL等配置有關

  85. * @return 時間戳字串

  86. * @throws IOException

  87. * @throws DocumentException

  88. * @throws MalformedURLException

  89. */

  90. public static String query_timestamp() throws MalformedURLException,

  91. DocumentException, IOException {

  92. //構造訪問query_timestamp介面的URL串

  93. String strUrl = ALIPAY_GATEWAY_NEW + "service=query_timestamp&partner=" + AlipayConfig.partner + "&_input_charset" +AlipayConfig.input_charset;

  94. StringBuffer result = new StringBuffer();

  95. SAXReader reader = new SAXReader();

  96. Document doc = reader.read(new URL(strUrl).openStream());

  97. List<Node> nodeList = doc.selectNodes("//alipay/*");

  98. for (Node node : nodeList) {

  99. // 擷取部分不需要解析的資訊

  100. if (node.getName().equals("is_success") && node.getText().equals("T")) {

  101. // 判斷是否有成功標示

  102. List<Node> nodeList1 = doc.selectNodes("//response/timestamp/*");

  103. for (Node node1 : nodeList1) {

  104. result.append(node1.getText());

  105. }

  106. }

  107. }

  108. return result.toString();

  109. }

  110. }

  • 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
  • 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

這幾個類呼叫支付寶介面的是AlipaySubmit,在網頁選好購買的商品時,在系統中生成訂單,然後進行支付,瀏覽器跳轉到支付寶支付網站,Controller中程式碼為:

  1. /**

  2. * 支付寶支付頁面

  3. *

  4. * @return

  5. * @throws IOException

  6. */

  7. @RequestMapping(value = "/aliPay")

  8. public void aliPay(HttpServletRequest request, HttpServletResponse response) throws IOException {

  9. LOGGER.info("支付寶支付頁面");

  10. //商戶訂單號,商戶網站訂單系統中唯一訂單號,必填

  11. String orderNo = request.getParameter("orderNo");

  12. //訂單名稱,必填

  13. String subjectName = request.getParameter("subjectName");

  14. //付款金額,必填

  15. String total_fee = request.getParameter("fee");

  16. //商品描述,可空

  17. String body = "法海風控 " + subjectName;

  18. if ("money".equals(body)) {

  19. body = "法海風控 餘額充值";

  20. }

  21. //把請求引數打包成map

  22. Map<String, String> sParaTemp = new HashMap<String, String>();

  23. sParaTemp.put("service", AlipayConfig.service);

  24. sParaTemp.put("partner", AlipayConfig.partner);

  25. sParaTemp.put("seller_id", AlipayConfig.seller_id);

  26. sParaTemp.put("_input_charset", AlipayConfig.input_charset);

  27. sParaTemp.put("payment_type", AlipayConfig.payment_type);

  28. sParaTemp.put("notify_url", AlipayConfig.notify_url);

  29. sParaTemp.put("return_url", AlipayConfig.return_url);

  30. sParaTemp.put("anti_phishing_key", AlipayConfig.anti_phishing_key);

  31. sParaTemp.put("exter_invoke_ip", AlipayConfig.exter_invoke_ip);

  32. sParaTemp.put("out_trade_no", orderNo);

  33. sParaTemp.put("subject", subjectName);

  34. sParaTemp.put("total_fee", total_fee);

  35. sParaTemp.put("body", body);

  36. //其他業務引數根據線上開發文件,新增引數.文件地址:https://doc.open.alipay.com/doc2/detail.htm?spm=a219a.7629140.0.0.O9yorI&treeId=62&articleId=103740&docType=1

  37. //如sParaTemp.put("引數名","引數值");

  38. //建立請求

  39. String sHtmlText = AlipaySubmit.buildRequest(sParaTemp,"get","確認");

  40. response.setHeader("Content-Type", "text/html; charset=UTF-8");

  41. response.setCharacterEncoding("UTF-8");

  42. PrintWriter out = response.getWriter();

  43. System.out.println(sHtmlText);

  44. out.println(sHtmlText);

  45. }

  • 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
  • 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

請求aliPay會跳轉到支付寶支付頁面: 支付寶支付頁面

3、接收支付結果通知

在配置好notify_url之後,支付結果會請求相應的介面,我的是order/pay/aliPayOrder,程式碼如下

  1. /**

  2. * 支付寶支付訂單

  3. * @return

  4. * @throws IOException

  5. */

  6. @ResponseBody

  7. @RequestMapping(value = "pay/aliPayOrder", method = RequestMethod.POST)

  8. public void aliPayOrder(HttpServletRequest request,HttpServletResponse response) throws IOException {

  9. LOGGER.info("支付訂單");

  10. //從request中獲得引數Map,並返回可讀的Map

  11. Map<String, String> params = RequestUtil.getParameterMap(request);

  12. LOGGER.info(params.toString());

  13. //驗證支付寶簽名

  14. boolean aliSign = AlipayNotify.verify(params);

  15. if (aliSign) {//驗證成功

  16. //交易狀態

  17. String tradeStatus = params.get("trade_status");

  18. //訂單編號

  19. String orderNo = params.get("out_trade_no");

  20. //支付單號

  21. String payNo = params.get("trade_no");

  22. //支付賬號

  23. String payAccount = params.get("buyer_email");

  24. //支付金額

  25. String totalFee = params.get("total_fee");

  26. //收款支付寶賬號

  27. String sellerId = params.get("seller_id");

  28. if (Constant.ALIPAY_TRADE_SUCCESS.equals(tradeStatus)) {//支付寶支付狀態為成功

  29. //驗證支付寶返回資訊與請求資訊一致

  30. if (ProInfoUtil.getInstance().getProperty("alipay_partner").equals(sellerId)) {

  31. //訂單處理狀態

  32. String orderHandleStatus = "error";

  33. //驗證訂單未做支付處理

  34. Order order = orderService.queryOrderByOrderNo(orderNo);

  35. //訂單已支付

  36. if (Constant.DEALSTATUS_PAY.equals(order.getDealStatus())) {

  37. response.getWriter().print("success");

  38. return;

  39. }

  40. if (null != order && Double.parseDouble(totalFee) == order.getDealPrice() &&

  41. Constant.DEALSTATUS_NOT_PAY.equals(order.getDealStatus())) {//驗證金額是否和訂單一致

  42. //更新訂單為已支付、更新使用者套餐餘額、新增使用者充值記錄、新增使用者餘額支出記錄

  43. order.setDealStatus(Constant.DEALSTATUS_PAY);

  44. order.setPayNo(payNo);

  45. order.setPayType(Constant.ALIPAY);

  46. order.setPayAccount(payAccount);

  47. try {

  48. //支付成功處理支付業務

  49. boolean result = orderService.payOrder(order);

  50. if (result) {

  51. //成功後向支付寶返回成功標誌

  52. LOGGER.info("支付寶支付成功");

  53. orderHandleStatus = "success";

  54. response.getWriter().print("success");

  55. }

  56. } catch (Exception e) {

  57. e.printStackTrace();

  58. LOGGER.info("支付寶支付失敗");

  59. response.getWriter().print("fail");

  60. }

  61. }

  62. //新增支付資訊

  63. Map<String, Object> map = new HashMap<String, Object>();

  64. map.put("params", params.toString());

  65. map.put("payType", Constant.ALIPAY);

  66. map.put("orderNo", orderNo);

  67. map.put("handleStatus", orderHandleStatus);

  68. orderService.addPayInfo(map);

  69. }

  70. }

  71. } else {//驗證失敗

  72. LOGGER.info("支付寶返回驗證失敗");

  73. response.getWriter().print("fail");

  74. }

  75. }

  76. /**

  77. * 從request中獲得引數Map,並返回可讀的Map

  78. *

  79. * @param request

  80. * @return

  81. */

  82. @SuppressWarnings("unchecked")

  83. public static Map getParameterMap(HttpServletRequest request) {

  84. // 引數Map

  85. Map properties = request.getParameterMap();

  86. // 返回值Map

  87. Map<String, String> returnMap = new HashMap<String, String>();

  88. Iterator entries = properties.entrySet().iterator();

  89. Map.Entry entry;

  90. String name = "";

  91. String value = "";

  92. while (entries.hasNext()) {

  93. entry = (Map.Entry) entries.next();

  94. name = (String) entry.getKey();

  95. Object valueObj = entry.getValue();

  96. if(null == valueObj){

  97. value = "";

  98. }else if(valueObj instanceof String[]){

  99. String[] values = (String[])valueObj;

  100. for(int i=0;i<values.length;i++){

  101. value = values[i] + ",";

  102. }

  103. value = value.substring(0, value.length()-1);

  104. }else{

  105. value = valueObj.toString();

  106. }

  107. returnMap.put(name, value);

  108. }

  109. return returnMap;

  110. }

  • 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
  • 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

至此,支付寶支付功能已經做完了,其中有幾個細節需要新增,比如支付時查詢訂單狀態是否已經支付,是否過期等等,可以根據自己的需求去完善。  支付寶的接入還是很順利的,如果熟練的話一兩天就可以完成了,剛開始寫部落格,有錯誤或者不明白的地方歡迎大家指出一起交流學習,共同進步。  由於篇幅問題,我在下一章介紹微信支付的接入。

++++++++++++++++++++++第二個版本++++++++++++++++++++++++++++++++++

引言

1、接入支付寶介面的準備

首先,進行一個說明,我做電腦網站接入支付寶介面時,用的是沙箱環境先進行除錯的,並且是以java版本為例子的。你需要先註冊一個企業號,並且登入支付寶: https://open.alipay.com/platform/home.htm

登入進去後,在左上角有一個“開發者中心”按鈕,點進去後,在左邊有一個“沙箱環境”按鈕,點選進入沙箱環境,進行沙箱環境下的支付寶介面開發(在沙箱環境下除錯好支付寶的介面後,只需要修改AlipayConfig.java中的配置資訊就可以使用了): 這裡寫圖片描述

1.1 配置沙箱環境

1)首先,需要生成RSA2(SHA256)的應用公鑰,並且配置好RSA2(SHA256)的應用公鑰,這裡注意,不需要配置RSA(SHA1)金鑰。  (生成RSA2的應用公鑰詳情請參考:https://docs.open.alipay.com/291/105971) 這裡寫圖片描述

2)!!★★★注意,在沙箱環境下,支付寶的閘道器與真實的閘道器有所不同!這裡需要注意!

1.2 下載SDK&Demo

2)下載完demo後,開啟裡面的readme.txt,按照裡面的使用方法一步步完成即可。這裡要說明的只有一點,那就是在demo裡面還需要下載SDK,將SDK壓縮包裡面的一些jar包放到工程專案中,就可以了

這裡寫圖片描述

2、接入支付寶

前面已經配置好沙箱環境以及下載好了demo和SDK,接下來要做的工作就是配置AlipayConfig.java檔案,並且執行index.jsp檔案,檢視效果,然後根據自己網站的需求修改index.jsp檔案。

2.1 配置AlipayConfig.java

開啟AlipayConfig.java檔案,可以看到需要配置app_id,RSA2私鑰,支付寶公鑰,伺服器非同步通知頁面路徑,頁面跳轉同步通知頁面路徑,支付寶閘道器。其中,簽名方式,字元編碼格式是不需要配置的。這個它本身就寫好了的。

1)配置app_id,這個app_id就是在沙箱應用中的APPID

2)配置RSA2私鑰和支付寶公鑰,RSA2私鑰是在前面生成好的私鑰,而支付寶公鑰在上傳了應用公鑰後,直接點選檢視支付寶公鑰即可

3)配置伺服器非同步通知頁面路徑,★★★注意:這個非同步通知頁面路徑一定要公網可以訪問的,不是內網訪問!(非同步通知的理解可以先轉2.2檢視介面呼叫流程),我在這裡個人建議可以使用 花生殼軟體,繫結本機的ip來進行測試。

4)配置頁面跳轉同步通知頁面路徑,這個不需要公網,只需要本機能訪問就可以了(同步通知的理解也轉2.2檢視介面呼叫流程)

5)支付寶閘道器,★★★這個一定要注意,使用沙箱環境的支付寶閘道器和不使用沙箱環境的支付寶閘道器是不一樣的!

註釋:有些地方需要配置PID,這個PID就是商戶UID

2.2 介面呼叫流程

這裡寫圖片描述

這裡對非同步回撥和同步回撥,進行一個詳細的說明。

簡單來說,非同步回撥的意思是不給使用者跳轉頁面,而是執行非同步回撥頁面(即.jsp中的java程式碼),這裡要重點注意的是,因為並不會跳轉到該頁面,所以並不會執行裡面的jsp或者js程式碼,只會執行java程式碼。但是,在這裡我用的struts2+spring框架,在該jsp頁面中呼叫action的話,在action呼叫service層時會發生錯誤。

所以,我在配置非同步回撥頁面的時候,直接通過url執行到action程式碼,並且通過:

  1. PrintWriter out = ServletActionContext.getResponse().getWriter();

  2. HttpServletRequest request = ServletActionContext.getRequest();

  • 1
  • 2
  • 1
  • 2

這裡我介紹一下,因為支付寶在非同步回撥的時候,一定要用“out.println”打印出success,支付寶的伺服器才會確定這個交易完成了。所以,首先需要定義out,在定義out前,需要得到response,那麼接下來,我們介紹一下response:

1、瞭解response響應

伺服器在接收和解釋客戶端的請求訊息後,伺服器會返回給客戶端一個HTTP響應訊息,我們稱之為響應(response)。其實也是一個按照http協議的規則拼接而成的一個字串
  • 1

在該action中進行商戶訂單號,交易狀態,付款金額,賣家id,商戶本身id的驗證,防止黑客通過修改該付款金額一類的引數,從而導致網站的損失。並且,這樣在action呼叫service層以及service層呼叫dao層時都不會發生錯誤!

同步回撥就比較好理解了,就是支付寶在支付完成後,過幾秒中會跳轉到,你在AlipayConfig中配置的同步回撥頁面,這個頁面可以是自己寫的,不需要一定要公網!

3、使用沙箱賬號測試支付寶介面

在沙箱環境那一欄,有沙箱賬號,使用沙箱賬號的買家賬號和登入密碼進行測試付款

+++++++++++++++++++++++++++++++第三部分++++++++++++

國內電子商務系統實現的基本流程如下:  客戶在系統內下訂單 -> 系統根據訂單生成支付寶介面url -> 客戶通過url使用支付寶(網上銀行)付款 -> 支付寶將客戶的付款完成資訊傳送給電子商務系統 -> 系統收到支付寶資訊後確定客戶訂單已經付款 -> 進行發貨等後續流程。

在開始下面的內容之前,你要先有一個支付寶賬戶,如果要整合支付寶介面,你還必須申請開通服務(關於如何開通,可以直接到支付寶網站上申請).在服務開通後,支付寶會給你2個字串編號:1個partnerId(合作伙伴ID),還有1個securityCode(安全碼).當你拿到這2個碼的時候就可以開始下面的內容了. (1)如何呼叫支付寶介面?(將客戶的訂單資訊按照既定的規則生成一個url跳轉到支付寶網站)

1

2

3

4

5

6

7

8

9

10