1. 程式人生 > 其它 >SpringBoot接入支付寶教程

SpringBoot接入支付寶教程

碼雲地址:

前言:

今天在一個公眾號看到了這樣一篇文章,寫的是:SpringBoot接入支付寶,看了那篇文章發現寫的比較一般,本著求知的心態,今天想著接觸下接入支付寶,然後寫個部落格~

參考部落格:

  springboot接入支付寶支付-新版SDK(2020/11/03)

使用到的支付寶開發網址:

  支付寶開發助手

  支付寶開放平臺-沙箱環境

  MiniU研發工作臺

  ngrok:內網穿透

下面需要使用到的連結或者祕鑰我都會用紅色標註出來

一、環境搭建

1、應用公鑰/私鑰的獲取

  進入到支付寶開發助手-->MiniU研發工作臺,以前的話應該是讓下載軟體什麼的獲取祕鑰,現在可以直接通過網頁進行獲取了

複製下來生成的公鑰跟私鑰,記到小本子上面~

2、APPID、支付寶公鑰的獲取

進入到支付寶開放平臺-沙箱環境,複製我們剛剛生成的公鑰,放在對應的框框中即可生成"支付寶公鑰"

複製你的APPID

複製生成的支付寶公鑰~

記得複製下來支付寶提供的測試賬號,下面測試要用:

3、內網穿透設定

我使用的是Windows環境,這裡我就下載Windows版本的ngrok,這是國外的網站有的小夥伴下載比較慢,可以使用藍奏雲下載:https://wws.lanzoui.com/izXZZsuw9wb

下載完成之後,使用命令列進入到解壓後的目錄,複製內網穿透的連結:注意先別把視窗關閉了。

1、進入目錄:滑鼠放到導航欄上面,輸入cmd,即可快速進入

2、啟動應用:ngrok http 埠

二、程式碼整理

新建SpringBoot專案(只需新增SpringBootWeb依賴即可),專案結構如下:

pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-easysdk</artifactId>
    <version>2.1.0</version>
</dependency>

application.properties  

## 埠
server.port=8080
## 支付寶配置
# 應用ID
alipay.appId=把你的應用id填到這裡
# 應用私鑰
alipay.privateKey=把你的應用私鑰填到這裡
# 支付寶公鑰,注意不是生成的應用公鑰
alipay.publicKey=把你的支付寶公鑰填到這裡
#支付閘道器配置,這一項是寫死的,正式環境是openapi.alipay.com
alipay.gateway=openapi.alipaydev.com
# 支付寶前臺跳轉地址
alipay.returnUrl=生成的外網穿透連結/return_url.html
# 支付寶後臺通知地址
alipay.notifyUrl=生成的外網穿透連結/api/alipay/notify_url
# 支付寶前臺手機網頁支付中途取消跳轉地址
alipay.errorUrl=生成的外網穿透連結/error_url.html

config/AlipayConfig.java

/**
 * @author zhangzhixi
 * @version 1.0
 * @date 2021-8-19 15:02
 */
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

@Component
public class AlipayConfig implements ApplicationRunner {

    // 應用id
    @Value("${alipay.appId}")
    private String appId;

    // 私鑰
    @Value("${alipay.privateKey}")
    private String privateKey;

    // 公鑰
    @Value("${alipay.publicKey}")
    private String publicKey;

    // 支付寶閘道器
    @Value("${alipay.gateway}")
    private String gateway;

    // 支付成功後的介面回撥地址,不是回撥的友好頁面,不要弄混了
    @Value("${alipay.notifyUrl}")
    private String notifyUrl;

    /**
     *  專案初始化事件
     * */
    @Override
    public void run(ApplicationArguments args) throws Exception {
        //初始化支付寶SDK
        Factory.setOptions(getOptions());
        System.out.println("**********支付寶SDK初始化完成**********");
    }

    private Config getOptions() {
        //這裡省略了一些不必要的配置,可參考文件的說明

        Config config = new Config();
        config.protocol = "https";
        config.gatewayHost = this.gateway;
        config.signType = "RSA2";

        config.appId = this.appId;

        // 為避免私鑰隨原始碼洩露,推薦從檔案中讀取私鑰字串而不是寫入原始碼中
        config.merchantPrivateKey = this.privateKey;

        // 注:如果採用非證書模式,則無需賦值上面的三個證書路徑,改為賦值如下的支付寶公鑰字串即可
        config.alipayPublicKey = this.publicKey;

        // 可設定非同步通知接收服務地址(可選)
        config.notifyUrl = notifyUrl;

        return config;
    }

}
View Code

controller/AlipayController.java

/**
 * @author zhangzhixi
 * @version 1.0
 * @date 2021-8-19 15:06
 */

import com.alipay.easysdk.factory.Factory;
import com.zhixi.aliyunpay.service.AlipayService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequestMapping("/api/alipay")
public class AlipayController {

    private final AlipayService alipayService;

    @Autowired
    public AlipayController(AlipayService alipayService) {
        this.alipayService = alipayService;
    }

    /**
     * 支付寶電腦網頁支付
     * @param subject: 訂單名稱
     * @param total:   金額
     * @return java.lang.String
     */
    @PostMapping("/page")
    public String page(String subject, String total) {
        subject = "測試支付";
        total = "1000";

        return alipayService.page(subject, total);
    }

    /**
     * 支付寶手機網頁支付
     * @param subject: 訂單名稱
     * @param total:   金額
     * @return java.lang.String
     */
    @PostMapping("/wap")
    public String wap(String subject, String total) {
        subject = "測試支付";
        total = "1000";

        return alipayService.wap(subject, total);
    }

