支付宝沙箱支付回调接口(详情)

前提:注册支付宝开放平台 开放平台

并且登录到沙箱控制台 登录 - 支付宝

1.准备工作做完,加pom依赖

<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-sdk-java</artifactId>
    <version>4.22.110.ALL</version>
</dependency>
<dependency>
    <groupId>com.alipay.sdk</groupId>
    <artifactId>alipay-easysdk</artifactId>
    <version>2.2.0</version>
</dependency>

  2.配置 将以下配置写入nacos

alipay:
  #APPID
  appId: 支付宝账号ID
  gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
  #应用私钥
  appPrivateKey: 这里写账号里的私钥
  #支付宝公钥
  alipayPublicKey: 支付宝公钥
  #回调接口 (使用内网穿透:https://natapp.cn/)
  returnUrl: https://www.baidu.com/s?ie=UTF-8&wd=%E5%8C%97%E4%BA%AC%E6%97%B6%E9%97%B4
  # 支付通知的回调地址,支付宝会在支付完成后通知这个地址
  notifyUrl: http://j97sy7.natappfree.cc/priceSum/notify
  # 参数返回格式,只支持JSON
  format: JSON
  # 请求使用的编码格式
  charset: UTF-8
  # 生成签名字符串所使用的签名算法类型
  signType: RSA2

注:支付宝公钥 分为两种,一种 支付宝公钥 一种应用公钥,这里一定要用支付宝公钥,不要写错了!!!

如图所示:

3.配置工具类

package com.shopgoods.order.config;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@Data
@ConfigurationProperties(prefix = "alipay")
public class AlipayConfig {
    /**
     * 支付宝网关
     */
    private String gatewayUrl;
    /**
     * 应用ID
     */
    private String appId;
    /**
     * 应用私钥
     */
    private String appPrivateKey;
    /**
     * 支付宝公钥
     */
    private String alipayPublicKey;
    /**
     * 用户确认支付后,支付宝调用的页面返回路径
     * 开发环境为:http://localhost:8060/#/pages/money/paySuccess
     */
    private String returnUrl;
    /**
     * 支付成功后,支付宝服务器主动通知商户服务器里的异步通知回调(需要公网能访问)
     * 开发环境为:http://localhost:8085/alipay/notify
     */
    private String notifyUrl;
    /**
     * 参数返回格式,只支持JSON
     */
    private String format;
    /**
     * 请求使用的编码格式
     */
    private String charset;
    /**
     * 生成签名字符串所使用的签名算法类型
     */
    private String signType;
}

4.当Spring容器启动时,它会自动调用alipayClient方法,并将结果作为bean存储在Spring的IoC(控制反转)容器中,这样在整个应用程序中都可以方便地注入和使用这个AlipayClient实例来进行支付宝相关的操作

package com.shopgoods.order.config;

import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AlipayClientConfig {

    @Bean
    public AlipayClient alipayClient(AlipayConfig config){
        return new DefaultAlipayClient(config.getGatewayUrl(),config.getAppId(),config.getAppPrivateKey(), config.getFormat(),config.getCharset(),config.getAlipayPublicKey(),config.getSignType());
    }
}

创建Service

package com.shopgoods.order.service;

import com.shopgoods.order.config.AlipayConfig;
import com.shopgoods.order.domain.AliPayParam;
import com.shopgoods.order.domain.PricesSum;
import org.springframework.stereotype.Service;

import java.util.Map;

/**
 * @ClassName: PriceSumService
 * @Description: TODO
 * @Author: qh
 * @Date: 2024/11/22 18:34
 */

public interface PriceSumService {
    String webPay(AliPayParam aliPayParam);
/**
     * 支付宝异步回调处理
     */
    String notify(Map<String, String> params);
}

创建ServiceImpl

package com.shopgoods.order.service.impl;

import com.alibaba.csp.sentinel.util.StringUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradeQueryRequest;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import com.alipay.api.response.AlipayTradeQueryResponse;
import com.shopgoods.order.config.AlipayConfig;
import com.shopgoods.order.domain.AliPayParam;
import com.shopgoods.order.mapper.OrderMapper;
import com.shopgoods.order.service.IOrderService;
import com.shopgoods.order.service.PriceSumService;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

import static org.bouncycastle.asn1.x500.style.RFC4519Style.cn;

