支付宝沙箱环境 支付

一 什么是沙箱:

沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境

支付宝正式和沙箱环境的区别 :

AI:

  • 从沙箱到正式环境

  • 当应用程序开发完成后,需要将应用程序从沙箱环境迁移到正式环境。

  • 这通常涉及到更新应用程序中的配置文件,更换正式的 AppID 和密钥等凭证

二 注册使用

网址:++登录 - 支付宝++ 点击 进行注册

查看信息:appid

点击查看 应用密钥与支付宝公钥 :appPrivateKey 与 publiceKey

​ 记录一下卖家信息:

三 实现

支付实现的步骤:1.导入依赖 2.配置参数 3.调用方法(API调用) 4.处理响应或异常

具体实现可查看官网文档: 小程序文档 - 支付宝文档中心

小程序文档 - 支付宝文档中心

简易版概述小程序文档 - 支付宝文档中心

小程序文档 - 支付宝文档中心

​​​查看api使用规范 根据需求选择对应的接口方法

比如下面我们要实现的电脑网站的支付功能

对应的就是 Factory.Payment.Page.pay()

Easy 版

有拦截器的 注意放开路径

3.1 导入项目依赖

XML 复制代码
<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk -->
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-easysdk</artifactId>
    <version>2.2.0</version>
</dependency>

3.2 编写配置信息:

其中关于//@PostConstruct 是一个 Java 注解,用于标记需要在依赖注入完成后执行的方法。它表示该方法应该在对象创建和属性注入完毕后由容器自动调用,以完成初始化工作。

java 复制代码
@Component
@ConfigurationProperties(prefix = "alipay")
@Data
	public class AlipayConfig {
    // 应用Id
    private String appId;
    // 应用私钥
    private String appPrivateKey;
    // 支付宝公钥
    private String publiceKey;
    // 回调接口路径
    private String notifyUrl;
    // 支付宝网关地址
    private String gatewayHost;
    @PostConstruct
    //@PostConstruct 是一个 Java 注解,用于标记需要在依赖注入完成后执行的方法。
    // 它表示该方法应该在对象创建和属性注入完毕后由容器自动调用,以完成初始化工作。
    // 此注解的方法无参数,返回类型可为空或其他类型。主要用于确保对象完全初始化。
    public void init(){
        Config config = new Config();
        // 基础配置
        config.protocol = "https";
        config.gatewayHost = this.gatewayHost;// 支付宝网关地址
        config.signType = "RSA2";

        // 业务配置
        config.appId = this.appId;
        config.merchantPrivateKey = this.appPrivateKey;
        config.alipayPublicKey = this.publiceKey;
        config.notifyUrl = this.notifyUrl;

        // 将配置信息, 添加到相应的工厂类
        Factory.setOptions(config);
        System.out.println("支付宝初始化配置完成");
    }
}

application.properties

其中 appid appPrivateKey publiceKey 在开发者平台获取

gatewayHost 大家都一样 无需更改

notifyUrl 是内网穿透这里使用不到 现在随便写都可以

Groovy 复制代码
alipay.appid=9021000139682312
alipay.appPrivateKey=MIIEvwIBADANBgkqhkiG9w0BAQEFAAS...
alipay.publiceKey=MIIBIjANBgkqhkiG9w0BAQEFAAOC.......
alipay.notifyUrl=http://xxxxxxx/api/alipay/notify
alipay.gatewayHost=openapi-sandbox.dl.alipaydev.com

3.3 调用支付方法

我这里直接在cotroller层编写

java 复制代码
@RestController
@RequestMapping("/api/alipay")
public class PayController {

    /**
     * 订单支付接口, 核心是调用支付宝的 Factory.Payment.Page().pay() 方法
     * @param subject  支付对象信息
     * @param outTradeNo  订单号
     * @param totalAmount 订单金额
     * @param returnUrl   支付成功以后返回的页面地址
     * @return
     */

    @GetMapping("/pay")
    public void pay(String subject, String outTradeNo, String totalAmount, String returnUrl, HttpServletResponse httpResponse) throws Exception {
        // 使用支付宝支付页面接口进行支付
        AlipayTradePagePayResponse response = Factory.Payment.Page().pay(subject, outTradeNo, totalAmount, returnUrl);
        System.out.println(response);
        // response.getBody();
        // 设置HTTP响应内容类型为HTML,编码为UTF-8
         httpResponse.setContentType("text/html;charset=utf-8");
        // 向HTTP响应写入支付宝支付页面接口返回的响应体
        httpResponse.getWriter().write(response.getBody());
        // 刷新HTTP响应输出流,确保数据立即发送到客户端
        httpResponse.getWriter().flush();
        // 关闭HTTP响应输出流,释放资源
        httpResponse.getWriter().close();
    }

}