    /**
     * @param request: 請求
     * @return java.lang.String
     * @description: 支付寶非同步回撥
     * @date: 2020/11/3
     */
    @PostMapping("/notify_url")
    public String notify_url(HttpServletRequest request) throws Exception {

        if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
            System.out.println("=========支付寶非同步回撥========");

            Map<String, String> params = new HashMap<>();
            Map<String, String[]> requestParams = request.getParameterMap();
            for (String name : requestParams.keySet()) {
                params.put(name, request.getParameter(name));
                // System.out.println(name + " = " + request.getParameter(name));
            }

            // 支付寶驗籤
            if (Factory.Payment.Common().verifyNotify(params)) {
                // 驗籤通過
                System.out.println("交易名稱: " + params.get("subject"));
                System.out.println("交易狀態: " + params.get("trade_status"));
                System.out.println("支付寶交易憑證號: " + params.get("trade_no"));
                System.out.println("商戶訂單號: " + params.get("out_trade_no"));
                System.out.println("交易金額: " + params.get("total_amount"));
                System.out.println("買家在支付寶唯一id: " + params.get("buyer_id"));
                System.out.println("買家付款時間: " + params.get("gmt_payment"));
                System.out.println("買家付款金額: " + params.get("buyer_pay_amount"));
            }
        }

        return "success";
    }

    /**
     * @param outTradeNo:   商家訂單號
     * @param refundAmount: 退款金額(不能大於交易金額)
     * @return java.lang.String
     * @description: 支付寶退款
     * @date: 2020/11/3
     */
    @PostMapping("/refund")
    public String refund(String outTradeNo, String refundAmount) {
        return alipayService.refund(outTradeNo, refundAmount);
    }

}
View Code

service/AlipayService.java

/**
 * @author zhangzhixi
 * @version 1.0
 * @date 2021-8-19 15:04
 */
public interface AlipayService {

    /**
     * @description: 支付寶電腦網頁支付
     * @param subject: 訂單名稱
     * @param total: 金額
     * @date: 2020/11/3
     * @return java.lang.String
     */
    String page(String subject, String total);

    /**
     * @description: 支付寶手機網頁支付
     * @param subject: 訂單名稱
     * @param total: 金額
     * @date: 2020/11/3
     * @return java.lang.String
     */
    String wap(String subject, String total);

    /**
     * @description: 支付寶退款
     * @param outTradeNo: 商家訂單號
     * @param refundAmount: 退款金額(不能大於交易金額)
     * @date: 2020/11/3
     * @return java.lang.String
     */
    String refund(String outTradeNo, String refundAmount);
}
View Code

service/impl/AlipayService.java

/**
 * @author zhangzhixi
 * @version 1.0
 * @date 2021-8-19 15:04
 */

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.alipay.easysdk.payment.wap.models.AlipayTradeWapPayResponse;
import com.zhixi.aliyunpay.service.AlipayService;
import com.zhixi.aliyunpay.util.OrderUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class AlipayServiceImpl implements AlipayService {

    // 支付成功後要跳轉的頁面
    @Value("${alipay.returnUrl}")
    private String returnUrl;

    // 支付寶前臺手機網頁支付中途取消跳轉地址
    @Value("${alipay.errorUrl}")
    private String errorUrl;

    @Override
    public String page(String subject, String total) {

        try {
            AlipayTradePagePayResponse response = Factory.Payment
                    // 選擇電腦網站
                    .Page()
                    // 呼叫支付方法(訂單名稱, 商家訂單號, 金額, 成功頁面)
                    .pay(subject, OrderUtil.getOrderNo(), total, returnUrl);

            return response.body;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public String wap(String subject, String total) {

        try {
            AlipayTradeWapPayResponse response = Factory.Payment
                    //選擇手機網站
                    .Wap()
                    // 呼叫支付方法(訂單名稱, 商家訂單號, 金額, 中途退出頁面, 成功頁面)
                    .pay(subject, OrderUtil.getOrderNo(), total, errorUrl, returnUrl);

            return response.body;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public String refund(String outTradeNo, String refundAmount) {
        try {
            AlipayTradeRefundResponse response = Factory.Payment
                    .Common()
                    // 呼叫交易退款(商家訂單號, 退款金額)
                    .refund(outTradeNo, refundAmount);

            if (response.getMsg().equals("Success")) {
                return "退款成功";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return "退款失敗";
    }
}
View Code

util/OrderUtil.java

/**
 * @author zhangzhixi
 * @version 1.0
 * @date 2021-8-19 15:03
 */

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class OrderUtil {

    /**
     * 根據時間戳生成訂單號
     */
    public static String getOrderNo() {
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS");
        LocalDateTime localDateTime = Instant.ofEpochMilli(System.currentTimeMillis()).atZone(ZoneOffset.ofHours(8)).toLocalDateTime();
        return df.format(localDateTime);
    }
}
View Code

html頁面:

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>測試支付</title>
</head>
<body>
<div>
    <h2>測試支付</h2>
    <form enctype="multipart/form-data" action="/api/alipay/page" method="post">
        <button type="submit">電腦確認支付</button>
    </form>
    <form enctype="multipart/form-data" action="/api/alipay/wap" method="post">
        <button type="submit">手機確認支付</button>
    </form>
</div>
</body>
</html>
View Code

return_url.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>支付成功</title>
</head>
<body>
<div>
    <h2>支付成功</h2>

    <a href="http://78ff7c27cdb6.ngrok.io/return_url.html">主頁</a>
    <a href="index.html">主頁</a>
</div>
</body>
</html>
View Code

error_url.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>支付失敗</title>
</head>
<body>
<div>
    <h2>支付失敗</h2>
</div>
</body>
</html>
View Code

三、測試

電腦測試訪問:

手機測試訪問: