支付宝小程序支付 查询 退款 异步回调通知

最近在开发一款预约停车小程序, 记录一下使用支付宝支付api的流程,本文涉及到的是 公钥 加签方式

1.开发前的配置准备

1.1 创建小程序并上传审核

1.2 生成秘钥并上传

生成秘钥地址:跟着流程走即可

签名完成之后会自动生成支付宝公钥,需要记录保存

注释:在配置完签名之后可以获取支付宝公钥, 支付宝公钥唯一, 不会因为私钥和公钥的变换而改变
关于支付宝公钥的问题链接

如果做的项目是第三方平台(ISV)代替商户收款, 还是需要商户授权的(我做的就是这个)

2.通用配置

2.1 引入 maven 依赖

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

添加配置信息

wensi:
  alipay:
    gatewayUrl: https://openapi.alipay.com/gateway.do
    appid: 小程序id
    appPrivateKey: 你的应用私钥
    alipayPublicKey: 生成的阿里公钥

2.2 AlipayProperties

@Data
@ConfigurationProperties(prefix = "pay.alipay")
public class AlipayProperties {
    /**
     * 支付宝gatewayUrl
     */
    private String gatewayUrl;
    /**
     * 商户应用id
     */
    private String appid;
    /**
     * RSA私钥,用于对商户请求报文加签
     */
    private String appPrivateKey;
    /**
     * 支付宝RSA公钥,用于验签支付宝应答
     */
    private String alipayPublicKey;

    /**
     * 签名类型
     */
    private String signType = "RSA2";

    /**
     * 格式
     */
    private String formate = "json";
    /**
     * 编码
     */
    private String charset = "UTF-8";

    /**
     * 同步地址
     */
    private String returnUrl;

    /**
     * 异步地址
     */
    private String notifyUrl;
}

AlipayClient

@Autowired
private AlipayProperties properties;

/**
 * 支付宝接口加签模式为公钥时使用
 */
@Bean
public AlipayClient alipayClient() {
    return new DefaultAlipayClient(properties.getGatewayUrl(), // 支付宝网关 唯一
            properties.getAppid(), // 小程序的appid
            properties.getAppPrivateKey(), // 生成的私钥
            properties.getFormate(),
            properties.getCharset(),
            properties.getAlipayPublicKey(), // 阿里公钥
            properties.getSignType());
}

调取支付接口

//将 alipayClient 注入进来
// 建议对入参进行验证
// 创建订单请求
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
// 使用第三方代商户收款的时候传入
String appAuthToken = model.getAppAuthToken();
log.info("第三方授权token: {}", appAuthToken);
request.putOtherTextParam ("app_auth_token", appAuthToken );

//异步回掉地址
request.setNotifyUrl(notifyUrlConfig.getSelf());

//不想自己拼接 json 也可以使用对应的 model: AlipayTradeCreateModel
// 拼接请求 json
request.setBizContent("{" +
         "\"out_trade_no\":\""+thirdReq.getOutTradeNo()+"\"," + // 自己生产的订单号
         "\"total_amount\":"+realAmount.divide(new BigDecimal(100)).toString()+"," + // 金额
         "\"buyer_id\": "+ thirdReq.getBuyerId() + "," + // 购买者id,可以在授权的时候获取
         "\"subject\":\""+thirdReq.getSubject()+"\"" + "}"); // 支付标题

try {
    AlipayTradeCreateResponse response = alipayClient.execute(request);
    if (response.isSuccess()) {
    	// 创建订单成功 进行相应操作
        // tradeNo 需要给到前端,唤起支付请求
        String tradeNo = response.getTradeNo();
        log.info("创建当面付订单返回成功:订单编号:{}" , tradeNo);
    }else{
    	// 创建订单失败 进行相应操作
        log.info("创建当面付订单返回失败,返回信息:{}" , response.getMsg());
    }
} catch (AlipayApiException e) {
    e.printStackTrace();
}

buyer_id 在小程序支付中必须传入

官网创建订单链接

退款接口

// 建议对入参进行验证
// 创建退款请求
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
// 拼接退款 json 
request.setBizContent("{" +
        "\"out_trade_no\":\""+h5Req.getOrderId()+"\"," + // 退款订单号, 建议使用 trade_no
        "\"refund_amount\":"+totalAmount.divide(new BigDecimal(100)).toString()+" "+"}"); // 退款金额
// 如果是第三方代商户收款, 需要传入授权token
String appAuthToken = tenantConfig.getAppAuthToken();
request.putOtherTextParam ("app_auth_token", appAuthToken );

try {
    AlipayTradeRefundResponse response = alipayClient.execute(request);
    if (response.isSuccess()) {
        // 退款成功之后的相应操作
        log.info("退款接口成功返回:{}", response);
    }else {
        // 退款失败之后的相应操作
        log.info("退款接口返回失败:{}", response);
    }
} catch (AlipayApiException e) {
    e.printStackTrace();
}

