专栏名称: Java基基
一个苦练基本功的 Java 公众号,所以取名 Java 基基
目录
相关文章推荐
什么值得买  ·  2025闲鱼最全避坑指南(附省钱隐蔽玩法... ·  2 天前  
物道  ·  英国小众轻奢品牌LEOS ... ·  2 天前  
无时尚中文网  ·  又一美容巨头扑街 ... ·  5 天前  
51好读  ›  专栏  ›  Java基基

SpringBoot集成支付宝支付功能

Java基基  · 公众号  ·  · 2025-02-10 11:55

正文

👉 这是一个或许对你有用 的社群

🐱 一对一交流/面试小册/简历优化/求职解惑,欢迎加入 芋道快速开发平台 知识星球。 下面是星球提供的部分资料:

👉 这是一个或许对你有用的开源项目

国产 Star 破 10w+ 的开源项目,前端包括管理后台 + 微信小程序,后端支持单体和微服务架构。

功能涵盖 RBAC 权限、SaaS 多租户、数据权限、 商城 、支付、工作流、大屏报表、微信公众号、 ERP CRM AI 大模型 等等功能:

  • Boot 多模块架构:https://gitee.com/zhijiantianya/ruoyi-vue-pro
  • Cloud 微服务架构:https://gitee.com/zhijiantianya/yudao-cloud
  • 视频教程:https://doc.iocoder.cn
【国内首批】支持 JDK 17/21 + SpringBoot 3.3、JDK 8/11 + Spring Boot 2.7 双版本

来源:juejin.cn/post/
7346763303459635251


前置需求

支付宝沙箱配置

需要有支付宝沙箱:提供一个虚拟的支付环境,用于测验调试,点击这里进入沙箱环境:

https://openhome.alipay.com/platform/appDaily.htm

因为是沙箱默认的密钥即可,这其中我们需要如下数据

  • 支付宝的公钥和私钥
  • 支付的网关
  • 支付的APPID
  • 支付宝sdk

内网穿透

系统启动只是在本地,如何让不同ip都能访问呢?内网穿透

内网穿透是一种技术手段,它允许外部网络的用户访问内部网络中的设备或服务。这项技术通常用于远程访问、建站、调试和游戏联机等场景,使得本地开发或维护的工作可以不受地理位置的限制。

为什么需要内网穿透呢?因为本质上调用人家的服务,当请求以后,支付宝需要返回给你信息,这就需要你的地址。这样才能找到我们的接口,我们才能根据他返回的信息做出一些业务处理。

免费即可,第一次需要实名认证

设置免费隧道,

我的隧道进行查询 以下红框中的码需要用到,

下载pc端app,解压出来,只有一个exe文件

这里68cvzs地址就是我本地映射到公网上的地址。

可以启动本地的9090服务,使用公网地址进行测试,试一试能不能访问成功

成功,则内网穿透成功。

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro
  • 视频教程:https://doc.iocoder.cn/video/

具体开发

sdk

<dependency>
<groupId>com.alipay.sdkgroupId>
<artifactId>alipay-sdk-javaartifactId>
<version>4.9.28.ALLversion>
dependency>

配置

相当于设置收钱的人是谁

server:
        port: 9090

        alipay:
        # appid
        appId: 9021000135634074
        # 应用私钥
        appPrivateKey: MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8bdoXTGIiXXkt/FBg0LPoOSvQANWo4wIYKVSjodGa60y+7Dk9d6DavrcWR7xrBYaJcSt9jr35rYGZQsXLuYJya0X1bkuiE4C1B26jrTdvPMu2UXlo9dQM2XdwuAb7ohkgMdp0jkMYag2IbtfjRFv0h+jnlUNfAZjJyQ8l7TePqFnJ8S94L9jVloYIRoeoJG3vj701HJ4IccEEFzpiNoznJnw33elr9Zu5K1gZqvQxp61D2pbMJ0daiof94uh3J0XwqeyB8HNbGlZj3OIyZMibU1AZfIpE2+cYVSGYt7+JawayNybhuTlb540OZGRjFGS7KCysqvEqIH6KbHqZJpwpAgMBAAECggEAVmPLDMmBaJ4Qc+vtciXdhgfINYpcax0BFdDFNGx5bBybSCGHsM3LGt87k+R511tmLleLh/pM0U8iTwEVLG02CH10Sq0x0fI9HUJ2EGbXNpHaGBHMpzml6eo+X5iP4wiTmnYg4TVkP6pH4BhptJHf0wII3zxI8iMKSOF8p3fV9G+Ay8i4zTmJtnzTopMshmH0IjemGBsImVLPjlrGNtt28ibarFNu+y8zq82H8ZKW9Gf2aokU3juml7ztIeVuEJEJGZo9D7hv+IwjCUr4q273pNSVE/RW0Nyi2moHmlaJzvSBY9iGPegmZDZAdG2pTUvfbj7KMUHUpTATSXkOwUg8AQKBgQD7zyspR0V9XAlWIYVNNu9aNgtN6lpYtG0MlQYAREsWF9/HCRgghnSE5/TfvKtDsdk2E2nw6WTp9D9ATPFf5TXTWNCcQp2bhiZttFgr4ii+inFpOf8zNJKovuLEa8SB9ImvPQXF7H1pbvWMnDoFtVTbmtiL7RtfOYK/GaK3I3Z2gQKBgQC/kKcXdieMY0jA6Ho6+5W5LmwBWiuhp/8S+o29494JzLr9cG074q69jaXHBNaEMgLfn3oM9Te2SzaPf8dEIzmfjmOJOrfzz8WOI9vWfW14u9ev6h52p21CjKCVsaxcjle9rXWoO4L8UfPpvjA3gz+/KLFdjyz16ctIeKqLWkvhqQKBgQCxcklBGnduorf1mUOdqRO8p48JxhcKoYKjNjT3ZSjglcxdLxxwdy+PJQJb1FGAL8kYoU+rtF0nvLYB8va5lAV9PP4sz4jPOxbDgi4MJqB9vYO0GmmrROYAwht9PVBKH/ASrFbwJfounUGuZ70/nowBATqOSHVcgmOPlVoj4nqtgQKBgBJdgNdr+XCpGBF+eDFtazY8sBgVF/fAjmC4apxY2zGfUhH4FFDYc54ylUEWQqab0NC1jlLts3Cjl1B8lJMAuYaFdR9z5KzYL31oDKxsi/E2OQBhdpgzhvMJXl/bj8Wz08+YcJ43TmB4TuUK2b6Is7TU5uQsVMgiqN2Cy/7eIkY5AoGANDCwDwrSTsHPzmrdL+8ACgWNv7KIj81mjSRIxGQrYYwuxMUAKWRBzEPcgFj3c6KfbyR/PxH+4jf8weYUIMZqY16pjmTUPs1Ba2UX0C2DSIcZeF7SRTrRX3CT0e5ycRBXu1EoqGPmtmO1YFnObTsGY+ZwMUKIFSS1ip2IkPaDyvA=
        # 支付宝公钥
        alipayPublicKey: MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx8Z31UrIoS1tL3f0VVqia8tlUze7RFnEVi3VbwOzC3RV9tt/crZaR+B21DrWkzjCw36tfrlL2WKYW4dWE/4KKwBY+TB67dZmIUShLf65imxysrB5woofe00uXv5GRYNVEgF+XAyUl3lVO5CHCwr2TGnBdOFOBJzvjmBViwEXHFLqECc4UqqnxvrP0AjMggwExktBEba3Z+i14o1jNznntf52FR2A/RGXiuj9FZHXTOlsc0FHodA3uO5V7WCwMlb7QI0HUm4UvTgPziLv6L3Gee2925Mu5t3NXQuRSVrOVh/W2xUCdwoPVeXd6mNh5v25qrR8TsKbmuO556haJbbCTQIDAQAB
        # 回调接口,支付宝通过什么接口通知你,这里就是填写具体接口地址,我们使用公网的地址以及接口uri /公网地址/uri
        notifyUrl: http://v6tqyw.natappfree.cc/alipay/notify
/**
 * 读取yml中的配置信息,自动填充到对应的属性
 */

@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
    private String appId;
    private String appPrivateKey;
    private String alipayPublicKey;
    private String notifyUrl;

}