/**
 * @ClassName: PriceSumServiceImpl
 * @Description: TODO
 * @Author: qh
 * @Date: 2024/11/22 18:35
 */
@Service
@Log4j2
public class PriceSumServiceImpl implements PriceSumService {

    @Autowired
    private AlipayClient alipayClient;
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private IOrderService orderService;

    @Autowired
    private AlipayConfig alipayConfig;
    @Override
    public String webPay(AliPayParam aliPayParam) {
        AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest ();
        if(StrUtil.isNotEmpty(alipayConfig.getNotifyUrl())){
            //异步接收地址,公网可访问
            request.setNotifyUrl(alipayConfig.getNotifyUrl());
        }
        if(StrUtil.isNotEmpty(alipayConfig.getReturnUrl())){
            //同步跳转地址
            request.setReturnUrl(alipayConfig.getReturnUrl());
        }
        //******必传参数******
        JSONObject bizContent = new JSONObject();
        //商户订单号,商家自定义,保持唯一性
        bizContent.put("out_trade_no", aliPayParam.getOutTradeNo());
        //支付金额,最小值0.01元
        bizContent.put("total_amount", aliPayParam.getTotalAmount());
        //订单标题,不可使用特殊符号
        bizContent.put("subject", aliPayParam.getSubject());
        //手机网站支付默认传值FAST_INSTANT_TRADE_PAY
        bizContent.put("product_code", "QUICK_WAP_WAY");
        request.setBizContent(bizContent.toString());
        String formHtml = null;
        try {
            formHtml = alipayClient.pageExecute(request).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        return formHtml;
    }

     @Override
    public String notify(Map<String, String> params) {
        String result = "failure";
        boolean signVerified = false;
        try {
            //调用SDK验证签名
            signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(), alipayConfig.getCharset(), alipayConfig.getSignType());
        } catch (AlipayApiException e) {
            log.error("支付回调签名校验异常!",e);
            e.printStackTrace();
        }
        if (signVerified) {
            String tradeStatus = params.get("trade_status");
            if("TRADE_SUCCESS".equals(tradeStatus)){
                result = "success";
                log.info("notify方法被调用了,tradeStatus:{}",tradeStatus);
                String outTradeNo = params.get("out_trade_no");
//                portalOrderService.paySuccessByOrderSn(outTradeNo,1);
               //支付成功修改状态
                orderService.updatePaySuccessByOrderSn(outTradeNo,3);
            }else{
                log.warn("订单未支付成功,trade_status:{}",tradeStatus);
            }
        } else {
            log.warn("支付回调签名校验失败!");
        }
        return result;
    }

6.回调之前必须提前配置好内网穿透

先下载natapp

内网穿透链接:NATAPP -

购买一个免费隧道就可以了

将nacos回调地址更改为以上的地址

### 支付宝沙盒环境中的异步回调参数传递 在支付宝沙盒环境中实现异步回调时,需确保服务器能够接收来自支付宝的通知。由于异步调用路径必须为公网地址,本地开发环境下可借助工具如 `ngrok` 将本地服务暴露于互联网上[^1]。 #### 实现异步回调的关键要素 - **公网访问**:使用类似 ngrok 的工具创建一个临时的公网 URL 来转发请求到本地服务器。 - **POST 请求处理**:支付宝通过 POST 方法发送通知给指定的回调 URL。因此,应用程序应设置相应的路由来监听并解析这些 POST 请求的数据。 ```python from flask import Flask, request app = Flask(__name__) @app.route('/notify', methods=['POST']) def notify(): data = request.form.to_dict() # 处理接收到的数据... return 'success' ``` - **验证签名**:为了保障数据的安全性和完整性,在接收到通知后应当先校验消息的真实性。这通常涉及到对接收的消息按照特定算法重新计算签名并与传入的 sign 值对比。 ```python import hashlib import hmac def verify_sign(data, secret_key): sorted_items = sorted(data.items()) message = '&'.join([f"{k}={v}" for k, v in sorted_items]) signature = hmac.new( key=secret_key.encode(), msg=message.encode(), digestmod=hashlib.sha256 ).hexdigest().upper() return signature == data.get('sign') ``` - **业务逻辑执行**:一旦确认了通知的有效性,则可以依据实际需求更新订单状态或其他相关操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值