前言 最近在工作中需要使用支付寶app支付,在初次使用過程中也不可避免的出現了一些問題,那麼本次隨筆主要是概述支付寶app支付服務端的整個實現過程以及就服務端出現的一些問題做一些總結。 1.準備工作 1.1 入駐螞蟻金服開放平臺 https://open.alipay.com/platform/ho ...
前言
最近在工作中需要使用支付寶app支付,在初次使用過程中也不可避免的出現了一些問題,那麼本次隨筆主要是概述支付寶app支付服務端的整個實現過程以及就服務端出現的一些問題做一些總結。
1.準備工作
1.1 入駐螞蟻金服開放平臺
https://open.alipay.com/platform/home.htm
1.2 創建應用
首先需要創建一個應用。
然後需要設置應用公鑰。
下載支付寶密鑰生成器。生成成功之後將公鑰複製到這裡。
最後提交審核,等待。
2.Maven依賴
首先需要下載SDK,https://docs.open.alipay.com/54/104509。
完成之後,需要切換命令行,進入SDK所在目錄,執行如下命令。如果命令無法執行,請百度如何配置maven環境變數,配置好之後再執行。
mvn install:install-file -DgroupId=com.alipay.sdk -DartifactId=alipay-sdk-java -Dversion=3.1.0 -Dpackaging=jar -Dfile=SDK文件名.jar
groupId:可以自己定義,pom文件依賴依據與此
artifactId:可以自己定義,pom文件依賴依據與此
version:可以自己定義,pom文件依賴依據與此
packaging:打包方式(jar)
file:文件的路徑的路徑
在pom.xml中引入依賴,如下。
<!-- 支付寶支付相關start --> <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>3.1.0</version> </dependency> <!-- 支付寶支付相關end -->
3.配置文件中配置支付寶相關參數
#支付寶支付相關配置
#支付寶分配給開發者的應用Id aliPayAppId=XXX
#賣家支付寶用戶號(對應非同步通知返回參數seller_id)(可以不配置,只是非同步通知時為了進一步校驗而配置) aliPaySellerId=XXX
#賣家支付寶賬號(對應非同步通知返回參數seller_email)(可以不配置,只是非同步通知時為了進一步校驗而配置) alipayAccount=XXX
#商戶公鑰 rsaPublicKey=XXX
#商戶私鑰(註意,如果是Java語言,需要使用pkcs8格式的私鑰,避免出現不可預知的錯誤) rsaPrivatKey=XXX
#支付寶公鑰 rsaAlipayPublicKey=XXX
#加密方式 signType=XXX
#僅支持JSON alipayFormat=json
#請求使用的編碼格式,如utf-8,gbk,gb2312等 alipayCharset=utf-8
4.生成安卓端需要的orderString信息的介面方法
/** *app支付 * *@author lp *@date 2019/1/4 16:32 */ @ApiOperation("app支付") @RequestMapping(value = "alipay", method = RequestMethod.POST) public String alipay(@RequestBody CombinedPaymentDto dto, HttpServletResponse response, HttpServletRequest request) { response.setHeader("Access-Control-Allow-Origin", "*"); // 獲取項目中實際的訂單的信息 // 此處是相關業務代碼 // 獲取配置文件中支付寶相關信息 String aliPayGateway = PropertiesUtils.getInstace("config/webService.properties").getProperty("aliPayGateway"); String aliPayAppId = PropertiesUtils.getInstace("config/webService.properties").getProperty("aliPayAppId"); String rsaPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaPublicKey"); String rsaPrivatKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaPrivatKey"); String rsaAlipayPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaAlipayPublicKey"); String signType = PropertiesUtils.getInstace("config/webService.properties").getProperty("signType"); String alipayFormat = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayFormat"); String alipayCharset = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayCharset"); AlipayClient alipayClient = new DefaultAlipayClient(aliPayGateway, aliPayAppId, rsaPrivatKey, alipayFormat, alipayCharset, rsaAlipayPublicKey, signType); AlipayTradeAppPayRequest alipayRequest = new AlipayTradeAppPayRequest(); AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); model.setBody("XXX"); model.setSubject("XXX"); // 唯一訂單號 根據項目中實際需要獲取相應的 model.setOutTradeNo(""); // 支付超時時間(根據項目需要填寫) model.setTimeoutExpress("30m"); // 支付金額(項目中實際訂單的需要支付的金額,金額的獲取與操作請放在服務端完成,相對安全) model.setTotalAmount(""); model.setProductCode("QUICK_MSECURITY_PAY"); alipayRequest.setBizModel(model); // 支付成功後支付寶非同步通知的接收地址url alipayRequest.setNotifyUrl("XXX/getAlipayNotifyInfo"); AlipayTradeAppPayResponse alipayResponse = null; try { alipayResponse = alipayClient.sdkExecute(alipayRequest); } catch (AlipayApiException e) { e.printStackTrace(); } // 返回支付相關信息(此處可以直接將getBody中的內容直接返回,無需再做一些其他操作) return alipayResponse.getBody(); }
5.支付成功後服務端接收支付寶發來的非同步通知的介面方法
/** *接收支付寶非同步通知消息 * *@author lp *@date 2019/1/4 17:19 */ @ApiOperation("接收支付寶非同步通知消息") @RequestMapping(value = "getAlipayNotifyInfo", method = RequestMethod.POST) public String getAlipayNotifyInfoOfCombinedPayment(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException { response.setHeader("Access-Control-Allow-Origin", "*"); // 解決POST請求中文亂碼問題(推薦使用此種方式解決中文亂碼,因為是支付寶發送非同步通知使用的是POST請求) request.setCharacterEncoding("UTF-8"); //獲取支付寶POST過來反饋信息 Map<String,String> params = new HashMap<>(); Map<String,String[]> requestParams = request.getParameterMap(); for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) { String name = (String) iter.next(); String[] values = (String[]) requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } // 官方demo中使用如下方式解決中文亂碼,在此本人不推薦使用,可能會出現中文亂碼解決無效的問題。 // valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8"); params.put(name, valueStr); } // 支付寶公鑰(請註意,不是商戶公鑰) String rsaAlipayPublicKey = PropertiesUtils.getInstace("config/webService.properties").getProperty("rsaAlipayPublicKey"); String signType = PropertiesUtils.getInstace("config/webService.properties").getProperty("signType"); String alipayCharset = PropertiesUtils.getInstace("config/webService.properties").getProperty("alipayCharset"); boolean signVerified = false; try { //調用SDK驗證簽名 signVerified = AlipaySignature.rsaCheckV1(params, rsaAlipayPublicKey, alipayCharset, signType); if(signVerified) { // 驗證通知後執行自己項目需要的業務操作 // 一般需要判斷支付狀態是否為TRADE_SUCCESS // 更嚴謹一些還可以判斷 1.appid 2.sellerId 3.out_trade_no 4.total_amount 等是否正確,正確之後再進行相關業務操作。 // 成功要返回success,不然支付寶會不斷發送通知。 return "success"; } // 驗簽失敗 筆者在這裡是輸出log,可以根據需要做一些其他操作 // 失敗要返回success,不然支付寶會不斷發送通知。 return "fail"; } catch (AlipayApiException e) { e.printStackTrace(); // 驗簽異常 筆者在這裡是輸出log,可以根據需要做一些其他操作 return "fail"; } }