具体支付

步骤

  • 必须传递如下参数(支付订单号(必须唯一), 订单名称,订单金额)
  • 创建支付客户端 设定appid 公钥密钥等等信息,用于知道这个订单谁发出的,钱给到谁的账户
  • 将请求的订单号等等写入支付的请求对象中 并且请求对象设置回调接口以及支付后的接口
  • 支付客户端对象根据支付请求对象去执行,调用支付宝API
  • 这个API接口会返回一个表单页面,让用户去输入帐号密码(也就是谁来支付),成功显示金额等等信息,填写支付密码进行转账
  • 转账以后无论成功与否,支付宝都会调用你的回调接口,传入数据

代码实现

业务参数代码

/**
 * 支付宝支付请求对象 所需要的参数
 */

@Data
public class PayVO {
    private String out_trade_no; // 商户订单号 必填
    private String subject; // 订单名称 必填
    private BigDecimal total_amount; // 付款金额 必填
    private String body; // 商品描述 可空
}

支付宝客户端执行

@RestController
@RequestMapping("/alipay")
@Transactional(rollbackFor = Exception.class)
public class AliPayController 
{

    @Resource
    AliPayConfig aliPayConfig;

    @Resource
    private ShopOrderDao shopOrderMapper;
    private static final String GATEWAY_URL = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";
    private static final String FORMAT = "JSON";
    private static final String CHARSET = "utf-8";
    private static final String SIGN_TYPE = "RSA2";