Java

可以进行测试后端了!!!!!!!!

可以进行测试后端了!!!!!!!!

可以进行测试后端了!!!!!!!!

http://localhost:8080/api/alipay/pay?subject=%E7%81%AB%E8%BD%A6%E7%A5%A8%E6%94%AF%E4%BB%98&outTradeNo=63172637&totalAmount=16.8&returnUrl=http%3A%2F%2Flocalhost%3A8080%2Fpayok.html%3ForderId%3D312323

3.4 回调方法 配合内网穿透使用

回调就是支付宝在进行扣款操作之后 调用我们的后端 告诉我们支付结果

回调方法如下:

回调中有个验证操作来源于:调用官方给我们提供的方法来验证数据的真实性。

java 复制代码
    @PostMapping("/notify")
    public String notify(@RequestParam Map parameterMap) throws Exception {
        String tradeStatus = parameterMap.getOrDefault("trade_status","").toString();
        if (tradeStatus.trim().equals("TRADE_SUCCESS")) {
            // 验证请求的有效性
            if (Factory.Payment.Common().verifyNotify(parameterMap)) {
                System.out.println("通过支付宝的验证");
                System.out.println("订单id:" + parameterMap.get("out_trade_no"));
            }else {
                System.out.println("支付验证不通过");
            }
        }
        return "success";
    }

需要先开启内网穿透

服务器为localhost:8080 支付宝无法调用:

注意:如果是部署云服务器就不需要内网穿透了 只不过需要我我们对回调的参数进行相对应的修改!!!!

3.5 内网穿透工具

1.路由侠-局域网变公网

​ 设置 信息 主机号

查看内网映射:

测试: 说明映射是没有问题的 成功调用了后端

修改 alipay.notifyUrl 的 配置信息

alipay.notifyUrl=http://xxxk.w1.luyouxia.net/api/alipay/notify

再次进行支付测试:s

这里加上vue进行测试:

前端 vue:

3.6 前端

javascript 复制代码
<template>
  <h2>支付</h2>
  <el-form :inline="true" :model="form" class="demo-form-inline">
    <el-form-item label="支付对象信息">
      <el-input v-model="form.subject" placeholder="请输入" clearable />
    </el-form-item>
    <el-form-item label="订单号">
      <el-input v-model="form.outTradeNo" placeholder="请输入" clearable />
    </el-form-item>
    <el-form-item label="订单金额">
      <el-input-number v-model="form.totalAmount" placeholder="请输入" clearable />
    </el-form-item>
    <el-form-item label="支付成功以后返回的页面地址">
      <el-input v-model="form.returnUrl" placeholder="请输入" clearable />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="onSubmit">提交</el-button>
    </el-form-item>
  </el-form>
  <br>
  <h2>退款</h2>
  <el-form :inline="true" :model="form2" class="demo-form-inline">
    <el-form-item label="退款单号">
      <el-input v-model="form2.outTradeNo" placeholder="请输入" clearable />
    </el-form-item>
    <el-form-item label="退款金额">
      <el-input-number v-model="form2.refundAmount" placeholder="请输入" clearable />
    </el-form-item>
    <el-form-item>
      <el-button type="primary" @click="onSubmit2">提交</el-button>
    </el-form-item>
  </el-form>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import dayjs from 'dayjs';
import router from '@/router';
import { ElNotification } from 'element-plus'
import { alipayApi } from '@/api';
const form = ref({
  subject: '小米su8',
  outTradeNo: dayjs().format('YYYYMMDDHHmmss'),
  totalAmount: 188888,
  returnUrl: 'http://localhost:5000/paysuccess'
})

const form2 = ref({
  outTradeNo: '20220422164101',
  refundAmount: 18888,
})
const onSubmit = () => {
  let returnUrl = encodeURIComponent(form.value.returnUrl)
  window.location.href = "http://localhost:8080/api/alipay/pay?subject=" + `${form.value.subject}` + "&outTradeNo=" + `${form.value.outTradeNo}`
    + "&totalAmount=" + `${form.value.totalAmount}` + "&returnUrl=" + `${returnUrl}`
}
const onSubmit2 = () => {
  alipayApi.refund.call({
    outTradeNo: form2.value.outTradeNo,
    refundAmount: form2.value.refundAmount
  }).then(_res => {
    ElNotification({
      title: '提示',
      message: '退款成功',
      type: 'success',
    })
  })
}

</script>

测试结果

一方面 : 前端返回我们设置的 returnUrl 界面

