当前位置: 首页 > article >正文

Uniapp Android SpringBoot3 对接支付宝支付(最新教程附源码)

Uniapp Android SpringBoot3 对接支付宝支付(最新教程附源码)

  • 1、效果展示
  • 2、后端实现
    • 2.1 引入支付宝SDK依赖 pom.xml
    • 2.2 配置 application.yml
    • 2.3 支付宝相关代码
      • 2.3.1 AlipayConfig.java
      • 2.3.2 ZfbPayConfig.java
      • 2.3.3 支付接口
      • 2.3.4 支付回调处理接口(用于支付成功后,支付宝通知我们支付信息)
      • 2.3.4 退款接口
  • 3 前端代码
    • 3.1 支付接口调用
    • 3.2 支付方法
    • 3.2 退款接口调用

1、效果展示

效果展示

2、后端实现

2.1 引入支付宝SDK依赖 pom.xml

<dependency>
       <groupId>com.alipay.sdk</groupId>
       <artifactId>alipay-sdk-java</artifactId>
       <version>4.40.0.ALL</version>
</dependency>

2.2 配置 application.yml

在这里插入图片描述

在这里插入图片描述

真实环境需要开通 APP 支付, 如果是沙箱环境的话不支持退款。

# 支付宝支付
alipay:
  server_url: https://openapi.alipay.com/gateway.do
  app_id: # 你的 appId
  private_key:  # 你的私钥
  format: json
  sellerId: 2088722047235165
  charset: utf-8
  alipay_public_key: # 你的公钥
  sign_type: RSA2
  notifyUrl: http://wtw867.natappfree.cc/app/shop/order/zfb-pay/notify # 支付成功通知地址

2.3 支付宝相关代码

2.3.1 AlipayConfig.java


package com.zhong.config;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Getter
@Setter
@ToString
@Component
@ConfigurationProperties(prefix = "alipay")
public class AlipayConfig extends com.alipay.api.AlipayConfig {
    private String serverUrl;
    private String appId;
    private String privateKey;
    private String format;
    private String charset;
    private String alipayPublicKey;
    private String signType;
    private String notifyUrl;
}

2.3.2 ZfbPayConfig.java


package com.zhong.config;

import com.alipay.api.AlipayApiException;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeAppPayModel;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.request.AlipayTradeAppPayRequest;

import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeAppPayResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.zhong.model.entity.goods.GoodsOrderInfo;
import com.zhong.service.GoodsOrderInfoService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

@Configuration
@Component
@Data
@Slf4j
public class ZfbPayConfig {
    @Autowired
    AlipayConfig alipayConfig;
    @Autowired
    private GoodsOrderInfoService goodsOrderInfoService;

    private DefaultAlipayClient client() throws AlipayApiException {
        return new DefaultAlipayClient(alipayConfig);
    }

    public String pay(GoodsOrderInfo order) {

        String source = "";
        try {
            DefaultAlipayClient client = client();
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            model.setSubject("云尚社区");
            model.setOutTradeNo(order.getOrderNo());
            model.setTotalAmount(String.valueOf(0.01));
            // alipay 封装的接口调用
            AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
            request.setBizModel(model);
            request.setNotifyUrl(alipayConfig.getNotifyUrl());
            AlipayTradeAppPayResponse response = client.sdkExecute(request);
            source = response.getBody();
        } catch (AlipayApiException e) {
            goodsOrderInfoService.noPay(order.getOrderNo());  // 支付失败更新订单状态,可以根据您的具体业务做出调整
            log.error("支付出现问题,详情:{}", e.getErrMsg());
            e.printStackTrace();
        }
        log.info(source);
        return source;

    }

    /**
     * 退款
     *
     * @param tradeNo
     * @param totalAmount
     * @return
     */
    public AlipayTradeRefundResponse refund(String tradeNo, String totalAmount) {
        try {
            DefaultAlipayClient client = client();
            AlipayTradeRefundModel alipayTradeRefundModel = new AlipayTradeRefundModel();
            alipayTradeRefundModel.setTradeNo(tradeNo);
            alipayTradeRefundModel.setRefundAmount(totalAmount);

            AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
            request.setBizModel(alipayTradeRefundModel);
            AlipayTradeRefundResponse response = client.execute(request);
            return response;
        } catch (AlipayApiException e) {
            log.error("退款出现问题,详情:{}", e.getErrMsg());
            e.printStackTrace();
        }
        return null;
    }

}

2.3.3 支付接口


全局统一返回结果类

package com.zhong.result;

import lombok.Data;

/**
 * 全局统一返回结果类
 */
@Data
public class Result<T> {

    //返回码
    private Integer code;

    //返回消息
    private String message;

    //返回数据
    private T data;

    public Result() {
    }

    private static <T> Result<T> build(T data) {
        Result<T> result = new Result<>();
        if (data != null)
            result.setData(data);
        return result;
    }

