SpringBoot3简单粗暴接入阿里支付宝接口

1 获取支付接入配置

支付宝沙箱地址

参数名称描述
app_id应用ID
商户私钥对应应用私钥
支付宝公钥对应支付宝公钥
服务器异步通知页面路径需http://格式的完整路径,须外网可访问
页面跳转同步通知页面路径需http://格式的完整路径须外网可访问
签名方式RSA2
字符编码格式utf-8
签名方式RSA2
支付宝网关https://openapi-sandbox.dl.alipaydev.com/gateway.do

2 引入依赖

springBoot版本 3.1.5 
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.1.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>myDreams</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>myDreams</name>
    <description>myDreams</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-logging</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- Druid 连接池引入 -->
        <!-- SpringBoot3 -->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid-spring-boot-3-starter -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-3-starter</artifactId>
            <version>1.2.18</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>

        <!--添加支付宝依赖-->

        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.10.124.ALL</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3 编写配置类

编写配置文件

#应用ID 这里用的沙箱模式
pay.app_id = 
#商户私钥,您的PKCS8格式RSA2私钥
pay.merchant_private_key=应用私钥
#支付宝公钥 公钥模式查看最底部
pay.alipay_public_key =
#服务器异步通知页面路径 需http://格式的完整路径,必须外网可以正常访问
pay.notify_url =http://ip/asyncNotify.html
#页面跳转同步通知页面路径 需http://格式的完整路径,必须外网可以正常访问
pay.return_url = http://ip/notify.html
#签名方式
pay.sign_type =RSA2
#字符编码格式
pay.charset = utf-8
#支付宝网关,注意这些使用的是沙箱的支付宝网关
pay.gatewayUrl =https://openapi-sandbox.dl.alipaydev.com/gateway.do

编写配置对象

package com.example.mydreams.util;

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

/**
 * 支付宝通用配置累
 */

@Data
@ToString
@Component
@PropertySource("classpath:applyPay.properties") // 加载自定义配置文件
@ConfigurationProperties(prefix="pay") // 配置属性,设置前缀
public class PayUtil {
    // 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
    public  String app_id;
    // 商户私钥,您的PKCS8格式RSA2私钥
    public  String merchant_private_key;
    // 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。
    public  String alipay_public_key;
    // 服务器异步通知页面路径
    //需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public  String notify_url;
    // 页面跳转同步通知页面路径
    //需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public  String return_url;
    // 签名方式
    public  String sign_type;
    // 字符编码格式
    public  String charset;
    // 支付宝网关,注意这些使用的是沙箱的支付宝网关,与正常网关的区别是多了dev
    public  String gatewayUrl;


    /**
     * 初始化支付宝客户端对象
     * @return AlipayClient
     */
    @Bean
    public AlipayClient alipayClient(){
        return new DefaultAlipayClient(gatewayUrl,app_id,merchant_private_key,"json",charset,
                alipay_public_key,sign_type);
    }
    //创建一个支付宝的请求对象
    @Bean
    public AlipayTradePagePayRequest alipayTradePagePayRequest(){
        return new AlipayTradePagePayRequest();
    }
}

4 编写最简单的html付款页面

resources文件夹下创建static静态文件夹,创建编写index.html文件


<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>支付宝网站支付</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }

        ul, ol {
            list-style: none;
        }

        body {
            font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande",
            sans-serif;
        }

        .tab-head {
            margin-left: 120px;
            margin-bottom: 10px;
        }

        .tab-content {
            clear: left;
            display: none;
        }

        h2 {
            border-bottom: solid #02aaf1 2px;
            width: 200px;
            height: 25px;
            margin: 0;
            float: left;
            text-align: center;
            font-size: 16px;
        }

        .selected {
            color: #FFFFFF;
            background-color: #02aaf1;
        }

        .show {
            clear: left;
            display: block;
        }

        .hidden {
            display: none;
        }

        .new-btn-login-sp {
            padding: 1px;
            display: inline-block;
            width: 75%;
        }

        .new-btn-login {
            background-color: #02aaf1;
            color: #FFFFFF;
            font-weight: bold;
            border: none;
            width: 100%;
            height: 30px;
            border-radius: 5px;
            font-size: 16px;
        }

        #main {
            width: 100%;
            margin: 0 auto;
            font-size: 14px;
        }

        .red-star {
            color: #f00;
            width: 10px;
            display: inline-block;
        }

        .null-star {
            color: #fff;
        }

        .content {
            margin-top: 5px;
        }

        .content dt {
            width: 100px;
            display: inline-block;
            float: left;
            margin-left: 20px;
            color: #666;
            font-size: 13px;
            margin-top: 8px;
        }

        .content dd {
            margin-left: 120px;
            margin-bottom: 5px;
        }

        .content dd input {
            width: 85%;
            height: 28px;
            border: 0;
            -webkit-border-radius: 0;
            -webkit-appearance: none;
        }

        #foot {
            margin-top: 10px;
            position: absolute;
            bottom: 15px;
            width: 100%;
        }

        .foot-ul {
            width: 100%;
        }

        .foot-ul li {
            width: 100%;
            text-align: center;
            color: #666;
        }

        .note-help {
            color: #999999;
            font-size: 12px;
            line-height: 130%;
            margin-top: 5px;
            width: 100%;
            display: block;
        }

        #btn-dd {
            margin: 20px;
            text-align: center;
        }

        .foot-ul {
            width: 100%;
        }

        .one_line {
            display: block;
            height: 1px;
            border: 0;
            border-top: 1px solid #eeeeee;
            width: 100%;
            margin-left: 20px;
        }

        .am-header {
            display: -webkit-box;
            display: -ms-flexbox;
            display: box;
            width: 100%;
            position: relative;
            padding: 7px 0;
            -webkit-box-sizing: border-box;
            -ms-box-sizing: border-box;
            box-sizing: border-box;
            background: #1D222D;
            height: 50px;
            text-align: center;
            -webkit-box-pack: center;
            -ms-flex-pack: center;
            box-pack: center;
            -webkit-box-align: center;
            -ms-flex-align: center;
            box-align: center;
        }

        .am-header h1 {
            -webkit-box-flex: 1;
            -ms-flex: 1;
            box-flex: 1;
            line-height: 18px;
            text-align: center;
            font-size: 18px;
            font-weight: 300;
            color: #fff;
        }
    </style>
