通過支付寶提供的API實現移動支付功能
一:下載相關的依賴和工具
螞蟻金服 https://open.alipay.com/platform/home.htm
移動支付開發文件 https://docs.open.alipay.com/203/105285/
sdk-jar檔案下載 https://docs.open.alipay.com/54/103419/
支付寶介面引數說明 https://docs.open.alipay.com/api_1/alipay.trade.wap.pay
線上支付例項下載 https://docs.open.alipay.com/54/106682/
生成支付寶公鑰和私鑰 https://gw.alipayobjects.com/os/rmsportal/PpisHyUkzJnZltrPyfuD.zip
二:搭建開發環境
(1):直接下載好sdk依賴包匯入lib目錄alipay-sdk-java-3.4.49.ALL.jar
(2):通過Maven依賴下載jar
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.4.49.ALL</version>
</dependency>
三:移動支付-全域性配置類
package com.svse.util;
/**
* 移動支付-全域性配置類
* @author lenovo
*
*/
public class AlipayConfig {
// 商戶appid
public static final String APPID=””;
// 請求閘道器地址
public static final String URL=”https://openapi.alipay.com/gateway.do”;
// 返回格式
public static final String FORMAT=”json”;
// 編碼
public static final String CHARSET=”UTF-8″;
// RSA2
public static final String SIGNTYPE=”RSA2″;
// 伺服器非同步通知頁面路徑 需http://或者https://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問
public static final String notify_url=”http://商戶閘道器地址/alipay.trade.wap.pay-JAVA-UTF-8/notify_url.jsp“;
// 頁面跳轉同步通知頁面路徑 需http://或者https://格式的完整路徑,不能加?id=123這類自定義引數,必須外網可以正常訪問 商戶可以自定義同步跳轉地址
public static final String return_url=”http://商戶閘道器地址/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp“;
// 過RSA簽名驗籤工具生成支付寶公鑰
public static final String ALIPAY_PUBLIC_KEY=””;
// 通過RSA簽名驗籤工具生成,PKCS8格式私鑰
public static final String RSA_PRIVATE_KEY=””;
}
四:編寫相關業務介面程式碼
1:支付寶線上支付介面
@RequestMapping(“payment“)
public void payment(HttpServletRequest request,HttpServletResponse response) throws IOException{
if(request.getParameter(“WIDout_trade_no”)!=null||request.getParameter(“WIDtrade_no”)!=null){
//商戶訂單號
String out_trade_no = new String(request.getParameter(“WIDout_trade_no”).getBytes(“ISO-8859-1″),”UTF-8”);
// 訂單名稱,必填
String subject = new String(request.getParameter(“WIDsubject”).getBytes(“ISO-8859-1″),”UTF-8”);
System.out.println(subject);
// 付款金額,必填
String total_amount=new String(request.getParameter(“WIDtotal_amount”).getBytes(“ISO-8859-1″),”UTF-8”);
// 商品描述,可空
String body = new String(request.getParameter(“WIDbody”).getBytes(“ISO-8859-1″),”UTF-8”);
// 超時時間 可空
String timeout_express=”2m”;
// 銷售產品碼 必填
String product_code=”QUICK_WAP_WAY”;
/**********************/
// SDK 公共請求類,包含公共請求引數,以及封裝了簽名與驗籤,開發者無需關注簽名與驗籤
//呼叫RSA簽名方式
AlipayClient client =this.getAlipayClient();
AlipayTradeWapPayRequest alipay_request=new AlipayTradeWapPayRequest();
// 封裝請求支付資訊
AlipayTradeWapPayModel model=new AlipayTradeWapPayModel();
model.setOutTradeNo(out_trade_no);
model.setSubject(subject);
model.setTotalAmount(total_amount);
model.setBody(body);
model.setTimeoutExpress(timeout_express);
model.setProductCode(product_code);
alipay_request.setBizModel(model);
// 設定非同步通知地址
alipay_request.setNotifyUrl(AlipayConfig.notify_url);
// 設定同步地址
alipay_request.setReturnUrl(AlipayConfig.return_url);
// form表單生產
String form = “”;
try {
// 呼叫SDK生成表單
form = client.pageExecute(alipay_request).getBody();
response.setContentType(“text/html;charset=” + AlipayConfig.CHARSET);
response.getWriter().write(form);//直接將完整的表單html輸出到頁面
response.getWriter().flush();
response.getWriter().close();
} catch (AlipayApiException e) {
e.printStackTrace();
}
}else{
System.out.println(“訂單出現問題,支付失敗“);
}
}
2:支付寶線上生成訂單介面
@RequestMapping(“generateOrder“)
public void generateOrder(HttpServletRequest request11,HttpServletResponse response11) throws UnsupportedEncodingException{
if(request11.getParameter(“WIDout_trade_no“)!=null||request11.getParameter(“WIDtrade_no“)!=null){
//商戶訂單號
String out_trade_no = new String(request11.getParameter(“WIDout_trade_no“).getBytes(“ISO-8859-1″),”UTF-8”);
//例項化客戶端
AlipayClient client =this.getAlipayClient();
//例項化具體API對應的request類,類名稱和介面名稱對應,當前呼叫介面名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
//SDK已經封裝掉了公共引數,這裡只需要傳入業務引數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody(“我是測試資料”);
model.setSubject(“App支付測試Java”);
model.setOutTradeNo(out_trade_no);
model.setTimeoutExpress(“30m”);
model.setTotalAmount(“0.01”);
model.setProductCode(“QUICK_MSECURITY_PAY”);
request.setBizModel(model);
request.setNotifyUrl(“商戶外網可以訪問的非同步地址”);
try {
//這裡和普通的介面呼叫不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
System.out.println(response.getBody());//就是orderString 可以直接給客戶端請求,無需再做處理。
} catch (AlipayApiException e) {
e.printStackTrace();
}
}
}
3:支付寶線上訂單查詢介面
@RequestMapping(“searchOrder“)
public void searchOrder(HttpServletRequest request,HttpServletResponse response){
if(request.getParameter(“WIDout_trade_no“)!=null||request.getParameter(“WIDtrade_no“)!=null){
try {
//商戶訂單號,商戶網站訂單系統中唯一訂單號,必填
String out_trade_no = new String(request.getParameter(“WIDout_trade_no“).getBytes(“ISO-8859-1″),”UTF-8”);
//支付寶交易號
String trade_no = new String(request.getParameter(“WIDtrade_no“).getBytes(“ISO-8859-1″),”UTF-8”);
/**********************/
// SDK 公共請求類,包含公共請求引數,以及封裝了簽名與驗籤,開發者無需關注簽名與驗籤
AlipayClient client =this.getAlipayClient();
AlipayTradeQueryRequest alipay_request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model=new AlipayTradeQueryModel();
model.setOutTradeNo(out_trade_no);
model.setTradeNo(trade_no);
alipay_request.setBizModel(model);
AlipayTradeQueryResponse alipay_response;
try {
alipay_response = client.execute(alipay_request);
System.out.println(alipay_response.getBody());
} catch (AlipayApiException e) {
e.printStackTrace();
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
4:支付寶線上訂單退款介面
@RequestMapping(“orderRefund“)
public void orderRefund(HttpServletRequest request,HttpServletResponse response){
if(request.getParameter(“WIDout_trade_no“)!=null||request.getParameter(“WIDtrade_no“)!=null){
//商戶訂單號和支付寶交易號不能同時為空。 trade_no、 out_trade_no如果同時存在優先取trade_no
//商戶訂單號,和支付寶交易號二選一
String out_trade_no;
try {
out_trade_no = new String(request.getParameter(“WIDout_trade_no“).getBytes(“ISO-8859-1″),”UTF-8”);
//支付寶交易號,和商戶訂單號二選一
String trade_no = new String(request.getParameter(“WIDtrade_no“).getBytes(“ISO-8859-1″),”UTF-8”);
//退款金額,不能大於訂單總金額
String refund_amount=new String(request.getParameter(“WIDrefund_amount“).getBytes(“ISO-8859-1″),”UTF-8”);
//退款的原因說明
String refund_reason=new String(request.getParameter(“WIDrefund_reason“).getBytes(“ISO-8859-1″),”UTF-8”);
//標識一次退款請求,同一筆交易多次退款需要保證唯一,如需部分退款,則此引數必傳。
String out_request_no=new String(request.getParameter(“WIDout_request_no“).getBytes(“ISO-8859-1″),”UTF-8”);
/**********************/
// SDK 公共請求類,包含公共請求引數,以及封裝了簽名與驗籤,開發者無需關注簽名與驗籤
AlipayClient client =this.getAlipayClient();
AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest();
AlipayTradeRefundModel model=new AlipayTradeRefundModel();
model.setOutTradeNo(out_trade_no);
model.setTradeNo(trade_no);
model.setRefundAmount(refund_amount);
model.setRefundReason(refund_reason);
model.setOutRequestNo(out_request_no);
alipay_request.setBizModel(model);
AlipayTradeRefundResponse alipay_response;
try {
alipay_response = client.execute(alipay_request);
System.out.println(alipay_response.getBody());
} catch (AlipayApiException e) {
e.printStackTrace();
}
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
}
}
5:訂單退款查詢介面
@RequestMapping(“searchOrderRefund“)
public void searchOrderRefund(HttpServletRequest request,HttpServletResponse response){
if(request.getParameter(“WIDout_trade_no“)!=null||request.getParameter(“WIDtrade_no“)!=null && request.getParameter(“WIDout_request_no“)!=null){
try {
//商戶訂單號和支付寶交易號不能同時為空。 trade_no、 out_trade_no如果同時存在優先取trade_no
//商戶訂單號,和支付寶交易號二選一
String out_trade_no = new String(request.getParameter(“WIDout_trade_no“).getBytes(“ISO-8859-1″),”UTF-8”);
//支付寶交易號,和商戶訂單號二選一
String trade_no = new String(request.getParameter(“WIDtrade_no“).getBytes(“ISO-8859-1″),”UTF-8”);
//請求退款介面時,傳入的退款請求號,如果在退款請求時未傳入,則該值為建立交易時的外部交易號
String out_request_no = new String(request.getParameter(“WIDout_request_no“).getBytes(“ISO-8859-1″),”UTF-8”);
/**********************/
// SDK 公共請求類,包含公共請求引數,以及封裝了簽名與驗籤,開發者無需關注簽名與驗籤
AlipayClient client =this.getAlipayClient();
AlipayTradeFastpayRefundQueryRequest alipay_request = new AlipayTradeFastpayRefundQueryRequest();
AlipayTradeFastpayRefundQueryModel model=new AlipayTradeFastpayRefundQueryModel();
model.setOutTradeNo(out_trade_no);
model.setTradeNo(trade_no);
model.setOutRequestNo(out_request_no);
alipay_request.setBizModel(model);
AlipayTradeFastpayRefundQueryResponse alipay_response=client.execute(alipay_request);
System.out.println(alipay_response.getBody());
} catch (Exception e) {
e.printStackTrace();
}
}
}
6:賬單下載介面
@RequestMapping(“downloadBill“)
public void downloadBill(HttpServletRequest request,HttpServletResponse response){
if(request.getParameter(“WIDbill_type“)!=null&&request.getParameter(“WIDbill_date“)!=null){
try {
// 賬單型別,商戶通過介面或商戶經開放平臺授權後其所屬服務商通過介面可以獲取以下賬單型別:trade、signcustomer;
// trade指商戶基於支付寶交易收單的業務賬單;signcustomer是指基於商戶支付寶餘額收入及支出等資金變動的帳務賬單;
String bill_type = new String(request.getParameter(“WIDbill_type“).getBytes(“ISO-8859-1″),”UTF-8”);
// 賬單時間:日賬單格式為yyyy-MM-dd,月賬單格式為yyyy-MM。
String bill_date = new String(request.getParameter(“WIDbill_date“).getBytes(“ISO-8859-1″),”UTF-8”);
/**********************/
// SDK 公共請求類,包含公共請求引數,以及封裝了簽名與驗籤,開發者無需關注簽名與驗籤
AlipayClient client =this.getAlipayClient();
AlipayDataDataserviceBillDownloadurlQueryRequest alipay_request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
AlipayDataDataserviceBillDownloadurlQueryModel model =new AlipayDataDataserviceBillDownloadurlQueryModel();
model.setBillType(bill_type);
model.setBillDate(bill_date);
alipay_request.setBizModel(model);
AlipayDataDataserviceBillDownloadurlQueryResponse alipay_response = client.execute(alipay_request);
System.out.println(alipay_response.getBillDownloadUrl());
} catch (Exception e) {
e.printStackTrace();
}
}
}
7:非同步通知訊息介面
@RequestMapping(“notifyUrl“)
@ResponseBody
public String notify(HttpServletRequest request){
int im=0;
im++;
//測試請求次數
System.out.println(“次數:”+im);
//獲取支付寶POST過來反饋資訊
Map<String,String> params = new HashMap<String,String>();
Map requestParams = request.getParameterMap();
for (Iterator 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] + “,”;
}
//亂碼解決,這段程式碼在出現亂碼時使用。
//valueStr = new String(valueStr.getBytes(“ISO-8859-1”), “utf-8”);
params.put(name, valueStr);
}
//獲取支付寶的通知返回引數,可參考技術文件中頁面跳轉同步通知引數列表(以下僅供參考)//
//商戶訂單號
String out_trade_no = request.getParameter(“out_trade_no“);
//支付寶交易號
String trade_no = request.getParameter(“trade_no“);
//交易狀態
String trade_status = request.getParameter(“trade_status“);
System.out.println(trade_status);
try {
boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, “utf-8”, “RSA2”);
if(verify_result){
//驗證成功
//請在這裡加上商戶的業務邏輯程式程式碼
System.out.println(“returnUrl_params:驗證成功“);
//——請根據您的業務邏輯來編寫程式(以下程式碼僅作參考)——
boolean flag = false;
if(trade_status.equals(“TRADE_FINISHED“)){
System.out.println(“returnUrl_params:交易結束“);
//交易結束,不可退款
//注意:
//退款日期超過可退款期限後(如三個月可退款),支付寶系統傳送該交易狀態通知
}else if (trade_status.equals(“TRADE_SUCCESS“)){
//交易支付成功
//注意:
//付款完成後,支付寶系統傳送該交易狀態通知
//根據訂單號將訂單狀態和支付寶記錄表中狀態都改為已支付
System.out.println(“returnUrl_params:交易支付成功“);
flag = true;
//——請根據您的業務邏輯來編寫程式(以上程式碼僅作參考)——
if(flag){
return “success”;
}else{
return “fail”;
}
}
}else{
//驗證失敗
System.out.println(“交易失敗“);
return “fail”;
}
} catch (Exception e) {
e.printStackTrace();
return “500”;
}
return null;
}
8:同步通知訊息介面
@RequestMapping(“/returnUrl“)
public ModelAndView result(HttpServletRequest request) {
System.out.println(“進來“);
//用ModelAndView 進行資料渲染
ModelAndView mv = new ModelAndView(“alipay/return_url”);
//獲取支付寶GET過來反饋資訊
Map<String,String> params = new HashMap<String,String>();
Map<String, String[]> requestParams = request.getParameterMap();
for(String str:requestParams.keySet()){
String[] values=requestParams.get(str);
String valueStr=””;
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length – 1) ? valueStr + values[i] : valueStr + values[i] + “,”;
}
//亂碼解決,這段程式碼在出現亂碼時使用。如果mysign和sign不相等也可以使用這段程式碼轉化
//valueStr = new String(valueStr.getBytes(“ISO-8859-1”), “gbk”);
params.put(str, valueStr);
}
//交易訂單編號
String out_trade_no = request.getParameter(“out_trade_no“);
//交易金額
String total_amount = request.getParameter(“total_amount“);
//支付寶交易賬號
//String trade_no = request.getParameter(“trade_no”);
//訂單建立時間
String timestamp = request.getParameter(“timestamp“);
mv.addObject(“out_trade_no”, out_trade_no);
mv.addObject(“total_amount”, total_amount);
mv.addObject(“timestamp”, timestamp);
//列印所有響應資料
System.out.println(“returnUrl_params:”+params);
try {
//切記AlipayConfig.ALIPAY_PUBLIC_KEY是支付寶的公鑰,請去open.alipay.com對應應用下檢視。
boolean verify_result = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, “utf-8”, “RSA2”);
if(verify_result){
//驗證成功 這裡寫的是假程式碼
//系統處理根據支付寶回撥更改訂單狀態或者其他關聯表的資料 (走業務流程, 根據訂單編號獲取訂單資料
//Order order =orderService.queryOrderByNumber(out_trade_no);
/* if(order !=null){
//order不為null
mv.addObject(“verify_result”, verify_result);
mv.addObject(“msg”, “商戶訂單號不存在”);
} */
return mv;
}else{
//驗證失敗 跳失敗頁面
System.out.println(“驗證失敗“);
return null;
}
} catch (Exception e) {
e.printStackTrace();
//出現異常 跳失敗頁面
return null;
}
}