    /**
     * 支付接口 传入业务参数
     * 支付是一个我向你要钱的过程,设置api参数就是为了,知道收钱的人是谁,
     * 当执行以后支付宝会返回一个登录页面,支付的人输入帐号密码。并且确定金额输入支付密码进行支付
     * @param aliPay
     * @param httpResponse
     * @throws Exception
     */

    // 这里使用Get其实不是很恰当,应该使用post,这里为了调试方便使用Get
    @GetMapping("/pay")
    public void pay(PayVO aliPay, HttpServletResponse httpResponse) throws Exception {
        // 1、根据支付宝的配置生成一个支付客户端 客户端用于去调用支付宝的API
        // 官方写法
        AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
                aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);


        // 2、创建一个支付请求对象
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        // 设置回调接口
        request.setNotifyUrl(aliPayConfig.getNotifyUrl());
        // 商户订单号,商户网站订单系统中唯一订单号,必填,支付宝不允许有两个相同的订单号
        // 使用uuid生成 避免重复
        aliPay.setOut_trade_no(UUID.randomUUID().toString());
        String out_trade_no = aliPay.getOut_trade_no();
        // 付款金额,必填
        BigDecimal total_amount = aliPay.getTotal_amount();
        // 订单名称,必填
        String subject = aliPay.getSubject();
        // 商品描述,可空
        String body = aliPay.getBody();
        // 设置 业务参数 是一个json对象
        // 这个json对象 支付宝后台回去识别,根据这些参数进行处理,例如 金额,订单名称,商品描述
        request.setBizContent("{"out_trade_no":"" + out_trade_no + "","
                + ""total_amount":"" + total_amount + "","
                + ""subject":"" + subject + "","""body":""+ body +"","
                + ""product_code":"FAST_INSTANT_TRADE_PAY"}");
        // 支付完以后跳转的地址
        request.setReturnUrl("http://loaclhost:9090/hello/pay");

        // 3. 客户端执行请求
        // 客户端执行请求,拿到响应的结果,返回给浏览器
        String form = "";
        try {
            // 调用阿里的SDK生成表单
            // 会收到支付宝的响应,响应的是一个页面,一开始是登陆,然后显示金额,让用户输入密码进行付款
            form = alipayClient.pageExecute(request).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        httpResponse.setContentType("text/html;charset=" + CHARSET);
        // 直接将完整的表单html输出到页面
        httpResponse.getWriter().write(form);
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

效果

输入如下地址

http://localhost:9090/alipay/pay?subject=测试商品&total_amount=1000

支付宝返回页面

输入帐号密码(沙箱有测试的密码)

输入支付密码支付

回调接口

以下是支付宝返回给我们的信息

"gmt_create" -> "2024-03-16 22:40:26"
        "charset" -> "utf-8"
        "gmt_payment" -> "2024-03-16 22:40:30"
        "notify_time" -> "2024-03-16 22:40:31"
        "subject" -> "测试商品"
        "sign" -> "XfBcgT1lIYpxYm0DzaBtLz7WjzxHxhBK4gUdmDCtD/JTAwhohqu"
        "buyer_id" -> "2088722031942622"
        "body" -> "null"
        "invoice_amount" -> "1000.00"
        "version" -> "1.0"
        "notify_id" -> "2024031601222224031142620502419"
        "fund_bill_list" -> "[{"amount":"1000.00","fundChannel":"ALIPAYACCOUNT"}]"
        "notify_type" -> "trade_status_sync"
        "out_trade_no" -> "96b14931-b0a7-49bb-aa93-498432247a4"
        "total_amount" -> "1000.00"
        "trade_status" -> "TRADE_SUCCESS"
        "trade_no" -> "20240316220014426205023040"
        "auth_app_id" -> "9021000135634074"
        "receipt_amount" -> "1000.00"
        "point_amount" -> "0.00"
        "buyer_pay_amount" -> "1000.00"






请到「今天看啥」查看全文