官网退款接口链接

订单查询接口

AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"20150320010101001\"," +
"\"trade_no\":\"2014112611001004680 073956707\"," +
"\"org_pid\":\"2088101117952222\"," +
"      \"query_options\":[" +
"        \"trade_settle_info\"" +
"      ]" +
"  }");
AlipayTradeQueryResponse response = alipayClient.execute(request);
if(response.isSuccess()){
System.out.println("调用成功");
} else {
System.out.println("调用失败");
}

官网查询接口链接

异步回调通知

public String notify(HttpServletRequest request, HttpServletResponse httpServletResponse) {
log.info("-----------支付异步通知----------------");
// 获取支付宝回调通知参数
Map requestParams = request.getParameterMap();
log.info(">>>支付宝回调参数:{}", requestParams);
Map<String, String> params = new HashMap<>();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
    String name = (String) iter.next();
    String[] values = (String[]) requestParams.get(name);
    String valueStr = "";
    for (int i = 0; i < values.length; i++) {
        valueStr = (i == values.length - 1) ? valueStr + values[i]
                : valueStr + values[i] + ",";
    }
    //乱码解决,这段代码在出现乱码时使用。
    //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
    params.put(name, valueStr);
}
log.info(">>>支付宝回调参数解析:{}", params);

try {
	// 验签
    boolean signVerified = AlipaySignature.rsaCheckV1(params,
            mp.getAlipayPublicKey(),
            mp.getCharset(),
            mp.getSignType());

    if (signVerified) {
        log.info(">>>支付宝回调签名认证成功");
        //商户订单号
        String outTradeNo = params.get("out_trade_no");
        log.info("商户订单号===================>: {}", outTradeNo);
        //阿里订单号
        String tradeNo = params.get("trade_no");
        log.info("阿里订单号===================>: {}", tradeNo);
        //交易状态
        String trade_status = params.get("trade_status");
        log.info("回调的状态=============> {}", trade_status);
        
        String totalAmount = params.get("total_amount");
        BigDecimal a = new BigDecimal(totalAmount);
        log.info("总金额(单位:分)=================> {}", totalAmount);

        String buyerId = params.get("buyer_id");
        log.info("buyerId======================{}", buyerId);
		
		// 支付宝官网说订单状态只要为 TRADE_SUCCESS 即可
        if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
            log.info("-----------^v^支付成功^v^------------");
            // 更改订单状态,编写相应逻辑
        }
    } else {
        log.info("支付宝回调签名认证失败,signVerified=false, params:{}", params);
        //return "failure";
    }
} catch (AlipayApiException e) {
    e.printStackTrace();
    log.error(e.getMessage(), e);
    log.info("支付宝回调签名认证失败,signVerified=false, params:{}", params);
    //return "failure";
}
return "success";
}

支付宝说必须要打印 success ,才会停止发送异步通知,但是我在这边打印了反而还是显示错误.直接返回 string 类型的 success 反而没问题

异步查看回调结果,可以使用云排查
云排查连接

本人做的是单独的收银台模块,支持多方使用,如有需要,请加 QQ:2569905320

好记性不如烂笔头, 记录 加油