    public static <T> Result<T> build(T body, ResultCodeEnum resultCodeEnum) {
        Result<T> result = build(body);
        result.setCode(resultCodeEnum.getCode());
        result.setMessage(resultCodeEnum.getMessage());
        return result;
    }
    public static <T> Result<T> fail(Integer code, String message) {
        Result<T> result = build(null);
        result.setCode(code);
        result.setMessage(message);
        return result;
    }

    public static <T> Result<T> ok(T data) {
        return build(data, ResultCodeEnum.SUCCESS);
    }

    public static <T> Result<T> ok() {
        return Result.ok(null);
    }

    public static <T> Result<T> fail() {
        return build(null, ResultCodeEnum.FAIL);
    }
}

支付接口

我这里是多订单的,如果是但订单的话这里 payUrl = zfbPayConfig.pay(goodsOrderInfoArrayList.get(0)); 可以传入一个 orderInfo 方便zfbPayConfig.pay() 获取 tradeNo 和 totalAmount。

   @Operation(summary = "支付商品订单")
    @GetMapping(value = "/pay/zfb")
    @ResponseBody
    public Result pay(@RequestParam String id) throws AlipayApiException {
        List<String> split = List.of(id.split(","));
        String payUrl = "";
        // 单个商品的情况
        if (split.size() == 1) {
            GoodsOrderInfo orderInfo = service.getById(id);
            orderInfo.setTotalPrice((orderInfo.getTotalPrice()));
            payUrl = zfbPayConfig.pay(orderInfo);
            orderInfo.setCodeUrl(payUrl);
            orderInfo.setOrderIds(id);
            service.saveOrUpdate(orderInfo);
        }
        // 多个商品
        else {
            ArrayList<GoodsOrderInfo> goodsOrderInfoArrayList = new ArrayList<>();
            BigDecimal price = new BigDecimal("0.00");
            for (String shopInfoId : split) {
                GoodsOrderInfo orderInfo = service.getById(shopInfoId);
                goodsOrderInfoArrayList.add(orderInfo);
                price = price.add(orderInfo.getPrice().multiply(BigDecimal.valueOf(orderInfo.getGoodNum())));
            }
            System.out.println(price);
            goodsOrderInfoArrayList.get(0).setTotalPrice(price);
            payUrl = zfbPayConfig.pay(goodsOrderInfoArrayList.get(0));
            goodsOrderInfoArrayList.get(0).setCodeUrl(payUrl);
            goodsOrderInfoArrayList.get(0).setOrderIds(id);
            service.saveOrUpdate(goodsOrderInfoArrayList.get(0));
        }
        return Result.ok(payUrl);

    }

2.3.4 支付回调处理接口(用于支付成功后,支付宝通知我们支付信息)


@PostMapping("/zfb-pay/notify")  // 注意这里必须是POST接口
    public String payNotify(HttpServletRequest request) {
        Map<String, String> params = new HashMap<>();
        Map<String, String[]> requestParams = request.getParameterMap();

        System.out.println("=========支付宝异步回调========");
        System.out.println(JSON.toJSONString(requestParams));
        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);
        }
        try {
            boolean flag = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());
            if (flag) {
                System.out.println("支付回调信息:" + params);
                // TODO 验签成功
                System.out.println("支付成功,异步验签成功!");

                // 验证订单是否为当前订单
                String orderNumber = params.get("out_trade_no");


                LambdaQueryWrapper<GoodsOrderInfo> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(GoodsOrderInfo::getOrderNo, orderNumber);
//                    .eq(ShopOrderInfo::getIsDeleted, 0)
                GoodsOrderInfo orderInfo = service.getOne(queryWrapper);
                if (orderInfo == null) {
                    throw new LeaseException(ResultCodeEnum.SHOP_ORDER_NOT_FIND_ERROR);
                }
                // 验证订单金额是否正确 TODO 测试环境不验证金额都是 0.01
//                BigDecimal totalPrice = new BigDecimal(params.get("total_amount"));
//                BigDecimal totalPriceParam = orderInfo.getTotalPrice();
//                if (!Objects.equals(totalPriceParam, totalPrice)) {
//                    throw new LeaseException(ResultCodeEnum.SHOP_ORDER_TOTAL_PRICE_ERROR);
//                }

                // 验证商家ID是否一致 防止付给别人了
                String sellerId = config.getProperty("alipay.sellerId");
                String sellerIdParams = params.get("seller_id");
                if (!Objects.equals(sellerId, sellerIdParams)) {
                    throw new LeaseException(ResultCodeEnum.SHOP_ORDER_BUSINESS_PID_ERROR);
                }

                // 验证APPID是否一致
                String appId = config.getProperty("alipay.app_id");
                String appIdParams = params.get("app_id");
                if (!Objects.equals(appIdParams, appId)) {
                    throw new LeaseException(ResultCodeEnum.SHOP_ORDER_BUSINESS_APPID_ERROR);
                }

                // 检查交易状态
                String tradeStatus = params.get("trade_status");
                if (!"TRADE_SUCCESS".equals(tradeStatus) && !"TRADE_CLOSED".equals(tradeStatus)) {
                    throw new LeaseException(ResultCodeEnum.SHOP_ORDER_PAY_ERROR);
                }
                // 支付成功
                if ("TRADE_SUCCESS".equals(tradeStatus)) {
                    // TODO 处理订单业务 修改订单状态 记录支付日志
                    service.processOrder(params);
                }
                // 退款操作
                if ("TRADE_CLOSED".equals(tradeStatus)) {
                    String orderNo = params.get("out_biz_no");
                    service.refund(orderNo);
                }


                return "success";
            } else {
                // TODO 支付失败标记为未付款
                String orderNumber = params.get("out_trade_no");
                service.noPay(orderNumber);


                return "error";
            }
        } catch (AlipayApiException e) {
            System.out.println("支付宝错误回调:" + e.getErrMsg());
            e.printStackTrace();
            return "error";
        }
    }

