1. 程式人生 > >Java支付寶APP支付-生成APP支付訂單

Java支付寶APP支付-生成APP支付訂單

講述開發之前,先吐槽一下支付寶的官方文件,做的真亂,看的一頭霧水,沒有微信那麼簡單、明瞭。支付寶介面的呼叫和普通介面的呼叫不一樣,使用的是支付寶官方的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支付訂單就已經完成了,下一章講述支付寶非同步結果通知介面開發。