支付寶SDK依賴
<!--支付寶-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.3.4.ALL</version>
</dependency>
支付寶參數(shù)配置類
@Component
@Configuration
public class AliDevPayConfig implements Serializable {
/**
* 支付寶服務器主動通知商戶服務器里指定的頁面http/https路徑
* 異步請求,地址必須是公網(wǎng)可以訪問的才行,不能有任何參數(shù)
* 例如:項目發(fā)布地址/本項目名/接口名
*/
public static String NOTIFY_URL;
public static String RETURN_URL;
@Value("${alipay.aliPayReturnUrl}")
public void setReturnUrl(String returnUrl) {
RETURN_URL = returnUrl;
}
@Value("${alipay.aliPayNotifyUrl}")
public void setNotifyUrl(String notifyUrl) {
NOTIFY_URL = notifyUrl;
}
public String getNotifyUrl() {
return NOTIFY_URL;
}
public String getReturnUrl() {
return RETURN_URL;
}
/**支付寶分配給開發(fā)者的應用ID*/
public static String aliPayAppId = "開發(fā)者id";
/**支付寶網(wǎng)關(guān)*/
public static String aliPayGateWay = "https://openapi.alipay.com/gateway.do";
/**私鑰*/
public static String aliPayPrivateKey = "你的私鑰";
/**支付寶公鑰*/
public static String aliPayPublicKey = "你的公鑰";
/**僅支持JSON*/
public static String FORMAT = "JSON";
/**請求使用的編碼格式,如utf-8,gbk,gb2312等*/
public static String CHARSET = "utf-8";
/**商戶生成簽名字符串所使用的簽名算法類型,目前支持RSA2和RSA,推薦使用RSA2*/
public static String SIGN_TYPE = "RSA2";
}
因為我的項目有多個環(huán)境,會有多個對應的配置文件,所以我選擇用@Value注入的方式。
配置文件的url配置如下:
alipay:
aliPayNotifyUrl: 異步回調(diào)url
aliPayReturnUrl: 同步回調(diào)url
Controller
@Resource
PayService payService;
@RequestMapping(value = "/ali", method = RequestMethod.POST)
@ApiOperation(value="[支付寶]充值")
public Result<String> alipayTopup(@RequestBody AliPayRechargeDTO aliPayRechargeDTO){
return Result.getSuccess(payService.saveAliPayRechangeBill(aliPayRechargeDTO));
}
@RequestMapping(value = "/alipaynotice", method = RequestMethod.POST)
@ApiOperation(value="[支付寶專用]支付寶充值接口異步回調(diào)接口")
public String paynotice(HttpServletRequest request){
return payService.alipayNotify(request);
}
DTO對象傳入你所需要的參數(shù),比如金額,賬戶id等等。
Service
@Slf4j
@Service
public class PayService{
public String saveAliPayRechangeBill(AliPayRechargeDTO rechargeDTO){
BigDecimal totalAmount = rechargeDTO.getRechargeTotalAmount();
//實例化客戶端(參數(shù):網(wǎng)關(guān)地址、商戶appid、商戶私鑰、格式、編碼、支付寶公鑰、加密類型),為了取得預付訂單信息
AlipayClient alipayClient = new DefaultAlipayClient(AliDevPayConfig.aliPayGateWay, AliDevPayConfig.aliPayAppId,
AliDevPayConfig.aliPayPrivateKey, AliDevPayConfig.FORMAT, AliDevPayConfig.CHARSET,
AliDevPayConfig.aliPayPublicKey, AliDevPayConfig.SIGN_TYPE);
//實例化具體API對應的request類,類名稱和接口名稱對應,當前調(diào)用接口名稱:alipay.trade.app.pay
AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();
//SDK已經(jīng)封裝掉了公共參數(shù),這里只需要傳入業(yè)務參數(shù)。以下方法為sdk的model入?yún)⒎绞? AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
//對一筆交易的具體描述信息。如果是多種商品,請將商品描述字符串累加傳給body。
model.setBody("xx商品介紹");
//商品名稱
model.setSubject("xx商品");
//商戶訂單號(根據(jù)業(yè)務需求自己生成)
model.setOutTradeNo("你自己業(yè)務賬單的id");
//交易超時時間 這里的30m就是30分鐘
model.setTimeoutExpress("30m");
//支付金額 后面保留2位小數(shù)點..不能超過2位
model.setTotalAmount(totalAmount.toString());
//銷售產(chǎn)品碼(固定值)
model.setProductCode("QUICK_MSECURITY_PAY");
ali_request.setBizModel(model);
//異步回調(diào)地址(后臺)
ali_request.setNotifyUrl(AliDevPayConfig.NOTIFY_URL);
log.info("Alipay異步通知的地址為:" + ali_request.getNotifyUrl());
try{
// 這里和普通的接口調(diào)用不同,使用的是sdkExecute
//返回支付寶訂單信息(預處理)
AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request);
//就是orderString 可以直接給APP請求,無需再做處理。
String alipayTransferId = alipayTradeAppPayResponse.getBody();
log.info("需要返回給支付寶的數(shù)據(jù) alipayTransferId:" + alipayTransferId);
return alipayTransferId;
}catch (AlipayApiException e){
e.printStackTrace();
}
return null;
}
public String alipayNotify(HttpServletRequest request) {
log.info("支付寶異步返回支付結(jié)果開始");
//1.從支付寶回調(diào)的request域中取值
//獲取支付寶返回的參數(shù)集合
Map<String, String[]> aliParams = request.getParameterMap();
log.info("支付寶Post過來的反饋信息:" + aliParams.toString());
//用以存放轉(zhuǎn)化后的參數(shù)集合
Map<String, String> conversionParams = new HashMap<String, String>();
for (Iterator<String> iter = aliParams.keySet().iterator(); iter.hasNext();) {
String key = iter.next();
String[] values = aliParams.get(key);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
// 亂碼解決,這段代碼在出現(xiàn)亂碼時使用。如果mysign和sign不相等也可以使用這段代碼轉(zhuǎn)化
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
conversionParams.put(key, valueStr);
}
log.info("支付寶返回參數(shù)集合:"+conversionParams);
String status=aliPayCheck(conversionParams);
return status;
}
public String aliPayCheck(Map conversionParams){
log.info("=支付寶異步請求邏輯處理=");
//簽名驗證(對支付寶返回的數(shù)據(jù)驗證,確定是支付寶返回的)
boolean signVerified = false;
try {
//調(diào)用SDK驗證簽名
String alipayPublicKey = AliDevPayConfig.aliPayPublicKey;
String charset = AliDevPayConfig.CHARSET;
String signType = AliDevPayConfig.SIGN_TYPE;
signVerified = AlipaySignature.rsaCheckV1(conversionParams, alipayPublicKey, charset, signType);
//對驗簽進行處理.
if (signVerified) {
log.info("+++++++++++支付寶回調(diào)簽名認證成功+++++++++++");
// 按照支付結(jié)果異步通知中的描述,對支付結(jié)果中的業(yè)務內(nèi)容進行1\2\3\4二次校驗,校驗成功后在response中返回success,校驗失敗返回failure 支付寶官方建議校驗的值(out_trade_no、total_amount、sellerId、app_id)
//驗簽通過 獲取交易狀態(tài)
String tradeStatus = (String)conversionParams.get("trade_status");
//只處理支付成功的訂單: 修改交易表狀態(tài),支付成功
//只有交易通知狀態(tài)為TRADE_SUCCESS或TRADE_FINISHED時,支付寶才會認定為買家付款成功。
if (tradeStatus.equals("TRADE_SUCCESS") ||tradeStatus.equals("TRADE_FINISHED")) {
//TODO 獲取支付寶通知完成充值后續(xù)業(yè)務
//交易成功 獲取商戶賬單id
String billId = (String) conversionParams.get("out_trade_no");
//支付寶交易流水號
String ali_pay_no = (String) conversionParams.get("trade_no");
//TODO 修改業(yè)務訂單信息
//TODO 余額到賬,消息推送
return "success";
} else {
return "fail";
}
}else{ //驗簽不通過
log.info("++驗簽不通過 !++");
return "fail";
}
} catch (AlipayApiException e) {
log.info("+++驗簽失敗 !+++");
e.printStackTrace();
}
return "fail";
}
}
以上saveAliPayRechangeBill方法返回的類型如下
app_id=2015052600090779&biz_content=%7B%22timeout_express%22%3A%2230m%22%2C%22seller_id%22%3A%22%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22total_amount%22%3A%220.01%22%2C%22subject%22%3A%221%22%2C%22body%22%3A%22%E6%88%91%E6%98%AF%E6%B5%8B%E8%AF%95%E6%95%B0%E6%8D%AE%22%2C%22out_trade_no%22%3A%22IQJZSRC1YMQB5HU%22%7D&charset=utf-8&format=json&method=alipay.trade.app.pay¬ify_url=http%3A%2F%2Fdomain.merchant.com%2Fpayment_notify&sign_type=RSA2×tamp=2016-08-25%2020%3A26%3A31&version=1.0&sign=cYmuUnKi5QdBsoZEAbMXVMmRWjsuUj%2By48A2DvWAVVBuYkiBj13CFDHu2vZQvmOfkjE0YqCUQE04kqm9Xg3tIX8tPeIGIFtsIyp%2FM45w1ZsDOiduBbduGfRo1XRsvAyVAv2hCrBLLrDI5Vi7uZZ77Lo5J0PpUUWwyQGt0M4cj8g%3D
以上結(jié)果等價于如下,但上面才是正常的返回結(jié)果。
body="test"&_input_charset="UTF-8"&it_b_pay="1d"&total_fee="1"&subject="test"¬ify_url="http://www.bejson.com/api/alipay/testpayotify.php"&service="mobile.securitypay.pay"&seller_id="cw@bejson.com"&partner="2088301"&out_trade_no="2088301971894011"&payment_type="1"&show_url="http://www.dcloud.io/helloh5/"&sign="RtUKAGMfelb5sl2az4YKhxst051l94FSkpk9xoD91Hbpr2PKnWjHIafTWqNLyxGibde%2BKwcq9Y8cDN0qU%2FsO6hXjch0B4GaMJHBxZQM%2FnJK2YGxPPOWFKKL5rBKVJ%2BrX4OImfSQIyKKUpAEFG6uFfek2hh%2FPFJSXk2Phvmrb8U%3D"&sign_type="RSA"
調(diào)用時,請核對所有支付寶所必要的參數(shù),參考支付寶參數(shù)
至此就已經(jīng)差不多完成支付寶的接入了,如果有其他問題可以百度或者留言,如果有什么錯誤,歡迎多多指正批評。:)