2.3.4 退款接口


ApplyRefund 退款参数

@Data
public class ApplyRefund {
    private String id;
    private String refundInfo;
    private String remarks;
}

退款接口

    @Operation(summary = "申请退款")
    @PostMapping("apply/refund")
    public Result applyRefund(@RequestBody ApplyRefund applyRefund) {
       service.applyRefund(applyRefund);
       return Result.ok();
    }

3 前端代码

3.1 支付接口调用


// 支付订单
export const payShopOrderApi = (id) => {
	return http.get(`/app/shop/order/pay/zfb?id=${id}`)
}

3.2 支付方法


	const toPayFun = async () => {
		// 调起支付
		let res = await payShopOrderApi(ids.value);
		console.log(res.data);
		uni.requestPayment({
			//服务提供商 通过uni.getProvider获取
			provider: 'alipay',
			//后台返回的订单数据
			orderInfo: res.data,
			//调用成功的回调
			success(res) {
				uni.showToast({
					title: "支付成功"
				})
				setTimeout(() => {
					uni.redirectTo({
						url: "/pages/src/user/user-order/user-order"
					})
				}, 500)
			},
			//调用失败的回调
			fail(err) {
				uni.showToast({
					title: "支付取消",
					icon: "none"
				})
				setTimeout(() => {
					uni.redirectTo({
						url: "/pages/src/user/user-order/user-order"
					})
				}, 500)
			}
		})
	}

3.2 退款接口调用


这里我的退款接口放在商家平台,app只负责申请退款,需要商家审核,使用的是TS代码。

// 退款
export interface PostInterfacesRefundRes {
  orderIds: number,
  tradeNo: number
}
const openDialog = async (
  rowData: PostInterfacesRefundRes = {} as PostInterfacesRefundRes,
) => {
  console.log(rowData);
  const params = {
    orderIds: rowData.orderIds,
    tradeNo: rowData.tradeNo
  }
  let res = await postAgreementRefundApi(params);
  ElMessage.success({ message: `操作成功!` })
  proTable.value?.getTableList()
}

http://www.kler.cn/a/428214.html

相关文章:

  • MySQL中的读锁与写锁:概念与作用深度剖析
  • Hive:Hive Shell技巧
  • C# dataGridView1获取选中行的名字
  • AI大模型开发原理篇-2:语言模型雏形之词袋模型
  • Flutter_学习记录_基本组件的使用记录
  • C# 与.NET 日志变革:JSON 让程序“开口说清话”
  • 【Linux】网络服务
  • k8s 之 DaemonSet
  • 【强化学习】策略梯度(Policy Gradient,PG)算法
  • 【MySQL】数据类型的注意点和应用
  • 008.精读《Apache Paimon Docs - Table w/o PK》
  • 【PyQt5教程 二】Qt Designer 信号与槽的使用方法及PyQt5基本小部件说明
  • CentOS8.5.2111(10)基于域名访问的邮件服务配置与管理
  • python录制鼠标键盘操作循环播放
  • LeetCode:28. 找出字符串中第一个匹配项的下标(KMP算法)
  • 【PlantUML系列】思维导图(五)
  • Flink自定义数据源
  • Netty 的多线程模型详解
  • LabVIEW中“this VI‘s owning library is missing”错误及解决
  • openharmony开发资料合集
  • UI Left EXE Right Recive TCPIP
  • YOLOv8-ultralytics-8.2.103部分代码阅读笔记-build.py
  • 【如何制定虚拟货币的补仓策略并计算回本和盈利】
  • Linux网络编程之---组播和广播
  • 快速排序的基本思想和java实现
  • Next.js系统性教学:全面掌握客服务端组件(Server Components)