SpringBoot项目(支付宝整合)——springboot整合支付宝沙箱支付 & 从极简实现到IOC改进

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。SpringBoot项目(支付宝整合)——springboot整合支付宝沙箱支付 & 从极简实现到IOC改进,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

引出


1.springboot整合支付宝沙箱支付;
2.准备工作:沙箱api,内网穿透;
3.极简实现理解支付,异步回调等;
4.按照spring依赖注入的思想改造基础demo;

git代码仓库

https://gitee.com/pet365/springboot-alipay

准备工作

支付宝沙箱api

支付宝开放平台 (alipay.com)

在这里插入图片描述

支付参数

在这里插入图片描述

内网穿透 natapp.cn

natapp.cn官网

在这里插入图片描述

启动和配置

在这里插入图片描述

springboot整合—极简实现版

在这里插入图片描述

1.导包+配置文件

<!--        支付宝相关-->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.34.0.ALL</version>
        </dependency>
server:
  port: 9090


# 日志需要配置一下 @Slf4j
logging:
  level:
    com.tianju.alipay: debug

2.controller层代码

订单ID,需要唯一;价格;物品名称(支付主题)

http://localhost:9090/api/ali/pay?orderId=202307302321&price=12.56&subject=iPhone

用户名:flrnht7304@sandbox.com

密码:111111

AliPayController.java文件

package com.tianju.alipay.controller;


import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 支付宝的支付接口
 * 用户名:flrnht7304@sandbox.com
 * 密码:111111
 */

// http://localhost:9090/api/ali/pay?orderId=202307302321&price=12.56&subject=iPhone
@RestController
@RequestMapping("/api/ali")
@Slf4j // tips:如果用debug记得在application.yml文件中配置一下日志级别
public class AliPayController {


    String alipayPublicKey = "";

    @GetMapping("/pay")
    public void payOrder(String orderId, String price, String subject, HttpServletResponse httpResponse) throws AlipayApiException, IOException {
        // 1.准备需要的参数,私匙,支付公匙,appid,沙箱支付平台的url
        String privateKey = "";
        String alipayPublicKey = "";
        String appId = "9021000123613164";
        String serverUrl = "https://openapi-sandbox.dl.alipaydev.com/gateway.do";

        // 2.把需要配置的参数set进AlipayConfig类中
        com.alipay.api.AlipayConfig alipayConfig = new com.alipay.api.AlipayConfig();
        alipayConfig.setServerUrl(serverUrl);
        alipayConfig.setAppId(appId);
        alipayConfig.setPrivateKey(privateKey);
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        alipayConfig.setCharset("UTF8");
        alipayConfig.setSignType("RSA2");

        // 3.创建支付宝的默认的客户端
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);

        // 4.准备支付的参数,包括需要支付的订单的id,价格,物品名称,
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
//        model.setOutTradeNo("2023073022083620");
        model.setOutTradeNo(orderId); // 需要支付的订单id,自定义的订单id,不能重复,唯一,已经支付的无法继续支付
        model.setTotalAmount(price); // 需要支付的钱 model.setTotalAmount("88.88");
        model.setSubject(subject); // 要支付的物品,比如 model.setSubject("Iphone6 16G");
        model.setProductCode("FAST_INSTANT_TRADE_PAY");

        // 5.创建支付的请求,把上面的准备支付的参数进行set
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setBizModel(model);

        /**
         * 设置支付宝异步回调,这个需要用内网穿透
         */
        request.setNotifyUrl("http://uw7ayu.natappfree.cc/api/ali/notify");

        /**
         * 设置支付宝支付成功返回的页面
         * 这里让支付成功直接回到static下的一个静态页面中
         */
        request.setReturnUrl("http://localhost:9090/aliPayReturn.html");