另一方: 后端执行 配置的 alipay.notifyUrl=http://xxxk.w1.luyouxia.net/api/alipay/notify

成功

3.7 退款

调用 refund 交易退款方法

java 复制代码
    @GetMapping("/refund")
    public String refund( String outTradeNo,Float refundAmount) {
        try {
com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse response = Factory.Payment.Common().refund(outTradeNo, String.valueOf(refundAmount));
            System.out.println(response);
            if (response.msg.equals("Success")){
                return "退款成功";
            }else {
                throw new BizException(777, "退款失败");
            }
        }catch (Exception e){
            e.printStackTrace();
            throw  new BizException(777, "退款失败");
        }
    }

通用版

​小程序文档 - 支付宝文档中心​

通用版

导入依赖

XML 复制代码
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.34.0.ALL</version>
        </dependency> 

配置

java 复制代码
@Component
@ConfigurationProperties(prefix = "alipay2")
@Data
public class Alipay2Config extends com.alipay.api.AlipayConfig {
    // 网关地址
    private String serverUrl;
    // 应用Id
    private String appId;
    // 应用私钥
    private String appPrivateKey;
    //请求格式
    private String format;
    //字符集编码
    private String charset;
    //签名类型
    private String signType;
    // 支付宝公钥
    private String publiceKey;
    // 回调接口路径
    private String notifyUrl;

}

支付

java 复制代码
    @GetMapping("/pay2")
    public void pay2(String subject, String outTradeNo, String totalAmount, String returnUrl, HttpServletResponse httpResponse) throws Exception {
        AlipayClient alipayClient = new DefaultAlipayClient(alipay2Config.getServerUrl(), alipay2Config.getAppId(),
       alipay2Config.getAppPrivateKey(), alipay2Config.getFormat(), alipay2Config.getCharset(), alipay2Config.getAlipayPublicKey(), alipay2Config.getSignType());
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        request.setNotifyUrl(alipay2Config.getNotifyUrl());
        request.setReturnUrl(returnUrl);
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", outTradeNo);
        bizContent.put("total_amount", totalAmount);
        bizContent.put("subject", subject);
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
        request.setBizContent(bizContent.toString());
        String form = "";
        try {
            // 调用SDK生成表单
            form = alipayClient.pageExecute(request).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        httpResponse.setContentType("text/html;charset=UTF-8");
        // 直接将完整的表单html输出到页面
        httpResponse.getWriter().write(form);
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

退款

java 复制代码
        /**
         * 退款接口
         *
         * @return
         */
        @GetMapping("/refund2")
        public String refund2 (String outTradeNo, Float refundAmount){
            AlipayClient alipayClient = new DefaultAlipayClient("https://openapi-sandbox.dl.alipaydev.com/gateway.do",
                    alipayConfig.getAppId(),
                    alipayConfig.getAppPrivateKey(),
                    "JSON",
                    "utf-8",
                    alipayConfig.getPubliceKey(),
                    "RSA2");
            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            // 获取获取对应订单信息
            JSONObject bizContent = new JSONObject();
            bizContent.put("out_trade_no", outTradeNo);
            bizContent.put("refund_amount", refundAmount);
            bizContent.put("out_request_no", "HZ01RF002"); //退款标识,用于查询状态是操作
            request.setBizContent(bizContent.toString());
            // 使用支付宝支付页面接口进行支付
            try {
                AlipayTradeRefundResponse response = alipayClient.execute(request);
                System.out.println(response);
                if (response.isSuccess()) {
                    System.out.println("退款成功");
                    return "退款成功";
                } else {
                    System.out.println("退款失败");
                    throw new BizException(777, "退款失败");
                }
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("退款失败");
                throw new BizException(777, "退款失败");
            }
        }
相关推荐
尘浮生10 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
六月闻君24 分钟前
MySQL 报错:1137 - Can‘t reopen table
数据库·mysql
mengao123425 分钟前
centos 服务器 docker 使用代理
服务器·docker·centos
SelectDB技术团队33 分钟前
兼顾高性能与低成本,浅析 Apache Doris 异步物化视图原理及典型场景
大数据·数据库·数据仓库·数据分析·doris
C-cat.34 分钟前
Linux|进程程序替换
linux·服务器·microsoft
怀澈12236 分钟前
高性能服务器模型之Reactor(单线程版本)
linux·服务器·网络·c++
腾科张老师38 分钟前
如何进行Apache的配置与调试?
apache
DC_BLOG38 分钟前
Linux-Apache静态资源
linux·运维·apache
学Linux的语莫40 分钟前
Ansible Playbook剧本用法
linux·服务器·云计算·ansible
inventecsh1 小时前
mongodb基础操作
数据库·mongodb