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

# 前言

码云地址:https://gitee.com/chenbz2/zhifubao

支付宝出了新的SDK,网上大部分教程是旧版的SDK,都可以用,看你选择哪个。

教程都会让你设置return_url 和 notify_url 地址,首先要了解这两个的区别,return_url 是同步调用,是支付成功后自动跳转过去的,notify_url 是异步调用需要返回 success 给支付宝,return_url 支付宝通知是GET请求,notify_url 支付宝通知是POST。
参考: 异步通知参数说明、支付宝异步回调



# 前期准备

  1. app_id(应用ID)
  2. private_key(应用私钥)
  3. public_key(支付宝公钥)
  4. 内网穿透


# 获取 app_id

沙箱应用

springboot接入支付宝支付-新版SDK(2020/11/03)_第1张图片



# 获取 private_key

1、工具下载

springboot接入支付宝支付-新版SDK(2020/11/03)_第2张图片


2、打开工具

springboot接入支付宝支付-新版SDK(2020/11/03)_第3张图片
springboot接入支付宝支付-新版SDK(2020/11/03)_第4张图片



# 获取 public_key

1、复制应用公钥

springboot接入支付宝支付-新版SDK(2020/11/03)_第5张图片


2、打开 沙箱应用 设置支付宝公钥

springboot接入支付宝支付-新版SDK(2020/11/03)_第6张图片


3、选择加签模式(公钥)

springboot接入支付宝支付-新版SDK(2020/11/03)_第7张图片


4、粘贴应用公钥

springboot接入支付宝支付-新版SDK(2020/11/03)_第8张图片
springboot接入支付宝支付-新版SDK(2020/11/03)_第9张图片



# 内网穿透

1、下载 ngrok

下载可能有点慢,有条件的梯子下载


2、解压 ngrok


3、启动 ngrok

cd ngrok所在路径
ngrok http 8866

这行命令是把 8866 端口穿透出去,因为我们接下来要建的项目端口是 8866

springboot接入支付宝支付-新版SDK(2020/11/03)_第10张图片

这个网址就是我们穿透出去的外网访问链接,窗口不要关掉,保留着



# 开始开发

新建springboot项目,项目结构如下

springboot接入支付宝支付-新版SDK(2020/11/03)_第11张图片



# pox.xml

        
            com.alipay.sdk
            alipay-easysdk
            2.1.0
        


# application.properties

## 端口
server.port= 8866


## 支付宝配置
# 应用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


# AlipayConfig.class

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;
    }

}

支付宝参考文档



# OrderUtil.class

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);
    }
}


# AlipayService.interface

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);
}


# AlipayServiceImpl.class

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.chenbz.zhifubao.system.service.AlipayService;
import com.chenbz.zhifubao.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 "退款失败";
    }
}

API的详细参数说明
API的更加详细参数说明



# AlipayController.class

import com.alipay.easysdk.factory.Factory;
import com.chenbz.zhifubao.system.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;
    }

    /**
     * @description: 支付宝电脑网页支付
     * @param subject: 订单名称
     * @param total: 金额
     * @date: 2020/11/3
     * @return java.lang.String
     */
    @PostMapping("/page")
    public String page(String subject, String total) {
     
        subject = "测试支付";
        total = "1000";

       return alipayService.page(subject, total);
    }

    /**
     * @description: 支付宝手机网页支付
     * @param subject: 订单名称
     * @param total: 金额
     * @date: 2020/11/3
     * @return java.lang.String
     */
    @PostMapping("/wap")
    public String wap(String subject, String total) {
     
        subject = "测试支付";
        total = "1000";

        return alipayService.wap(subject, total);
    }

    /**
     * @description: 支付宝异步回调
     * @param request: 请求
     * @date: 2020/11/3
     * @return java.lang.String
     */
    @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";
    }

    /**
     * @description: 支付宝退款
     * @param outTradeNo: 商家订单号
     * @param refundAmount: 退款金额(不能大于交易金额)
     * @date: 2020/11/3
     * @return java.lang.String
     */
    @PostMapping("/refund")
    public String refund(String outTradeNo, String refundAmount) {
     
        return alipayService.refund(outTradeNo, refundAmount);
    }

}


# index.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>


# return_url.html


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

    <a href="外网穿透链接">主页a>
div>
body>
html>


# error_url.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>支付失败title>
head>
<body>
<div>
    <h2>支付失败h2>
div>
body>
html>


# 测试前期准备

1、下载沙箱app

springboot接入支付宝支付-新版SDK(2020/11/03)_第12张图片


2、获取沙箱账号

springboot接入支付宝支付-新版SDK(2020/11/03)_第13张图片



# 测试电脑支付

springboot接入支付宝支付-新版SDK(2020/11/03)_第14张图片

springboot接入支付宝支付-新版SDK(2020/11/03)_第15张图片



# 测试手机支付

springboot接入支付宝支付-新版SDK(2020/11/03)_第16张图片
springboot接入支付宝支付-新版SDK(2020/11/03)_第17张图片

springboot接入支付宝支付-新版SDK(2020/11/03)_第18张图片



# 参考博客

  1. Spring Boot集成支付宝(最新版SDK)—— H5/网页支付
  2. springboot接入支付宝app支付
  3. 支付宝支付接口之异步回调
  4. 支付宝支付后回调处理(Java版)

你可能感兴趣的:(spring,boot,java)