目錄
1.查看沙箱賬號(hào)
2.內(nèi)網(wǎng)穿透
3.沙箱環(huán)境整合SpringBoot開(kāi)發(fā)
下面我將以實(shí)際案例詳細(xì)介紹如何使用沙箱環(huán)境進(jìn)行支付寶支付對(duì)接的開(kāi)發(fā)
1.查看沙箱賬號(hào)
?首先什么是沙箱賬號(hào)?
沙箱賬號(hào)是指在支付寶沙箱環(huán)境中創(chuàng)建的測(cè)試賬戶,用于模擬真實(shí)的支付流程。在開(kāi)發(fā)和測(cè)試過(guò)程中,使用沙箱賬號(hào)可以避免真實(shí)賬戶數(shù)據(jù)的泄露和風(fēng)險(xiǎn),同時(shí)可以進(jìn)行多種測(cè)試場(chǎng)景和交易模擬,以保證應(yīng)用程序的穩(wěn)定性和可靠性。
支付寶沙箱環(huán)境中的測(cè)試賬戶和真實(shí)賬戶一樣,可以進(jìn)行支付、退款、查詢等操作。開(kāi)發(fā)人員可以通過(guò)創(chuàng)建和使用沙箱賬號(hào),進(jìn)行多種測(cè)試和調(diào)試,以保證應(yīng)用程序的正確性和穩(wěn)定性。同時(shí),沙箱賬號(hào)的創(chuàng)建和使用是免費(fèi)的,不需要任何費(fèi)用。
需要注意的是,沙箱賬號(hào)只能在支付寶沙箱環(huán)境中使用,不能在生產(chǎn)環(huán)境中使用。在將應(yīng)用程序上線之前,需要使用真實(shí)賬戶進(jìn)行測(cè)試和驗(yàn)證。
1.登錄支付寶開(kāi)放平臺(tái):https://open.alipay.com/platform/home.htm
?
?2.點(diǎn)擊登錄,系統(tǒng)會(huì)彈出一個(gè)二維碼進(jìn)行掃描登錄,當(dāng)然也可以使用賬號(hào)密碼進(jìn)行登錄
3.點(diǎn)擊進(jìn)入控制臺(tái)
?
4.開(kāi)發(fā)工具推薦中選擇使用沙箱環(huán)境
?
5.自此完成沙箱賬號(hào)信息的查看
2.內(nèi)網(wǎng)穿透
獲取方式:電腦應(yīng)用商店搜索花生殼
網(wǎng)頁(yè)端申請(qǐng)配置:
1.需要進(jìn)行實(shí)名認(rèn)證否則用不了
2.需要花6元買(mǎi)個(gè)域名映射
?3.將ip和端口換成剛剛申請(qǐng)的域名,填入回調(diào)地址處,用于后續(xù)的支付寶系統(tǒng)回調(diào)接口
客戶端:開(kāi)啟自定義映射
下面將進(jìn)入主題,如何整合SpringBoot進(jìn)行支付開(kāi)發(fā)
3.沙箱環(huán)境整合SpringBoot開(kāi)發(fā)
?1.1.創(chuàng)建Spring Boot項(xiàng)目
可以使用Spring Initializr快速創(chuàng)建一個(gè)新項(xiàng)目也可以在maven創(chuàng)建的基礎(chǔ)上加上相關(guān)的依賴。
如果您是maven創(chuàng)建的項(xiàng)目請(qǐng)加如下依賴:
<dependencies>
<!-- Spring Boot starter dependencies -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.5.4</version>
</dependency>
</dependencies>
如果是基于Spring Initializr快速創(chuàng)建一個(gè)SpringBoot項(xiàng)目則導(dǎo)入如下依賴:
2.導(dǎo)入依賴
<dependencies>
<!-- Other dependencies -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.0.0</version>
</dependency>
<!-- Fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.78</version>
</dependency>
<!-- slf4j -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<!-- JSON -->
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20210307</version>
</dependency>
</dependencies>
3.配置應(yīng)用程序
在application.yml文件中,我們需要添加支付寶支付的相關(guān)配置。
# 應(yīng)用ID,您的APPID,收款賬號(hào)既是您的APPID對(duì)應(yīng)支付寶賬號(hào),在沙箱應(yīng)用中獲取
appId:
# 商戶私鑰,您的PKCS8格式RSA2私鑰,通過(guò)開(kāi)發(fā)助手生成的應(yīng)用私鑰
privateKey:
# 支付寶公鑰,在沙箱應(yīng)用獲取,通過(guò)應(yīng)用公鑰生成支付寶公鑰
publicKey:
# 服務(wù)器異步通知頁(yè)面路徑需http://格式的完整路徑,不能加?id=123這類(lèi)自定義參數(shù)
notifyUrl: https://7*****.zicp.fun/alipay/notify
# 頁(yè)面跳轉(zhuǎn)同步通知頁(yè)面路徑 需http://格式的完整路徑,不能加?id=123這類(lèi)自定義參數(shù)
returnUrl: https://7*****.zicp.fun/alipay/success
# 支付寶網(wǎng)關(guān),在沙箱應(yīng)用中獲取
gatewayUrl:
?下面就上面的參數(shù)進(jìn)行說(shuō)明
?
所以應(yīng)用ID、應(yīng)用私鑰和支付寶公鑰可以在支付寶開(kāi)放平臺(tái)上獲取。gateway-url是支付寶支付接口的地址,return-url和notify-url是支付完成后跳轉(zhuǎn)的地址和支付結(jié)果通知地址。
4.創(chuàng)建支付服務(wù)
接下來(lái),創(chuàng)建一個(gè)支付服務(wù)類(lèi),用于處理支付請(qǐng)求和支付結(jié)果通知。在創(chuàng)建支付服務(wù)之前,我要先創(chuàng)建一個(gè)AlipayClient對(duì)象,用于調(diào)用支付寶支付接口。
@Configuration
public class AlipayConfig {
//獲取配置文件中的配置信息
//應(yīng)用ID,您的APPID,收款賬號(hào)既是您的APPID對(duì)應(yīng)支付寶賬號(hào)
@Value("${appId}")
private String appId;
//商戶私鑰 您的PKCS8格式RSA2私鑰
@Value("${privateKey}")
private String privateKey;
//支付寶公鑰
@Value("${publicKey}")
private String publicKey;
//支付寶網(wǎng)關(guān)
@Value("${gatewayUrl}")
private String gatewayUrl;
@Bean
public AlipayClient alipayClient() {
return new DefaultAlipayClient(gatewayUrl, appId, privateKey, "json", "UTF-8", publicKey, "RSA2");
}
}
再創(chuàng)建一個(gè)支付服務(wù),用于處理支付請(qǐng)求和支付結(jié)果通知。
@Service
public class AlipayService {
@Autowired
private AlipayClient alipayClient;
//服務(wù)器異步通知頁(yè)面路徑
@Value("${notifyUrl}")
private String notifyUrl;
//頁(yè)面跳轉(zhuǎn)同步通知頁(yè)面路徑
@Value("${returnUrl}")
private String returnUrl;
/**
* 發(fā)起支付請(qǐng)求
* @param order 訂單信息
* @return 支付頁(yè)面HTML代碼
*/
public String pay(Order order) {
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setReturnUrl(returnUrl);
request.setNotifyUrl(notifyUrl);
Map<String, Object> params = new HashMap<>();
params.put("out_trade_no", order.getOrderId());
params.put("total_amount", order.getTotalAmount());
params.put("subject", order.getSubject());
params.put("body", order.getBody());
params.put("product_code", "FAST_INSTANT_TRADE_PAY");
request.setBizContent(JSON.toJSONString(params));
try {
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
return response.getBody();
} catch (AlipayApiException e) {
throw new RuntimeException("支付寶支付失敗", e);
}
}
/**
* 處理支付結(jié)果通知
*
* @param request 支付結(jié)果通知參數(shù)
* @return 處理結(jié)果
*/
public String notify(HttpServletRequest request) throws AlipayApiException {
log.info("異步回調(diào)");
Map<String, String> params = new HashMap<String, String>();
Map<String, String[]> requestParams = request.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = iter.next();
String[] values = requestParams.get(name);
StringBuilder valueStr = new StringBuilder();
for (int i = 0; i < values.length; i++) {
valueStr.append((i == values.length - 1) ? values[i] : values[i] + ",");
}
params.put(name, valueStr.toString());
}
log.info("請(qǐng)求參數(shù)的傳入:" + params);
String tradeStatus = params.get("trade_status");
log.info("tradeStatus:" + tradeStatus);
String outTradeNo = params.get("out_trade_no");
log.info("outTradeNo:" + outTradeNo);
String totalAmount = params.get("total_amount");
log.info("totalAmount:" + totalAmount);
//
// // 從數(shù)據(jù)庫(kù)中查詢訂單信息
// Order order = orderService.findByOutTradeNo(outTradeNo);
// 驗(yàn)證通知是否來(lái)自支付寶服務(wù)器
if (!AlipaySignature.rsaCheckV1(params, publicKey, charset, signType)) {
return "fail";
}
// 驗(yàn)證交易狀態(tài)和訂單金額等信息
// if (!"TRADE_SUCCESS".equals(tradeStatus) || !totalAmount.equals(order.getTotalAmount().toString())) {
if (!"TRADE_SUCCESS".equals(tradeStatus)) {
return "fail";
}
// 根據(jù)交易狀態(tài)進(jìn)行業(yè)務(wù)處理
switch (tradeStatus) {
case "TRADE_SUCCESS":
// 更新訂單狀態(tài)、發(fā)貨等操作
break;
case "TRADE_CLOSED":
// 訂單關(guān)閉處理
break;
default:
// 其他狀態(tài)處理
break;
}
return "success";
}
public String success(HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException {
log.info("=================同步回調(diào)======================");
// 獲取支付寶GET過(guò)來(lái)反饋信息
Map<String, String> params = new HashMap<String, String>();
Map<String, String[]> requestParams = request.getParameterMap();
for (Iterator<String> 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] + ",";
}
// 亂碼解決,這段代碼在出現(xiàn)亂碼時(shí)使用
valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
log.info("支付寶平臺(tái)同步回調(diào)傳入的參數(shù):" + params);
//驗(yàn)證簽名(支付寶公鑰)
boolean signVerified = AlipaySignature.rsaCheckV1(params, publicKey, charset, signType); // 調(diào)用SDK驗(yàn)證簽名
//驗(yàn)證簽名通過(guò)
if (signVerified) {
// 商戶訂單號(hào)
String out_trade_no = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 支付寶交易流水號(hào)
String trade_no = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"), "UTF-8");
// 付款金額
float money = Float.parseFloat(new String(request.getParameter("total_amount").getBytes("ISO-8859-1"), "UTF-8"));
log.info("商戶訂單號(hào)=" + out_trade_no);
log.info("支付寶交易號(hào)=" + trade_no);
log.info("付款金額=" + money);
//在這里編寫(xiě)自己的業(yè)務(wù)代碼(對(duì)數(shù)據(jù)庫(kù)的操作)
/*
################################
*/
//跳轉(zhuǎn)到提示頁(yè)面(成功或者失敗的提示頁(yè)面)
return "交易成功!";
} else {
//跳轉(zhuǎn)到提示頁(yè)面(成功或者失敗的提示頁(yè)面)
return "交易失??!";
}
}
}
在AlipayService類(lèi)中,我們使用@Autowired注解注入AlipayClient對(duì)象,并使用@Value注解注入支付寶支付的相關(guān)配置。
pay方法用于發(fā)起支付請(qǐng)求,首先創(chuàng)建一個(gè)AlipayTradePagePayRequest對(duì)象,設(shè)置returnUrl和notifyUrl,然后將訂單信息封裝成一個(gè)Map對(duì)象,調(diào)用alipayClient的pageExecute方法發(fā)起支付請(qǐng)求,并返回支付頁(yè)面的HTML代碼。
notify方法用于處理支付結(jié)果通知,首先使用AlipaySignature.rsaCheckV1方法驗(yàn)證支付結(jié)果通知的簽名,然后根據(jù)支付結(jié)果更新訂單狀態(tài)。
success方法也是如此,但是開(kāi)發(fā)中用notify異步處理效率更高一些。
?5.5.創(chuàng)建支付控制器
創(chuàng)建一個(gè)支付控制器,用于處理支付請(qǐng)求和支付結(jié)果通知。
@Controller
@RequestMapping("/alipay")
public class AlipayController {
@Autowired
private AlipayService alipayService;
/**
* 發(fā)起支付請(qǐng)求
* @param order 訂單信息
* @return 支付頁(yè)面HTML代碼
*/
@RequestMapping("/pay")
@ResponseBody
public String pay(Order order) {
return alipayService.pay(order);
}
/**
* 處理支付結(jié)果通知
* @param request 支付結(jié)果通知參數(shù)
* @return 處理結(jié)果
*/
@PostMapping("/notify")
@ResponseBody
public String notify(@RequestParam HttpServletRequest request) throws AlipayApiException {
return alipayService.notify(request);
}
/**
* 支付完成后跳轉(zhuǎn)回商戶網(wǎng)站的地址
*
* @return 跳轉(zhuǎn)頁(yè)面
*/
@RequestMapping("/success")
@ResponseBody
public String success(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException {
return alipayService.success(request);
}
//根據(jù)自己的實(shí)際業(yè)務(wù)選擇是同步處理還是異步處理
}
在AlipayController類(lèi)中,我們使用@Autowired注解注入AlipayService對(duì)象,并創(chuàng)建pay、notify和returnUrl三個(gè)方法,分別用于處理支付請(qǐng)求、支付結(jié)果通知和支付完成后跳轉(zhuǎn)回商戶網(wǎng)站的地址。?
? ? ? ? 這里需要注意的是,只有當(dāng)方法的返回值類(lèi)型為
void
或String
時(shí),才需要使用@ResponseBody
注解。如果方法的返回值類(lèi)型為其他類(lèi)型(如對(duì)象、集合等),Spring MVC會(huì)自動(dòng)將其轉(zhuǎn)換為JSON或XML格式的數(shù)據(jù)并返回給客戶端,無(wú)需使用@ResponseBody
注解。
?6.測(cè)試支付功能
現(xiàn)在,我們已經(jīng)完成了支付寶支付的整合,可以通過(guò)調(diào)用支付控制器中的pay方法發(fā)起支付請(qǐng)求,并在支付完成后處理支付結(jié)果通知和支付完成后跳轉(zhuǎn)回商戶網(wǎng)站的地址。
可以通過(guò)Postman等工具模擬支付請(qǐng)求,或者在網(wǎng)站上添加一個(gè)支付按鈕,點(diǎn)擊按鈕后跳轉(zhuǎn)到支付頁(yè)面完成支付。
在網(wǎng)站上面添加一個(gè)支付按鈕
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/alipay/pay" method="post">
訂單號(hào):<input type="text" name="out_trade_no" required><br/>
訂單名稱:<input type="text" name="subject" required><br/>
付款金額:<input type="text" name="total_amount" required><br/>
商品描述:<input type="text" name="body"><br/>
<input type="submit" value="下單"> <input type="reset" value="重置">
</form>
</body>
</html>
瀏覽器地址欄輸入:http://localhost:8081/
輸入支付賬號(hào)和支付密碼即可完成支付
? ? ? ? ? ? ? ? ? ? ?支付寶沙箱環(huán)境+SpringBoot+內(nèi)網(wǎng)穿透整合開(kāi)發(fā)完美收官!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-413674.html
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 有任何問(wèn)題隨時(shí)私信我!文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-413674.html
到了這里,關(guān)于支付寶沙箱環(huán)境+SpringBoot+內(nèi)網(wǎng)穿透整合開(kāi)發(fā)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!