        // 6.调用ali客户端alipayClient,用客户端执行请求,获取响应,获取.getBody(),拿到form表单
        // 执行请求,拿到响应的结果,返回给浏览器
        String form = "";
        try {
            form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
            log.debug(">>>>>>getAliPayFrom");
            System.out.println("getAliPayFrom");
            System.out.println(form);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        // 表单数据作为响应返回给前端,显示前端页面
        /**
         * <form name="punchout_form" method="post" action="https://openapi-sandbox.dl.alipaydev.com/gateway.do?charset=UTF8&method=alipay.trade.page.pay&sign=ZSYIysQXMlJK6q%2B%2BQVJVhKi3qtHBaXTMmh4%2Fi7Wcj1OuSr5Qs6X%2Fhq0jgDbR%2BFw6da3fO5Hov8iV8%2BPo07CVnIQDSL1X2WDZzSN3Srqid%2BLKP%2BnoME2Jv9AfhaPwYkbElg0x40pLspkCv7%2FeRs93ROkrvLUL0aTA%2B7wXrIe5FKkvptqfqjReMayVR1lKmiGw8SWToNJ0OQoDp4g6191vJIy9ld%2BQfRU6PLq9dUH3XIifNvCwOceMCqpOXNlJIAb8MC2FkXK%2FCwEij5mj%2BpqNEevMf0DRczuUklJe20FeXrx6bSsjEIly8Swt1j4UYZZJY817TRQp%2FG3XEOjnLfAH5g%3D%3D&version=1.0&app_id=9021000123613164&sign_type=RSA2&timestamp=2023-07-30+23%3A11%3A17&alipay_sdk=alipay-sdk-java-dynamicVersionNo&format=json">
         * <input type="hidden" name="biz_content" value="{&quot;out_trade_no&quot;:&quot;202307302206&quot;,&quot;product_code&quot;:&quot;FAST_INSTANT_TRADE_PAY&quot;,&quot;subject&quot;:&quot;iPhone&quot;,&quot;total_amount&quot;:&quot;12.56&quot;}">
         * <input type="submit" value="立即支付" style="display:none" >
         * </form>
         * <script>document.forms[0].submit();</script>
         */
        httpResponse.setContentType("text/html;charset=UTF-8"); // 设置头部
        httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

    /**
     * 支付宝异步回调
     * request.setNotifyUrl("");
     * http://localhost:9090/api/ali/notify
     * 上面这个网址用内网穿透代理一下
     * http://jqdxgm.natappfree.cc/api/ali/notify
     * 此时支付宝就能回调到这个页面
     */
    @PostMapping("/notify")
    public void aliPayNotify(HttpServletRequest request) throws AlipayApiException {
        log.debug(">>>>>>>支付宝异步回调");
        Map<String, String[]> parameterMap = request.getParameterMap();
        // [gmt_create, charset, gmt_payment, notify_time, subject, sign, buyer_id, invoice_amount, version, notify_id,
        // fund_bill_list, notify_type, out_trade_no, total_amount, trade_status, trade_no, auth_app_id, receipt_amount,
        // point_amount, buyer_pay_amount, app_id, sign_type, seller_id]
        Set<String> keySet = parameterMap.keySet(); // 获取http请求里面的所有键

        /**
         * paramsMap如下:
         * {gmt_create=2023-07-31 15:54:11, charset=UTF8,
         * gmt_payment=2023-07-31 15:54:26,
         * notify_time=2023-07-31 15:54:27,
         * sign=fsCABNzc5hax4mwwMULluDiEAT70Kqj77uTMcCgSi82AU6tP5LGbXucEvP7CbvjXrYo5g3hrz5xRQAwddE7qU9Qyrg0v3EnearJBcW4It6N+VNBQ7yfY/W79eKRSKspLBKHRa21RILjyRrmQYG4Cw8R7twP7y0lDCOE8j3rV6ZyGfhiQ7EXp49d6HpgcIT1NjgJjQYSyJFdgyqkzFljKRfbhwPFAtubsmd8IcJCU7XI3YosSKnDhQaCA6ec4dmQiWtvcTbOLNR/r2Sou7rCnI7s1lc8pKeEsuacWTZW2FVR7hdHoLZ/expaRQIt+dNzA86lwQxu3SRCQ9wNTPICv1A==,
         * buyer_id=2088722005286475, invoice_amount=12.56, version=1.0, notify_id=2023073101222155427086470500776505,
         * fund_bill_list=[{"amount":"12.56","fundChannel":"ALIPAYACCOUNT"}],
         * notify_type=trade_status_sync,
         * subject=iPhone, // 物品名称
         * out_trade_no=202307311553, // 进行支付的订单id,唯一,商家自定义,即支付时传入的 String orderId
         * total_amount=12.56, // 总价格
         * trade_status=TRADE_SUCCESS, // 支付状态
         * trade_no=2023073122001486470500697216, auth_app_id=9021000123613164,
         * receipt_amount=12.56, point_amount=0.00,
         * buyer_pay_amount=12.56, app_id=9021000123613164, sign_type=RSA2, seller_id=2088721005318559}
         */
        Map<String,String> paramsMap = new HashMap<>(); // 专门用来放置请求里面的参数
        for(String key : keySet){
            paramsMap.put(key, request.getParameter(key));
        }
        System.out.println("*************");
        System.out.println(paramsMap);

        // 验证签名
        String sign = paramsMap.get("sign");
        String contentV1 = AlipaySignature.getSignCheckContentV1(paramsMap);
        boolean rsa256CheckSignature = AlipaySignature.rsa256CheckContent(contentV1, sign, alipayPublicKey, "UTF-8");
        if (rsa256CheckSignature && "TRADE_SUCCESS".equals(paramsMap.get("trade_status"))){
            // 签名验证成功 并且 支付宝回调的状态是成功状态 TRADE_SUCCESS
            log.info("在{},买家{}进行订单{}的付款,交易名称{},付款金额{}",
                    paramsMap.get("gmt_payment"),paramsMap.get("buyer_id"),paramsMap.get("out_trade_no"),paramsMap.get("subject"),paramsMap.get("total_amount"));

            // 支付成功,修改数据库中该订单的状态
            // 比如:流程,根据订单ID查询出一条数据,修改该条订单的数据,或者只有支付成功,才给数据库里面新增一条数据
        }
    }
}

3.进行支付流程

在这里插入图片描述

支付密码输入

在这里插入图片描述

支付成功

在这里插入图片描述

4.支付成功回调

设置异步回调

在这里插入图片描述

启动内网穿透

在这里插入图片描述

设置地址

在这里插入图片描述

异步回调流程解析

在这里插入图片描述

支付宝支付成功跳转

在这里插入图片描述

跳转成功

在这里插入图片描述

依赖注入的改进

在这里插入图片描述

1.整体结构

在这里插入图片描述

2.pom.xml文件依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tianju.alipay</groupId>
    <artifactId>springboot-alipay</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--json工具-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.12</version>
        </dependency>


        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>

