Springboot?對(duì)接支付寶實(shí)現(xiàn)掃碼支付功能
前言
最近項(xiàng)目中需要對(duì)接支付模塊,需要考慮到微信支付與支付寶支付的實(shí)現(xiàn)。
由于微信支付的還在審核中,先預(yù)研demo做一個(gè)支付寶支付碼獲取的實(shí)現(xiàn)。
官方文檔以及說明
本次開發(fā)環(huán)境中編寫demo實(shí)現(xiàn),采用的是支付寶的沙箱方式,后續(xù)上線會(huì)重新申請(qǐng)正式的appid等信息。
支付寶開發(fā)平臺(tái)鏈接:https://open.alipay.com/
1、申請(qǐng)沙箱
進(jìn)入支付寶的開發(fā)平臺(tái),用支付寶登錄后,在控制臺(tái)面板中找到沙箱,并創(chuàng)建第一個(gè)沙箱。
https://open.alipay.com/develop/manage

2、進(jìn)入沙箱獲取對(duì)應(yīng)的關(guān)鍵信息

對(duì)于像授權(quán)回調(diào)地址、應(yīng)用網(wǎng)關(guān)地址這些暫時(shí)不設(shè)置。
3、拿到系統(tǒng)生成的公鑰和密鑰


這里會(huì)有應(yīng)用公鑰、支付寶公鑰和應(yīng)用私鑰。但這里通過個(gè)人實(shí)踐,只需要支付寶公鑰和應(yīng)用私鑰。
應(yīng)用公鑰在某些特定的場(chǎng)景中并不會(huì)生效還會(huì)出現(xiàn)各種奇怪的報(bào)錯(cuò)。
注意事項(xiàng)
沙箱并不是所有的操作都能夠在其中進(jìn)行開發(fā)操作,詳情參考官方文檔說明。
https://opendocs.alipay.com/common/097jyi?pathHash=9fcbe0d0&highlight_field=%E6%B2%99%E7%AE%B1%E7%8E%AF%E5%A2%83

創(chuàng)建springboot項(xiàng)目
1、引入依賴
選用的是springboot 2.x 的版本,并且引用的依賴在官方文檔中有版本說明。
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.34.47.ALL</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.0.0</version>
</dependency>參考官方文檔依賴版本規(guī)定:
https://opendocs.alipay.com/common/02n6z6?pathHash=f5e2a056
其中,針對(duì)通用版的版本要求,官方文檔中有做說明:
https://opendocs.alipay.com/common/02kkv2?pathHash=358ff034