</head>
<body text=#000000 bgColor="#ffffff" leftMargin=0 topMargin=4>
<header class="am-header">
    <h1>支付宝体验入口页</h1>
</header>
<div id="main">
    <div id="tabhead" class="tab-head">
        <h2 id="tab1" class="selected" name="tab">付 款</h2>
    </div>
    <form name=alipayment action=pay method=post
          target="_blank">
        <div id="body1" class="show" name="divcontent">
            <dl class="content">
                <dt>商户订单号 :</dt>
                <dd>
                    <input id="WIDout_trade_no" name="WIDout_trade_no" />
                </dd>
                <hr class="one_line">
                <dt>订单名称 :</dt>
                <dd>
                    <input id="WIDsubject" name="WIDsubject" />
                </dd>
                <hr class="one_line">
                <dt>付款金额 :</dt>
                <dd>
                    <input id="WIDtotal_amount" name="WIDtotal_amount" />
                </dd>
                <hr class="one_line">
                <dt>商品描述:</dt>
                <dd>
                    <input id="WIDbody" name="WIDbody" />
                </dd>
                <hr class="one_line">
                <dt></dt>
                <dd id="btn-dd">
                                                <span class="new-btn-login-sp">
                                                        <button class="new-btn-login" type="submit"
                                                                style="text-align: center;">付 款</button>
                                                </span> <span class="note-help">如果您点击“付款”按钮,即表示您同意该次的执行操作。</span>
                </dd>
            </dl>
        </div>
    </form>

    <div id="foot">
        <ul class="foot-ul">
            <li>版权所有2022</li>
        </ul>
    </div>
</div>
</body>
<script language="javascript">
    function GetDateNow() {
        var vNow = new Date();
        var sNow = "";
        sNow += String(vNow.getFullYear());
        sNow += String(vNow.getMonth() + 1);
        sNow += String(vNow.getDate());
        sNow += String(vNow.getHours());
        sNow += String(vNow.getMinutes());
        sNow += String(vNow.getSeconds());
        sNow += String(vNow.getMilliseconds());
        document.getElementById("WIDout_trade_no").value =  sNow;
        document.getElementById("WIDsubject").value = "测试";
        document.getElementById("WIDtotal_amount").value = "0.01";
    }
    GetDateNow();
</script>
</html>

5 编写支付接口

页面的作用主要是向服务器发起付款请求,所以,我们要写一个付款请求接口,页面发的请求先走我们的接口,然后我们拼装参数请求支付宝。

package com.example.mydreams.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.example.mydreams.util.PayUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;
@Controller
public class PayController {
    @Resource
    private AlipayClient alipayClient;
    @Resource
    private AlipayTradePagePayRequest alipayTradePagePayRequest;
    @Resource
    PayUtil  payUtil;