        <!--        支付宝相关-->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.34.0.ALL</version>
        </dependency>


    </dependencies>
</project>

3.配置文件

applicaiton.yml

server:
  port: 9090


# 日志需要配置一下 @Slf4j
logging:
  level:
    com.tianju.alipay: debug

alipay.properties

ali.privateKey = 
ali.alipayPublicKey = 
ali.appId = 9021000123613164
ali.serverUrl = https://openapi-sandbox.dl.alipaydev.com/gateway.do

ali.returnUrl = http://localhost:9090/aliPayReturn.html
ali.notifyUrl = http://uw7ayu.natappfree.cc/api/ali/notify

4.配置类,依赖注入

package com.tianju.alipay.config;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import lombok.Getter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

@Configuration
@PropertySource("classpath:config/alipay.properties")
@Getter
public class AlipayConfig {
    @Value("${ali.serverUrl}")
    private String serverUrl;
    @Value("${ali.appId}")

    private String appId;
    @Value("${ali.alipayPublicKey}")
    private String alipayPublicKey;

    @Value("${ali.privateKey}")
    private String privateKey;

    @Bean
    public AlipayClient alipayClient() throws AlipayApiException {
        // 2.把需要配置的参数set进AlipayConfig类中
        com.alipay.api.AlipayConfig alipayConfig = new com.alipay.api.AlipayConfig();
        alipayConfig.setServerUrl(serverUrl);
        alipayConfig.setAppId(appId);
        alipayConfig.setPrivateKey(privateKey);
        alipayConfig.setFormat("json");
        alipayConfig.setAlipayPublicKey(alipayPublicKey);
        alipayConfig.setCharset("UTF8");
        alipayConfig.setSignType("RSA2");
        return new DefaultAlipayClient(alipayConfig);
    }
}

5.支付商品id,价格,名称

package com.tianju.alipay.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Alipay {
    private String orderId; // 商家自定义的订单编号,唯一
    private String price; // 商品价格
    private String subject; // 支付主题
}

6.controller层进行支付和回调

package com.tianju.alipay.controller;


import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.domain.AlipayTradePagePayModel;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.tianju.alipay.entity.Alipay;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * 支付宝的支付接口
 * 用户名:flrnht7304@sandbox.com
 * 密码:111111
 */

// http://localhost:9090/api/ali/pay?orderId=202307302321&price=12.56&subject=iPhone
@RestController
@RequestMapping("/api/ali")
@Slf4j
public class AliPayController {