<think>嗯,用户想在他们的IDEA程序里加一个支付功能。首先,我需要明确他们指的是什么类型的程序。IDEA通常是指JetBrains的集成开发环境,但可能用户指的是他们自己开发的应用程序,可能用Java或Kotlin写的。需要确认这一点,不过可能用户指的是后者,即他们自己的应用。 接下来,支付功能的实现需要考虑几个方面。首先是选择支付渠道,比如支付宝、微信支付、银联,或者国际的PayPal、Stripe等。用户可能需要根据目标用户群体来选择,如果是国内用户,可能优先考虑支付宝和微信;国际用户则可能需要Stripe或PayPal。 然后,支付方式的选择也很重要。用户可能需要扫码支付、H5支付、APP支付小程序支付等。比如,如果他们的应用是移动端的,可能需要接入APP支付;如果是网页端,可能需要H5或扫码。 接下来是后端接口的开发。支付涉及金额和安全性,必须通过后端处理,不能在前端直接调用支付接口,否则会有安全风险。需要生成订单、处理回调通知、更新订单状态等。同时,需要处理异步通知,保证支付状态同步。 安全性方面,HTTPS是必须的,所有支付请求都要加密。敏感数据如API密钥要妥善保管,不能硬编码在代码里,可能用环境变量或配置中心。另外,签名验证也很重要,防止数据篡改。 前端集成的话,可能需要生成支付二维码,或者跳转到支付页面。在IDEA中开发的话,如果是桌面应用,可能需要内嵌浏览器组件来处理支付页面的跳转。如果是Web应用,可能直接在前端调用支付接口,但需确保后端处理敏感操作。 测试环节也很关键,支付功能必须经过充分的测试,尤其是沙箱环境。要模拟各种支付成功、失败、超时的情况,确保系统稳定。订单状态的更新和通知处理要可靠,避免出现掉单或重复支付的问题。 最后,合规性和用户体验。需要遵守相关法律法规,比如中国的支付业务许可证要求,如果自己没有资质,可能需要通过第三方支付公司。用户界面要友好,支付流程要简洁,避免步骤过多导致用户放弃。 可能用户是开发者,但经验不足,所以需要详细步骤和注意事项。比如,如何申请支付接口,如何生成签名,如何处理回调等。需要提醒他们注意安全,不要泄露密钥,使用沙箱环境测试,以及处理异常情况。 可能还需要考虑支付后的订单查询退款功能,这些也是支付系统的重要组成部分。另外,日志记录和监控,方便排查问题。比如,支付过程中出现网络错误,如何重试或通知用户。 总之,实现支付功能需要前后端协作,选择合适的支付渠道,确保安全性和稳定性,同时遵守法律法规,提供良好的用户体验。</think>在IDEA(IntelliJ平台)开发的应用程序中添加支付功能,需结合业务场景和技术选型分步骤实现。以下是详细指南: --- ### 一、明确需求 1. **支付场景** - 应用类型:桌面应用/插件/Web服务? - 支付范围:单次购买、订阅制、虚拟商品? - 用户地区:国内(支付宝/微信)或国际(Stripe/PayPal)? 2. **合规性** - 需申请企业资质(如企业支付宝/微信支付) - 若为个人开发者,推荐使用第三方聚合支付平台(如Ping++、Braintree) --- ### 二、技术实现步骤 #### 1. 选择支付渠道 - **国内常用** - 支付宝开放平台:[https://open.alipay.com](https://open.alipay.com) - 微信支付商户平台:[https://pay.weixin.qq.com](https://pay.weixin.qq.com) - **国际常用** - Stripe:[https://stripe.com](https://stripe.com) - PayPal:[https://developer.paypal.com](https://developer.paypal.com) #### 2. 后端开发(以Java为例) ```java // 示例:支付宝下单接口(需依赖Alipay SDK) public String createOrder(String orderId, BigDecimal amount) { AlipayClient client = new DefaultAlipayClient( "https://openapi.alipay.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", "UTF-8", ALIPAY_PUBLIC_KEY, "RSA2" ); AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); request.setReturnUrl("https://your-domain.com/return"); request.setNotifyUrl("https://your-domain.com/notify"); AlipayTradePagePayModel model = new AlipayTradePagePayModel(); model.setOutTradeNo(orderId); model.setTotalAmount(amount.toString()); model.setSubject("商品名称"); model.setProductCode("FAST_INSTANT_TRADE_PAY"); request.setBizModel(model); return client.pageExecute(request).getBody(); } ``` #### 3. 前端集成 - **桌面应用(JavaFX/Swing)** ```java // 使用JavaFX WebView加载支付页面 WebView webView = new WebView(); WebEngine engine = webView.getEngine(); engine.load(createOrderUrl); // 后端返回的支付URL Stage stage = new Stage(); stage.setScene(new Scene(webView, 800, 600)); stage.show(); ``` - **插件开发** 通过`BrowserUtil`打开外部浏览器: ```java BrowserUtil.browse("https://payment-page-url"); ``` #### 4. 处理支付回调 ```java // 支付宝异步通知验签 public boolean verifyNotification(Map<String, String> params) { try { return AlipaySignature.rsaCheckV1( params, ALIPAY_PUBLIC_KEY, "UTF-8", "RSA2" ); } catch (AlipayApiException e) { return false; } } ``` --- ### 三、关键注意事项 1. **安全性** - 使用HTTPS传输数据 - 敏感信息(如API密钥)通过环境变量或Vault管理 - 避免在日志中记录支付敏感数据 2. **测试策略** - 支付宝沙箱环境:`https://openhome.alipay.com/platform/appDaily.htm` - Stripe测试卡号:`4242 4242 4242 4242`(模拟成功支付) 3. **异常处理** - 网络超时重试机制 - 订单状态对账(每日定时任务) --- ### 四、推荐工具 1. **调试工具** - IDEA内置HTTP Client:测试支付API - Postman:模拟回调通知 2. **监控** - ELK日志分析 - Prometheus + Grafana监控支付成功率 --- 通过以上步骤,可在保证安全性和稳定性的前提下,为应用程序集成支付功能。若需更具体的代码示例(如微信支付或Stripe),可进一步说明技术栈和业务场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值