2、配置連接參數(shù)
在src/main/resources中新建一個(gè)application.yml文件,如果是nacos項(xiàng)目,可以在對(duì)應(yīng)的配置中心中新增配置項(xiàng)。
# 支付寶支付
alipay:
# 應(yīng)用ID,標(biāo)識(shí)你的應(yīng)用
appId:
# 應(yīng)用私鑰,用于簽名請(qǐng)求
appPrivateKey:
# 應(yīng)用公鑰,用于驗(yàn)證支付寶的響應(yīng)
#alipayPublicKey: 沙箱頁(yè)面中的應(yīng)用公鑰
# 支付寶公鑰(推薦使用這個(gè))
alipayPublicKey: 支付寶公鑰
# 支付通知的回調(diào)地址,支付寶會(huì)在支付完成后通知這個(gè)地址
notifyUrl: 支付成功后的回調(diào)地址,必須要求公網(wǎng)能夠訪問
# 頁(yè)面跳轉(zhuǎn)地址,支付完成后跳轉(zhuǎn)到此URL
returnUrl: 場(chǎng)景一中登錄成功后的重定向頁(yè)面
# 簽名類型,通常為RSA2
signType: RSA2
# 字符編碼,通常為utf-8
charset: utf-8
# 支付寶網(wǎng)關(guān)地址,用于發(fā)送請(qǐng)求
gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do3、創(chuàng)建配置類,用于接收這些參數(shù)
package cn.alipay.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 支付寶 支付參數(shù)配置類
*/
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AlipayProperties {
/**
* APPID
*/
private String appId;
/**
* 應(yīng)用私鑰,就是工具生成的應(yīng)用私鑰
*/
public String appPrivateKey;
/**
* 支付寶公鑰,對(duì)應(yīng)APPID下的支付寶公鑰
*/
public String alipayPublicKey;
/**
* 支付寶會(huì)悄悄的給我們發(fā)送一個(gè)請(qǐng)求,告訴我們支付成功的信息
*/
public String notifyUrl;
/**
* 同步通知,支付成功,一般跳轉(zhuǎn)到成功頁(yè)
*/
public String returnUrl;
/**
* 簽名方式
*/
private String signType;
/**
* 字符編碼格式
*/
private String charset;
/**
* 支付寶網(wǎng)關(guān);https://openapi-sandbox.dl.alipaydev.com/gateway.do
*/
public String gatewayUrl;
/**
* 訂單超時(shí)時(shí)間
*/
private String timeout = "5m";
}新建配置類,獲取對(duì)應(yīng)的配置參數(shù),并構(gòu)建連接對(duì)象
package cn.alipay.config;
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.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.BusinessParams;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.domain.SettleDetailInfo;
import com.alipay.api.domain.SettleInfo;
import com.alipay.api.internal.util.WebUtils;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* 支付寶支付 模板
*/
@Slf4j
@Data
@Component
public class AliPayTemplate {
@Autowired
private AlipayProperties alipayProperties;
private AlipayClient alipayClient;
@PostConstruct
public void init() {
log.info("APPID:" + alipayProperties.getAppId());
log.info("應(yīng)用私鑰:" + alipayProperties.getAppPrivateKey());
log.info("支付寶公鑰:" + alipayProperties.getAlipayPublicKey());
log.info("支付寶會(huì)悄悄的給我們發(fā)送一個(gè)請(qǐng)求,告訴我們支付成功的信息:" + alipayProperties.getNotifyUrl());
log.info("同步通知,支付成功,一般跳轉(zhuǎn)到成功頁(yè):" + alipayProperties.getReturnUrl());
log.info("簽名方式:" + alipayProperties.getSignType());
log.info("字符編碼格式:" + alipayProperties.getCharset());
log.info("訂單超時(shí)時(shí)間:" + alipayProperties.getTimeout());
log.info("支付寶網(wǎng)關(guān):" + alipayProperties.getGatewayUrl());
// 1. 根據(jù)支付寶的配置生成一個(gè)支付客戶端
alipayClient = new DefaultAlipayClient(
alipayProperties.getGatewayUrl(),
alipayProperties.getAppId(),
alipayProperties.getAppPrivateKey(),
"json",
alipayProperties.getCharset(),
alipayProperties.getAlipayPublicKey(),
alipayProperties.getSignType()
);
}
}4、中間類的定義(訂單類)
創(chuàng)建一個(gè)訂單類,主要用于一些基本信息的傳參處理。
package cn.alipay.config;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 訂單表
*/
@Data
public class Order implements Serializable {
/**
* 訂單Id
*/
private Long id;
/**
* 用戶Id
*/
private Long userId;
/**
* 接口Id
*/
private Long interfaceInfoId;
/**
* 支付金額
*/
private Double money;
/**
* 支付方式
*/
private String paymentMethod;
/**
* 0 - 未支付 1 - 已支付
*/
private Integer status;
/**
* 創(chuàng)建時(shí)間
*/
private Date createTime;
/**
* 更新時(shí)間
*/
private Date updateTime;
/**
* 是否刪除
*/
private Integer isDelete;
private static final long serialVersionUID = 1L;
}5、編寫測(cè)試接口
場(chǎng)景一、pc端請(qǐng)求后端后,生成支付寶的特制頁(yè)面(AlipayTradePagePayRequest)
在支付寶的PC端案例文檔中,有一個(gè)注意事項(xiàng)。
https://opendocs.alipay.com/open/00dn7o?pathHash=c1e36251
像這種傳遞訂單信息至后臺(tái),后臺(tái)調(diào)用支付寶的對(duì)應(yīng)接口后,返回前端頁(yè)面樣式或者地址,前端再進(jìn)行渲染實(shí)現(xiàn)??梢詤⒄找韵碌姆绞健?/p>
定義接口
package cn.alipay.controller;
import cn.alipay.config.AliPayTemplate;
import cn.alipay.config.Order;
import com.alipay.api.AlipayApiException;
import com.alipay.easysdk.factory.Factory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.MimeTypeUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 阿里支付寶支付與回調(diào)接口
*/
@Slf4j
@RestController
@RequestMapping("/alipay")
public class AliPayController {
@Autowired
private AliPayTemplate aliPayTemplate;
/**
* 獲取支付寶
* post 請(qǐng)求 生成 frame 頁(yè)面
* get 請(qǐng)求生成 頁(yè)面url
* @param id
* @return
* @throws AlipayApiException
*/
@GetMapping(value = "/pay", produces = MimeTypeUtils.TEXT_HTML_VALUE)
@ResponseBody
public String pay(@RequestParam long id) throws AlipayApiException {
// 創(chuàng)建訂單對(duì)象并設(shè)置屬性
Order order = createOrder(id);
// 調(diào)用支付寶支付模板進(jìn)行支付
return aliPayTemplate.pay(order);
}
/**
* 偽造訂單數(shù)據(jù)
* @param id
* @return
*/
private Order createOrder(long id) {
Order order = new Order();
order.setId(id);
order.setUserId(1111111L);
order.setInterfaceInfoId(294389472934L);
order.setMoney(1000.0);
order.setPaymentMethod("支付寶");
return order;
}
}定義請(qǐng)求邏輯代碼
package cn.alipay.config;
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.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.BusinessParams;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.domain.SettleDetailInfo;
import com.alipay.api.domain.SettleInfo;
import com.alipay.api.internal.util.WebUtils;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* 支付寶支付 模板
*/
@Slf4j
@Data
@Component
public class AliPayTemplate {
@Autowired
private AlipayProperties alipayProperties;
private AlipayClient alipayClient;
@PostConstruct
public void init() {
log.info("APPID:" + alipayProperties.getAppId());
log.info("應(yīng)用私鑰:" + alipayProperties.getAppPrivateKey());
log.info("支付寶公鑰:" + alipayProperties.getAlipayPublicKey());
log.info("支付寶會(huì)悄悄的給我們發(fā)送一個(gè)請(qǐng)求,告訴我們支付成功的信息:" + alipayProperties.getNotifyUrl());
log.info("同步通知,支付成功,一般跳轉(zhuǎn)到成功頁(yè):" + alipayProperties.getReturnUrl());
log.info("簽名方式:" + alipayProperties.getSignType());
log.info("字符編碼格式:" + alipayProperties.getCharset());
log.info("訂單超時(shí)時(shí)間:" + alipayProperties.getTimeout());
log.info("支付寶網(wǎng)關(guān):" + alipayProperties.getGatewayUrl());
// 1. 根據(jù)支付寶的配置生成一個(gè)支付客戶端
alipayClient = new DefaultAlipayClient(
alipayProperties.getGatewayUrl(),
alipayProperties.getAppId(),
alipayProperties.getAppPrivateKey(),
"json",
alipayProperties.getCharset(),
alipayProperties.getAlipayPublicKey(),
alipayProperties.getSignType()
);
}
/**
* 調(diào)用支付接口
* @param order
* @return
* @throws AlipayApiException
*/
public String pay(Order order) throws AlipayApiException {
//2、創(chuàng)建一個(gè)支付請(qǐng)求,并設(shè)置請(qǐng)求參數(shù)
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(alipayProperties.getReturnUrl());
alipayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());
Long id = order.getId();
Long interfaceInfoId = order.getInterfaceInfoId();
Double money = order.getMoney();
String paymentMethod = order.getPaymentMethod();
// 設(shè)置業(yè)務(wù)內(nèi)容,包含必要的支付參數(shù)
AlipayTradePagePayModel pagePayModel = new AlipayTradePagePayModel();
pagePayModel.setOutTradeNo(String.valueOf(id));
pagePayModel.setTotalAmount(String.valueOf(money));
pagePayModel.setSubject(String.valueOf(interfaceInfoId));
pagePayModel.setBody(paymentMethod);
pagePayModel.setTimeoutExpress(alipayProperties.getTimeout());
// 電腦支付場(chǎng)景下僅支持FAST_INSTANT_TRADE_PAY
pagePayModel.setProductCode("FAST_INSTANT_TRADE_PAY");
alipayRequest.setBizModel(pagePayModel);
// post 請(qǐng)求返回 frame 前端樣式
AlipayTradePagePayResponse response = alipayClient.pageExecute(alipayRequest, "POST");
// get 請(qǐng)求返回一個(gè)頁(yè)面地址url
AlipayTradePagePayResponse response2 = alipayClient.pageExecute(alipayRequest, "GET");
String result = response.getBody();
//返回支付寶響應(yīng)的結(jié)果
return result;
}
}啟動(dòng)服務(wù),請(qǐng)求后的效果如下:
localhost:8080/alipay/pay?id=123456
post 請(qǐng)求生成的樣式如下所示:
<form name="punchout_form" method="post" action="會(huì)有對(duì)應(yīng)的信息">
<input type="hidden" name="biz_content" value="{"body":"支付寶","out_trade_no":"125477","product_code":"FAST_INSTANT_TRADE_PAY","subject":"294389472934","timeout_express":"5m","total_amount":"1000.0"}">
<input type="submit" value="立即支付" style="display:none" >
</form>
<script>document.forms[0].submit();</script>如果是GET請(qǐng)求,則只會(huì)是上面action的地址。
場(chǎng)景二、前端請(qǐng)求后端,只返回對(duì)應(yīng)的二維碼地址(AlipayTradePrecreateRequest)
參照官方文檔中的案例實(shí)現(xiàn)
https://opendocs.alipay.com/open/8ad49e4a_alipay.trade.precreate?scene=2ae8516856f24a5592194d237f3f235d&pathHash=d18bff53
編寫對(duì)應(yīng)的接口和實(shí)現(xiàn)類
@GetMapping(value = "/pay3")
@ResponseBody
public String pay3(@RequestParam long id) throws AlipayApiException {
// 創(chuàng)建訂單對(duì)象并設(shè)置屬性
Order order = createOrder(id);
// 調(diào)用支付寶支付模板進(jìn)行支付
return aliPayTemplate.pay3(order);
}package cn.alipay.config;
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.AlipayTradePagePayModel;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.AlipayTradePrecreateModel;
import com.alipay.api.domain.BusinessParams;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.domain.SettleDetailInfo;
import com.alipay.api.domain.SettleInfo;
import com.alipay.api.internal.util.WebUtils;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePagePayResponse;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
/**
* 支付寶支付 模板
*/
@Slf4j
@Data
@Component
public class AliPayTemplate {
@Autowired
private AlipayProperties alipayProperties;
private AlipayClient alipayClient;
@PostConstruct
public void init() {
log.info("APPID:" + alipayProperties.getAppId());
log.info("應(yīng)用私鑰:" + alipayProperties.getAppPrivateKey());
log.info("支付寶公鑰:" + alipayProperties.getAlipayPublicKey());
log.info("支付寶會(huì)悄悄的給我們發(fā)送一個(gè)請(qǐng)求,告訴我們支付成功的信息:" + alipayProperties.getNotifyUrl());
log.info("同步通知,支付成功,一般跳轉(zhuǎn)到成功頁(yè):" + alipayProperties.getReturnUrl());
log.info("簽名方式:" + alipayProperties.getSignType());
log.info("字符編碼格式:" + alipayProperties.getCharset());
log.info("訂單超時(shí)時(shí)間:" + alipayProperties.getTimeout());
log.info("支付寶網(wǎng)關(guān):" + alipayProperties.getGatewayUrl());
// 1. 根據(jù)支付寶的配置生成一個(gè)支付客戶端
alipayClient = new DefaultAlipayClient(
alipayProperties.getGatewayUrl(),
alipayProperties.getAppId(),
alipayProperties.getAppPrivateKey(),
"json",
alipayProperties.getCharset(),
alipayProperties.getAlipayPublicKey(),
alipayProperties.getSignType()
);
}
public String pay3(Order order) throws AlipayApiException {
AlipayTradePrecreateRequest alipayRequest = new AlipayTradePrecreateRequest();
// 強(qiáng)制關(guān)閉 ssl 證書校驗(yàn)
WebUtils.setNeedCheckServerTrusted(false);
alipayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());
JSONObject jsonObject = new JSONObject();
jsonObject.put("out_trade_no",order.getId());// 商戶訂單號(hào)
jsonObject.put("total_amount",order.getMoney());// 商品價(jià)格
jsonObject.put("subject","這只是個(gè)商品標(biāo)題");// 商品標(biāo)題
jsonObject.put("store_id","香蕉集團(tuán)");//組織或公司名
// jsonObject.put("timeout_express","5m");// 訂單有效時(shí)間
alipayRequest.setBizContent(jsonObject.toString());
AlipayTradePrecreateResponse response = alipayClient.execute(alipayRequest);
System.out.println("創(chuàng)建訂單結(jié)果:"+response.getBody());
System.out.println("訂單編號(hào)是"+response.getOutTradeNo());
String qrCode = response.getQrCode();
// AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
return qrCode;
}
}請(qǐng)求后會(huì)得到一個(gè)支付的地址,使用ZXing框架,將其轉(zhuǎn)換為二維碼。
場(chǎng)景三、沙箱APP掃碼支付后回調(diào)處理
在每次請(qǐng)求AliPay的接口時(shí),都會(huì)傳遞一個(gè)回調(diào)接口參數(shù)。
alipayRequest.setNotifyUrl(alipayProperties.getNotifyUrl());
這個(gè)參數(shù)主要是用于告知AliPay在支付操作中,各項(xiàng)信息的回調(diào)信息,是個(gè)異步的操作。
針對(duì)回調(diào),判斷是否是支付成功,可以參照如下邏輯:
/**
* 支付寶 支付 異步回調(diào)接口 必須是 Post
* @param request
* @return
* @throws Exception
*/
@PostMapping("/notify")
public String payNotify(HttpServletRequest request) throws Exception {
// 檢查交易狀態(tài)是否為成功
if (!"TRADE_SUCCESS".equalsIgnoreCase(request.getParameter("trade_status"))) {
// 如果狀態(tài)不是成功,則返回失敗
return "failure";
}
log.info("=========支付寶異步回調(diào)========");
// .... 此處省略部分業(yè)務(wù)邏輯
aliPayServide.payNotify(request);
return "success";
}業(yè)務(wù)層中的代碼片段如下:
public void payNotify(HttpServletRequest request) throws AlipayApiException {
// 創(chuàng)建一個(gè)存儲(chǔ)請(qǐng)求參數(shù)的Map
Map<String, String> params = getRequestParams(request);
String tradeNo = params.get("out_trade_no");
// 驗(yàn)證支付寶返回的簽名
if (!verifySignature(params)) {
log.info("----驗(yàn)簽失敗----");
return;
}
// 記錄交易詳情
logTransactionDetails(params);
// 其他業(yè)務(wù)邏輯
}
/**
* 記錄交易詳情的方法
* @param params
*/
private void logTransactionDetails(Map<String, String> params) {
log.info("交易名稱: " + params.get("subject"));
log.info("交易狀態(tài): " + params.get("trade_status"));
log.info("支付寶交易憑證號(hào): " + params.get("trade_no"));
log.info("商戶訂單號(hào): " + params.get("out_trade_no"));
log.info("交易金額: " + params.get("total_amount"));
log.info("買家在支付寶唯一id: " + params.get("buyer_id"));
log.info("買家付款時(shí)間: " + params.get("gmt_payment"));
log.info("買家付款金額: " + params.get("buyer_pay_amount"));
// 記錄日志
ChatAliPayDetailLog chatAliPayDetailLog = ChatAliPayDetailLog.builder()
.id(IdUtil.getSnowflakeNextIdStr())
.subject(params.get("subject"))
.tradeStatus(params.get("trade_status"))
.tradeNo(params.get("trade_no"))
.outTradeNo(params.get("out_trade_no"))
.totalAmount(new BigDecimal(params.get("total_amount")))
.buyerId(params.get("buyer_id"))
.gmtPayment(DateUtil.parseDate(params.get("gmt_payment")))
.buyerPayAmount(new BigDecimal(params.get("buyer_pay_amount")))
.createdTime(new Date())
.build();
chatAliPayDetailLogMapper.insert(chatAliPayDetailLog);
}
/**
* 驗(yàn)證簽名
* @param params
* @return
*/
private boolean verifySignature(Map<String, String> params) throws AlipayApiException {
String sign = params.get("sign");
String content = AlipaySignature.getSignCheckContentV1(params);
return AlipaySignature.rsa256CheckContent(content, sign, alipayProperties.getAlipayPublicKey(), "UTF-8");
}
/**
* 提取請(qǐng)求參數(shù)的方法
* @param request
* @return
*/
private Map<String, String> getRequestParams(HttpServletRequest request) {
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
return params;
}但回調(diào)處理是一個(gè)異步,如果前端界面中需要實(shí)時(shí)獲取支付成功狀態(tài),可以使用輪訓(xùn)的方式,定時(shí)去查詢支付結(jié)果。
場(chǎng)景四、定時(shí)查詢支付結(jié)果
在官方文檔中,其中提供有一個(gè)alipay.trade.query(統(tǒng)一收單交易查詢),專門提供查詢操作。
https://opendocs.alipay.com/open/217dd591_alipay.trade.query?scene=common&pathHash=62ae74aa
代碼片段如下所示:
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
AlipayTradeQueryModel model = new AlipayTradeQueryModel();
model.setOutTradeNo(chatUserPayOrder.getOrderNo());
request.setBizModel(model);
try {
AlipayTradeQueryResponse response = alipayClient.execute(request);
if ("TRADE_SUCCESS".equalsIgnoreCase(response.getTradeStatus())) {
// 成功支付 則進(jìn)行后續(xù)處理
insertLog(response);
// 根據(jù) response.getOutTradeNo() 修改對(duì)應(yīng)的支付信息
updatePayOrderStatus(response);
}
} catch (AlipayApiException e) {
throw new RuntimeException(e);
}也可以考慮定時(shí)任務(wù)xxl-job定時(shí)去獲取所有未收到支付狀態(tài)的數(shù)據(jù),請(qǐng)求獲取最終結(jié)果。或者超過限定時(shí)間表示失效等邏輯。
到此這篇關(guān)于Springboot 對(duì)接支付寶實(shí)現(xiàn)掃碼支付的文章就介紹到這了,更多相關(guān)Springboot 掃碼支付內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
FeignClient實(shí)現(xiàn)接口調(diào)用方式(不同參數(shù)形式)
這篇文章主要介紹了FeignClient實(shí)現(xiàn)接口調(diào)用方式(不同參數(shù)形式),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
如何動(dòng)態(tài)替換Spring容器中的Bean
這篇文章主要介紹了如何動(dòng)態(tài)替換Spring容器中的Bean,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
SpringBoot生產(chǎn)環(huán)境和測(cè)試環(huán)境配置分離的教程詳解
這篇文章主要介紹了SpringBoot生產(chǎn)環(huán)境和測(cè)試環(huán)境配置分離的教程詳解,需要的朋友可以參考下2020-08-08
java lambda循環(huán)_使用Java 8 Lambda簡(jiǎn)化嵌套循環(huán)操作
這篇文章主要介紹了java lambda循環(huán)_使用Java 8 Lambda簡(jiǎn)化嵌套循環(huán)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-09-09
mybatis3.4.6 批量更新 foreach 遍歷map 的正確姿勢(shì)詳解
這篇文章主要介紹了mybatis3.4.6 批量更新 foreach 遍歷map 的正確姿勢(shì)詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-11-11
使用FeignClient進(jìn)行微服務(wù)交互方式(微服務(wù)接口互相調(diào)用)
這篇文章主要介紹了使用FeignClient進(jìn)行微服務(wù)交互方式(微服務(wù)接口互相調(diào)用),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
Java?I/O?(Input/Output)文件字節(jié)流舉例詳解
Java的輸入輸出流(IO)是用于與外部設(shè)備(如文件、網(wǎng)絡(luò)連接等)進(jìn)行數(shù)據(jù)交互的機(jī)制,下面這篇文章主要給大家介紹了關(guān)于Java?I/O?(Input/Output)文件字節(jié)流的相關(guān)資料,需要的朋友可以參考下2024-08-08

