Java支付寶APP支付-生成APP支付訂單
阿新 • • 發佈:2019-01-24
講述開發之前,先吐槽一下支付寶的官方文件,做的真亂,看的一頭霧水,沒有微信那麼簡單、明瞭。支付寶介面的呼叫和普通介面的呼叫不一樣,使用的是支付寶官方的SDK的sdkExecute方法。
1、App支付請求引數說明
介面功能:外部商戶App喚起快捷SDK建立訂單並支付。
請求引數是商戶在與支付寶進行資料互動時,提供給支付寶的請求資料,以便支付寶根據這些資料進一步處理。
1.1公共引數
引數 | 型別 | 是否必填 | 最大長度 | 描述 | 示例值 |
---|---|---|---|---|---|
app_id | String | 是 | 32 | 支付寶分配給開發者的應用ID | 2014072300007148 |
method | String | 是 | 128 | 介面名稱 | alipay.trade.app.pay |
format | String | 否 | 40 | 僅支援JSON | JSON |
charset | String | 是 | 10 | 請求使用的編碼格式,如utf-8,gbk,gb2312等 | utf-8 |
sign_type | String | 是 | 10 | 商戶生成簽名字串所使用的簽名演算法型別,目前支援RSA2和RSA,推薦使用RSA2 | RSA2 |
sign | String | 是 | 256 | 商戶請求引數的簽名串,詳見 |
詳見示例 |
timestamp | String | 是 | 19 | 傳送請求的時間,格式"yyyy-MM-dd HH:mm:ss" | 2014-07-24 03:07:50 |
version | String | 是 | 3 | 呼叫的介面版本,固定為:1.0 | 1.0 |
notify_url | String | 是 | 256 | 支付寶伺服器主動通知商戶伺服器裡指定的頁面http/https路徑。建議商戶使用https | |
biz_content | String | 是 | - | 業務請求引數的集合,最大長度不限,除公共引數外所有請求引數都必須放在這個引數中傳遞,具體參照各產品快速接入文件 |
1.2業務引數
引數 | 型別 | 是否必填 | 最大長度 | 描述 | 示例值 |
---|---|---|---|---|---|
body | String | 否 | 128 | 對一筆交易的具體描述資訊。如果是多種商品,請將商品描述字串累加傳給body。 | Iphone6 16G |
subject | String | 是 | 256 | 商品的標題/交易標題/訂單標題/訂單關鍵字等。 | 大樂透 |
out_trade_no | String | 是 | 64 | 商戶網站唯一訂單號 | 70501111111S001111119 |
timeout_express | String | 否 | 6 | 該筆訂單允許的最晚付款時間,逾期將關閉交易。取值範圍:1m~15d。m-分鐘,h-小時,d-天,1c-當天(1c-當天的情況下,無論交易何時建立,都在0點關閉)。 該引數數值不接受小數點, 如 1.5h,可轉換為 90m。 注:若為空,則預設為15d。 |
90m |
total_amount | String | 是 | 9 | 訂單總金額,單位為元,精確到小數點後兩位,取值範圍[0.01,100000000] | 9.00 |
product_code | String | 是 | 64 | 銷售產品碼,商家和支付寶簽約的產品碼,為固定值QUICK_MSECURITY_PAY | QUICK_MSECURITY_PAY |
goods_type | String | 否 | 2 | 商品主型別:0—虛擬類商品,1—實物類商品 注:虛擬類商品不支援使用花唄渠道 |
0 |
passback_params | String | 否 | 512 | 公用回傳引數,如果請求時傳遞了該引數,則返回給商戶時會回傳該引數。支付寶會在非同步通知時將該引數原樣返回。本引數必須進行UrlEncode之後才可以傳送給支付寶 | merchantBizType%3d3C%26merchantBizNo%3d2016010101111 |
promo_params | String | 否 | 512 | 優惠引數 注:僅與支付寶協商後可用 |
{"storeIdType":"1"} |
extend_params | String | 否 | 業務擴充套件引數,詳見下面的“業務擴充套件引數說明” | {"sys_service_provider_id":"2088511833207846"} | |
enable_pay_channels | String | 否 | 128 | 可用渠道,使用者只能在指定渠道範圍內支付 當有多個渠道時用“,”分隔 注:與disable_pay_channels互斥 |
pcredit,moneyFund,debitCardExpress |
disable_pay_channels | String | 否 | 128 | 禁用渠道,使用者不可用指定渠道支付 當有多個渠道時用“,”分隔 注:與enable_pay_channels互斥 |
pcredit,moneyFund,debitCardExpress |
store_id | String | 否 | 32 | 商戶門店編號。該引數用於請求引數中以區分各門店,非必傳項。 | NJ_001 |
ext_user_info | ExtUserInfo | 否 | 外部指定買家,詳見外部使用者ExtUserInfo引數說明 |
其它擴充套件引數,我這裡就不詳細描述了。
2、程式碼實現
2.1基礎類
AlipayConfig配置類,主要包含支付寶的配置資訊
package com.hisap.xql.api.common.ali;
/**
* @Author: QijieLiu
* @Description: 支付寶配置資訊
* @Date: Created in 10:39 2018/8/20
*/
public class AlipayConfig {
public static String APP_ID = "xxxxxx";
public static String APP_PRIVATE_KEY = "xxxxxx";//APP私鑰
public static String APP_PUBLIC_KEY = "xxxxxx";//APP公鑰
public static String ALIPAY_PUBLIC_KEY = "xxxxxx";//支付寶公鑰
public static String UNIFIEDORDER_URL = "https://openapi.alipay.com/gateway.do";
public static String NOTIFY_URL = "http://xxx.xxx.xxx.xxx/XqlApi/xxx/paynotify";
public static String CHARSET = "UTF-8";
public static String FORMAT = "json";
public static String SIGNTYPE = "RSA2";
public static String TIMEOUT_EXPRESS = "30m";
}
ResponseJson基礎類,主要與APP前端進行互動
package com.hisap.xql.api.common.bean;
public class ResponseJson {
// 結果碼
private String code;
// 結果說明
private String message;
// 內容
private Object data;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public Object getData() {
return data;
}
public void setData(Object data) {
this.data = data;
}
}
2.2業務類
AliPayController類
package com.hisap.xql.api.controller;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alipay.api.internal.util.AlipaySignature;
import com.hisap.xql.api.common.ali.AlipayConfig;
import com.hisap.xql.api.common.bean.ResponseJson;
import com.hisap.xql.api.common.constant.CodeMsg;
import com.hisap.xql.api.common.utils.CommonUtil;
import com.hisap.xql.api.service.AliPayService;
/**
* @Author: QijieLiu
* @Description: 支付寶支付資訊
* @Date: Created in 10:39 2018/8/20
*/
@Controller
@RequestMapping("/xxx")
public class AliPayController {
private static final Logger logger = LoggerFactory.getLogger(AliPayController.class);
@Autowired
private AliPayService aliPayService;
@RequestMapping("/xxx")
@ResponseBody
public ResponseJson unifiedorder(HttpServletRequest request,
HttpServletResponse response){
ResponseJson responseJson = new ResponseJson();
try{
String requestJson = IOUtils.toString(request.getInputStream(), "utf-8");
logger.info("支付寶統一下單介面請求資料json:" + requestJson);
responseJson = aliPayService.unifiedorder(requestJson);
logger.info("支付寶統一下單介面響應資料json:"
+ JSON.toJSONString(responseJson, SerializerFeature.WriteNullStringAsEmpty));
}catch(Exception e){
e.printStackTrace();
logger.error("支付寶統一下單介面服務端異常,異常資訊---" + e.getMessage(), e);
return CommonUtil.createResponseJson(
CodeMsg.SERVER_ERROR_CODE, CodeMsg.SERVER_ERROR_MSG, new JSONObject());
}
return responseJson;
}
}
AliPayService介面類
package com.hisap.xql.api.service;
import java.math.BigDecimal;
import java.util.Map;
import com.hisap.xql.api.common.bean.ResponseJson;
/**
* @Author: QijieLiu
* @Description: 支付寶支付
* @Date: Created in 11:29 2018/8/20
*/
public interface AliPayService {
ResponseJson unifiedorder(String reqJson) throws Exception;
}
AliPayServiceImpl介面實現類
package com.hisap.xql.api.service.impl;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeAppPayRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.hisap.xql.api.common.ali.AlipayConfig;
import com.hisap.xql.api.common.ali.AlipayRefund;
import com.hisap.xql.api.common.bean.ResponseJson;
import com.hisap.xql.api.common.constant.CodeMsg;
import com.hisap.xql.api.common.utils.Collections3;
import com.hisap.xql.api.common.utils.CommonUtil;
import com.hisap.xql.api.common.utils.StringUtil;
import com.hisap.xql.api.common.utils.VersionUtil;
import com.hisap.xql.api.dao.XqlOrderGoodsMapper;
import com.hisap.xql.api.model.XqlOrder;
import com.hisap.xql.api.model.XqlOrderGoods;
import com.hisap.xql.api.model.XqlOrderGoodsExample;
import com.hisap.xql.api.model.XqlVersion;
import com.hisap.xql.api.service.AliPayService;
import com.hisap.xql.api.service.CommonService;
import com.hisap.xql.api.service.ErpInterfaceService;
import com.hisap.xql.api.service.WeChatPayService;
import com.hisap.xql.api.service.XqlOrderService;
@Service
public class AliPayServiceImpl implements AliPayService {
private static final Logger logger = LoggerFactory
.getLogger(AliPayServiceImpl.class);
@Autowired
CommonService commonService;
@Autowired
XqlOrderService xqlOrderServiceImpl;
@Autowired
XqlOrderGoodsMapper xqlOrderGoodsMapper;
@Autowired
WeChatPayService weChatPayServiceImpl;
@Autowired
ErpInterfaceService erpInterfaceServiceImpl;
@Override
public ResponseJson unifiedorder(String reqJson) throws Exception {
ResponseJson responseJson = new ResponseJson();
if (StringUtil.isEmpty(reqJson)) {
return CommonUtil.createResponseJson(CodeMsg.PARAM_CHECK_ERROR_CODE, "請求引數不能為空", new JSONObject());
}
/**獲取請求引數*/
JSONObject reqObj = JSON.parseObject(reqJson);
/**版本號比較*/
String appVersion = reqObj.getString("appVersion");
if (StringUtil.isEmpty(appVersion)) {
return CommonUtil.createResponseJson(CodeMsg.PARAM_CHECK_ERROR_CODE, "請求引數appVersion不能為空", new JSONObject());
}
XqlVersion xqlVersion = commonService.selectXqlVersion();
if (xqlVersion != null && VersionUtil.compareVersion(xqlVersion.getVersionId(), appVersion) > 0) {
return CommonUtil.createResponseJson(CodeMsg.FORCE_APP_VERSION_UPDATE_CODE, xqlVersion.getVersionUrl(), new JSONObject());
}
String orderNoStr = reqObj.getString("orderNo");
if (StringUtil.isEmpty(orderNoStr)) {
return CommonUtil.createResponseJson(CodeMsg.PARAM_CHECK_ERROR_CODE, "請求引數orderNo不能為空", new JSONObject());
}
BigDecimal orderNo = new BigDecimal(orderNoStr);
/** 訂單主資訊 */
XqlOrder xqlOrder = xqlOrderServiceImpl
.selectXqlOrderByOrderNo(orderNo);
if (xqlOrder == null) {
return CommonUtil.createResponseJson(CodeMsg.ORDER_NOT_EXIST_CODE,
CodeMsg.ORDER_NOT_EXIST_MSG, new JSONObject());
}
/** 訂單明細資訊 */
XqlOrderGoodsExample xqlOrderGoodsExample = new XqlOrderGoodsExample();
XqlOrderGoodsExample.Criteria criteria = xqlOrderGoodsExample
.createCriteria();
criteria.andOrderNoEqualTo(orderNo);
List<XqlOrderGoods> xqlOrderGoodsList = xqlOrderGoodsMapper
.selectByExample(xqlOrderGoodsExample);
if (Collections3.isEmpty(xqlOrderGoodsList)) {
return CommonUtil.createResponseJson(
CodeMsg.ORDER_ITEM_NOT_EXIST_CODE,
CodeMsg.ORDER_ITEM_NOT_EXIST_MSG, new JSONObject());
}
XqlOrderGoods xqlOrderGoods = xqlOrderGoodsList.get(0);
/** 驗證庫存與優惠券介面 */
responseJson = erpInterfaceServiceImpl.checkStockAndCouponBeforePay(orderNo);
if(!responseJson.getCode().equalsIgnoreCase(CodeMsg.SUCCESS_CODE)){
return responseJson;
}
if(xqlOrder.getOrderAmount() == 0){
XqlOrder xqlOrder1 = new XqlOrder();
xqlOrder1.setOrderNo(orderNo);
if(xqlOrder.getDeliveryType() == 0){
xqlOrder1.setOrderStatus(302);
xqlOrder1.setSelfDeliveryStatus((short) 0);
}else{
xqlOrder1.setOrderStatus(201);
}
xqlOrder1.setPayStatus((short) 1);
xqlOrderServiceImpl.updateXqlOrderByOrderNo(xqlOrder1);
return CommonUtil.createResponseJson(
CodeMsg.SUCCESS_CODE, CodeMsg.SUCCESS_MSG, new JSONObject());
}
// 例項化客戶端
AlipayClient alipayClient = new DefaultAlipayClient(
AlipayConfig.UNIFIEDORDER_URL, AlipayConfig.APP_ID,
AlipayConfig.APP_PRIVATE_KEY, AlipayConfig.FORMAT,
AlipayConfig.CHARSET, AlipayConfig.APP_PUBLIC_KEY,
AlipayConfig.SIGNTYPE);
// 例項化具體API對應的request類,類名稱和介面名稱對應,當前呼叫介面名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
// SDK已經封裝掉了公共引數,這裡只需要傳入業務引數。以下方法為sdk的model入參方式(model和biz_content同時存在的情況下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody(xqlOrderGoods.getGoodsName());
model.setSubject(xqlOrderGoods.getGoodsName());
model.setOutTradeNo(orderNo.toString());
model.setTimeoutExpress(AlipayConfig.TIMEOUT_EXPRESS);
double totalAmount = (double)xqlOrder.getOrderAmount()/100;
model.setTotalAmount(String.valueOf(totalAmount));
model.setProductCode(xqlOrderGoods.getSku().toString());
request.setBizModel(model);
request.setNotifyUrl(AlipayConfig.NOTIFY_URL);
try {
// 這裡和普通的介面呼叫不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient
.sdkExecute(request);
// 就是orderString 可以直接給客戶端請求,無需再做處理。
String message = response.getBody();
Map<String, String> resMap = new HashMap<String, String>();
resMap.put("payCode", message);
logger.info("支付寶統一下單返回資料:" + message);
responseJson = CommonUtil.createResponseJson(CodeMsg.SUCCESS_CODE,
CodeMsg.SUCCESS_MSG, resMap);
} catch (AlipayApiException e) {
e.printStackTrace();
logger.error("支付寶統一下單介面服務端異常,異常資訊---" + e.getMessage(), e);
return CommonUtil.createResponseJson(CodeMsg.SERVER_ERROR_CODE,
CodeMsg.SERVER_ERROR_MSG, new JSONObject());
}
return responseJson;
}
}
好了,支付寶生成APP支付訂單就已經完成了,下一章講述支付寶非同步結果通知介面開發。