    //处理支付请求
    //1.接收页面传过来的数据:订单号,金额,名称,商品描述  表单中的name值=参数名
    @RequestMapping("/pay")
    public void pay(String WIDout_trade_no, String WIDsubject, String WIDtotal_amount, String WIDbody, HttpServletResponse response)
            throws AlipayApiException, IOException {
        //2.获得支付的客户端AlipayClient,和配置支付信息的对象AlipayTradePagePayRequest
        //3.设置响应的地址(支付宝返回给商户的响应地址)
        alipayTradePagePayRequest.setNotifyUrl(payUtil.notify_url);
        alipayTradePagePayRequest.setReturnUrl(payUtil.return_url);
        //4.设置请求的参数(传递给支付宝的数据)
        alipayTradePagePayRequest.setBizContent(
                "{\"out_trade_no\":\""+ WIDout_trade_no +"\","
                        + "\"total_amount\":\""+ WIDtotal_amount +"\","
                        + "\"subject\":\""+ WIDsubject +"\","
                        + "\"body\":\""+ WIDbody +"\","
                        + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
        //5.发送请求
        String result = alipayClient.pageExecute(alipayTradePagePayRequest).getBody();
        //6.将响应结果返回给前端
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().println(result);
    }
}

6 添加同步通知接口

同步接口是用户完成支付后会自动跳转的地址

package com.example.mydreams.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.example.mydreams.util.PayUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
public class ReturnController {
    @Autowired
    PayUtil payUtil;
    @RequestMapping("/getreturn")
    public String getreturn(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException{
        //获取支付宝GET过来反馈信息
        Map<String,String> params = new HashMap<>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values =requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }

        //RSA2验证
        boolean signVerified = AlipaySignature.rsaCheckV2(params, payUtil.alipay_public_key, payUtil.charset, payUtil.sign_type); //调用SDK验证签名
        if(signVerified) {
            //商户订单号
            String out_trade_no = request.getParameter("out_trade_no");
            //支付宝交易号
            String trade_no = request.getParameter("trade_no");
            //付款金额
            String total_amount = request.getParameter("total_amount");
            return "沙箱支付宝付款成功,跳转同步通知接口:"+"trade_no:"+trade_no+"<br/>out_trade_no:"+out_trade_no+"<br/>total_amount:"+total_amount;
        }else {
            return "付款失败,验签失败!";
        }
    }
}

7 编写异步通知接口

异步接口,是用户完成支付之后,支付宝会回调来通知支付结果的地址。

package com.example.mydreams.controller;

import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.example.mydreams.util.PayUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Controller
public class NotifyController {
    private static final Logger logger = LogManager.getLogger(NotifyController.class);

    @Resource
    PayUtil payUtil;
    //接收支付宝返回的异步通知的信息
    @RequestMapping("/notify")
    public void getnotify(HttpServletRequest request,HttpServletResponse response) throws AlipayApiException, IOException {
        //支付宝POST过来反馈信息
        Map<String,String> params = new HashMap<>();
        Map<String,String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
            String[] values = requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i]
                        : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        boolean signVerified = AlipaySignature.rsaCheckV1(params, payUtil.alipay_public_key, payUtil.charset, payUtil.sign_type); //调用SDK验证签名
        /*
         * 实际验证过程建议商户务必添加以下校验:
         */
        if(signVerified) {//验证成功
            //商户订单号
            String out_trade_no =request.getParameter("out_trade_no");
            //支付宝交易号
            String trade_no = request.getParameter("trade_no");
            //交易状态
            String trade_status = request.getParameter("trade_status");
            if(trade_status.equals("TRADE_FINISHED")){
                //判断该笔订单是否在商户网站中已经做过处理
                logger.info("支付宝给了我提醒:商户订单号:"+out_trade_no+",支付宝交易号:"+trade_no+"trade_status:"+trade_status+",状态值:TRADE_FINISHED!");
            }else if (trade_status.equals("TRADE_SUCCESS")){
                //判断该笔订单是否在商户网站中已经做过处理
                logger.info("支付宝给了我提醒:商户订单号:"+out_trade_no+",支付宝交易号:"+trade_no+"trade_status:"+trade_status+",状态值:TRADE_SUCCESS!");
            }

        }else {
         logger.error("验证失败,无法获取支付宝提醒信息!!!");
        }

    }
}

8 试运行

先跑一下,能跳支付宝页面了,有点成就感了,干杯!此刻如果跳转错误,一定是参数配置问题了,可以在评论区提出你的疑问!
点击付款

点击付款
地址跳转到支付宝啦
此时已成功一半!

9 扫码付款

扫码下载安卓沙箱支付宝
在这里插入图片描述
沙箱支付宝登录账号密码,这里填写买家的,别搞混了!
在这里插入图片描述
这个时候登录沙箱支付宝,就可以扫码支付,查看效果了!

10 扩展 消息接入

消息服务接入简介
alipay.user.opencard.result.notify
会员卡开卡结果通知
alipay.marketing.activity.delivery.changed
变更推广计划消息
alipay.trade.refund.depositback.completed
收单退款冲退完成通知
alipay.marketing.activity.message.received
券领取通知
alipay.marketing.activity.message.modified
商家券活动修改通知
alipay.marketing.activity.message.stopped
商家券活动停止通知
alipay.marketing.activity.message.created
商家券活动创建通知
alipay.marketing.activity.message.appended
商家券活动预算追加通知
alipay.marketing.activity.message.used
券核销消息
ant.merchant.expand.shop.save.rejected
店铺保存拒绝消息

在这里插入图片描述

  • 11
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农佩奇

打酒喝!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值