    @Autowired
    private AlipayClient alipayClient;

    @Value("${ali.alipayPublicKey}")
    private String alipayPublicKey;
    @Value("${ali.returnUrl}")
    private String returnUrl; // 支付成功返回的页面
    @Value("${ali.notifyUrl}")
    private String notifyUrl; // 支付宝支付成功异步回调的页面,需要内网穿透

    @GetMapping("/pay")
    public void payOrder(Alipay alipay, HttpServletResponse httpResponse) throws IOException {

        // 4.准备支付的参数,包括需要支付的订单的id,价格,物品名称,
        AlipayTradePagePayModel model = new AlipayTradePagePayModel();
        model.setOutTradeNo(alipay.getOrderId()); // 需要支付的订单id,自定义的订单id,不能重复,唯一,已经支付的无法继续支付
        model.setTotalAmount(alipay.getPrice()); // 需要支付的钱 model.setTotalAmount("88.88");
        model.setSubject(alipay.getSubject()); // 要支付的物品,比如 model.setSubject("Iphone6 16G");
        model.setProductCode("FAST_INSTANT_TRADE_PAY");

        // 5.创建支付的请求,把上面的准备支付的参数进行set
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setBizModel(model);

        /**
         * 设置支付宝异步回调,这个需要用内网穿透
         */
        request.setNotifyUrl(notifyUrl);

        /**
         * 设置支付宝支付成功返回的页面
         * 这里让支付成功直接回到static下的一个静态页面中
         */
        request.setReturnUrl(returnUrl);

        // 6.调用ali客户端alipayClient,用客户端执行请求,获取响应,获取.getBody(),拿到form表单
        // 执行请求,拿到响应的结果,返回给浏览器
        String form = "";
        try {
            form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单
            log.debug(">>>>>>getAliPayFrom");
            System.out.println("getAliPayFrom");
            System.out.println(form);
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }

        // 表单数据作为响应返回给前端,显示前端页面
        httpResponse.setContentType("text/html;charset=UTF-8"); // 设置头部
        httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

    /**
     * 支付宝异步回调
     * request.setNotifyUrl("");
     * http://localhost:9090/api/ali/notify
     * 上面这个网址用内网穿透代理一下
     * http://jqdxgm.natappfree.cc/api/ali/notify
     * 此时支付宝就能回调到这个页面
     */
    @PostMapping("/notify")
    public void aliPayNotify(HttpServletRequest request) throws AlipayApiException {
        log.debug(">>>>>>>支付宝异步回调");
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<String> keySet = parameterMap.keySet(); // 获取http请求里面的所有键

        /**
         * paramsMap如下:
         * {gmt_create=2023-07-31 15:54:11, charset=UTF8,
         * gmt_payment=2023-07-31 15:54:26,
         * notify_time=2023-07-31 15:54:27,
         * sign=fsCABNzc5hax4mwwMULluDiEAT70Kqj77uTMcCgSi82AU6tP5LGbXucEvP7CbvjXrYo5g3hrz5xRQAwddE7qU9Qyrg0v3EnearJBcW4It6N+VNBQ7yfY/W79eKRSKspLBKHRa21RILjyRrmQYG4Cw8R7twP7y0lDCOE8j3rV6ZyGfhiQ7EXp49d6HpgcIT1NjgJjQYSyJFdgyqkzFljKRfbhwPFAtubsmd8IcJCU7XI3YosSKnDhQaCA6ec4dmQiWtvcTbOLNR/r2Sou7rCnI7s1lc8pKeEsuacWTZW2FVR7hdHoLZ/expaRQIt+dNzA86lwQxu3SRCQ9wNTPICv1A==,
         * buyer_id=2088722005286475, invoice_amount=12.56, version=1.0, notify_id=2023073101222155427086470500776505,
         * fund_bill_list=[{"amount":"12.56","fundChannel":"ALIPAYACCOUNT"}],
         * notify_type=trade_status_sync,
         * subject=iPhone, // 物品名称
         * out_trade_no=202307311553, // 进行支付的订单id,唯一,商家自定义,即支付时传入的 String orderId
         * total_amount=12.56, // 总价格
         * trade_status=TRADE_SUCCESS, // 支付状态
         * trade_no=2023073122001486470500697216, auth_app_id=9021000123613164,
         * receipt_amount=12.56, point_amount=0.00,
         * buyer_pay_amount=12.56, app_id=9021000123613164, sign_type=RSA2, seller_id=2088721005318559}
         */
        Map<String,String> paramsMap = new HashMap<>(); // 专门用来放置请求里面的参数
        for(String key : keySet){
            paramsMap.put(key, request.getParameter(key));
        }
        System.out.println("*************");
        System.out.println(paramsMap);

        // 验证签名
        String sign = paramsMap.get("sign");
        String contentV1 = AlipaySignature.getSignCheckContentV1(paramsMap);
        boolean rsa256CheckSignature = AlipaySignature.rsa256CheckContent(contentV1, sign, alipayPublicKey, "UTF-8");
        if (rsa256CheckSignature && "TRADE_SUCCESS".equals(paramsMap.get("trade_status"))){
            // 签名验证成功 并且 支付宝回调的状态是成功状态 TRADE_SUCCESS
            log.info("在{},买家{}进行订单{}的付款,交易名称{},付款金额{}",
                    paramsMap.get("gmt_payment"),paramsMap.get("buyer_id"),paramsMap.get("out_trade_no"),paramsMap.get("subject"),paramsMap.get("total_amount"));

            // 支付成功,修改数据库中该订单的状态
            // 比如:流程,根据订单ID查询出一条数据,修改该条订单的数据,或者只有支付成功,才给数据库里面新增一条数据
        }
    }
}

7.主启动类

package com.tianju.alipay;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class AliPayApp {
    public static void main(String[] args) {
        SpringApplication.run(AliPayApp.class, args);

    }
}

总结

1.springboot整合支付宝沙箱支付;
2.准备工作:沙箱api,内网穿透;
3.极简实现理解支付,异步回调等;
4.按照spring依赖注入的思想改造基础demo;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/165068.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!