支付宝网页支付对接

支付宝支付联调

本篇文章主要是针对支付宝官网的接口文档,进行说明,虽说文档很详细,也也有图例分析,也有代码示例,但这里还是按照MVC架构分析一下

流程如下

  1. 预支付
    • 获取商品信息
    • 获取二维码图片
    • 用户扫码,确认支付
  2. 商家查看支付详情
    • 库存充足,缓存没问题的情况下,直接获取支付结果
      • 用户支付成功,交易成功
      • 用户支付失败,交易取消
    • 库存不足的情况下
      • 有缓存限制,预先锁定商品
        • 用户支付成功,交易成功
        • 用户支付失败,交易取消
      • 未做锁定商品
        • 直接取消交易(用户支付成功,退款;支付失败取消交易)
  3. 退款
    • 银行卡支付
    • 其他渠道支付
      • 部分退款(幂等性)
      • 全额退款
  4. 对账
    • 账单打印

其实,以上也就是常规的一些交易流程了,但是需要针对具体的业务进行具体的分析,例如高并发的缓存以及消息队列使用。以及常规情况下的网络延迟等问题都是需要考虑的,若仅仅作为测试使用,可以不需要考虑

整体流程

支付宝网页支付对接

前置工作

建议用户准备自己的沙箱环境,进行测试

沙箱环境流程

支付宝网页支付对接

沙箱App准备

因为使用的是沙箱环境,所以只能使用沙箱钱包进行扫码支付
支付宝网页支付对接
有可能出现的问题:如果不用沙箱钱包支付,有可能导致二维码超时

配置类(静态)

public class AlipayConfig {
    // 商户appid
    public static String APPID = "";
    // 私钥 pkcs8格式的
    public static String RSA_PRIVATE_KEY = "";
    // 服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
    public static String notify_url = "http://https://openapi.alipaydev.com/gateway.do/alipay.trade.wap.pay-JAVA-UTF-8/notify_url.jsp";
    // 页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
    public static String return_url = "http://https://openapi.alipaydev.com/gateway.do/alipay.trade.wap.pay-JAVA-UTF-8/return_url.jsp";
    // 请求网关地址
    public static String URL = "";
    // 编码
    public static String CHARSET = "UTF-8";
    // 返回格式
    public static String FORMAT = "json";
    // 支付宝公钥
    public static String ALIPAY_PUBLIC_KEY = "";
    // 日志记录目录
    public static String log_path = "/log";
    // RSA2
    public static String SIGNTYPE = "RSA2";
}

预支付

代码(AlipayTradePrecreateRequest)

@PostMapping("/payPer")
    public void payPer(String WIDout_trade_no, String WIDsubject, String WIDtotal_amount, String WIDbody, HttpServletResponse response) throws AlipayApiException {
        AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);
        AlipayTradePrecreateRequest alipay_request=new AlipayTradePrecreateRequest ();

        // 封装请求支付信息
        alipay_request . setBizContent ( "{"   +
                "\"out_trade_no\":\""+WIDout_trade_no+"\"," + //商户订单号
                "\"total_amount\":\""+WIDtotal_amount+"\","   +
                "\"subject\":\""+WIDsubject+"\","   +
                "\"store_id\":\""+WIDbody+"\","   +
                "\"timeout_express\":\"9000s\"}" );
        AlipayTradePrecreateResponse response1 = client.execute (alipay_request);
        List list= Arrays.asList(response1.getBody().split("\"qr_code\":"));
        String[] list1= list.get(1).toString().split("},\"sign\"");
        String a=list1[0].replace("\\","").replace("\"","");
        QrConfig config = new QrConfig(180, 180);

        // 设置边距,既二维码和背景之间的边距
        config.setMargin(3);
        // 高纠错级别
        config.setErrorCorrection(ErrorCorrectionLevel.H);
        //二维码内容
        BufferedImage bufferedImage = QrCodeUtil.generate(
                a,
                config
        );
        try {
            // 以JPEG格式向客户端发送
            ServletOutputStream os = response.getOutputStream();
            ImageIO.write(bufferedImage, "PNG", os);
            os.flush();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println(WIDout_trade_no);
    }

以上代码包含了一个二维码转换的工具类“Hutool”,工具类支持二维码定义中心logo

同时这里,并没有去解析JSON格式,仅仅作为测试使用,直接获取字符串分割

入参

  • out_trade_no:商户订单号,需要保证商家系统不重复。
  • total_amount:订单金额。
  • subject:商品的标题/交易标题/订单标题/订单关键字等。不可使用特殊字符,如 /,=,& 等。
  • store_id:商户门店编号。
  • timeout_express:交易超时时间。

出参

  • qr_code:订单二维码(有效时间 2 小时)以字符串的格式返回,开发者需要自己使用工具根据内容生成二维码图片。

查询交易

代码(AlipayTradeQueryRequest)

@GetMapping("/queryPay")
    public void queryPay(String WIDout_trade_no) throws AlipayApiException {
        AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
        AlipayTradeQueryRequest alipay_request = new AlipayTradeQueryRequest();

        alipay_request.setBizContent("{" +
                "\"out_trade_no\":\"2020123111227522\"}"); //设置业务参数
        AlipayTradeQueryResponse response = client.execute(alipay_request);//通过alipayClient调用API,获得对应的response类
        System.out.print(response.getBody());
    }

这里的做法,建议前端轮询请求,当然,也可以放入消息队列,然后后台做监听处理,根据具体业务来看吧

不是高并发的情况,建议轮询,以做到用户体验最好

入参

  • out_trade_no:支付时传入的商户订单号,与 trade_no 必填一个
  • trade_no:支付时返回的支付宝交易号,与out_trade_no 必填一个。

返回

  • code=10000,支付成功,流程结束
  • code=10003,等待用户付款
  • code=20000,网络超时,系统异常(根据需求,撤销交易或者继续等待)

撤销交易

代码(AlipayTradeCancelRequest )

@GetMapping("/refundPay")
    public void refundPay(String WIDout_trade_no) throws AlipayApiException {
        AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
        AlipayTradeCancelRequest alipay_request = new AlipayTradeCancelRequest ();

        alipay_request.setBizContent("{" +
                "\"out_trade_no\":\"20201231122418603\"}"); //设置业务参数
        AlipayTradeCancelResponse response = client.execute(alipay_request);//通过alipayClient调用API,获得对应的response类
        System.out.print(response.getBody());
    }

说明

  • 如果此订单用户支付失败,支付宝将关闭此订单。
  • 如果此订单用户支付成功,支付宝将退还订单资金给用户。
  • 仅发生支付系统超时或者支付结果未知时可调用本接口撤销交易,其他正常支付的单如需实现相同功能请调用alipay.trade.refund(统一收单交易退款接口)。

入参

  • out_trade_no:支付时传入的商户订单号,与 trade_no 必填一个。
  • trade_no:支付时返回的支付宝交易号,与out_trade_no 必填一个。

出参

  • retry_flag:是否需要重试,Y/N。
  • action:本次撤销触发的交易动作。
    • close:关闭交易,无退款 。
    • refund:产生了退款。

退款

流程图

支付宝网页支付对接

代码(AlipayTradeRefundRequest)

AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
        AlipayTradeRefundRequest alipay_request = new AlipayTradeRefundRequest();

        alipay_request.setBizContent("{" +
                "\"out_trade_no\":\"20201231122418603\"," +
                "\"out_request_no\":\"1000002\"," +
                "\"refund_amount\":\"5\"}"); //设置业务参数
        AlipayTradeRefundResponse response = client.execute(alipay_request);//通过alipayClient调用API,获得对应的response类
        System.out.print(response.getBody());
    }

说明

  • 退款的途径按照支付途径原路返回。
  • 支付渠道为花呗、余额等退款即时到账。
  • 银行卡的退款时间以银行退款时间为准,一般情况下 2 小时内可到账。
  • 开发者也可以在 商家中心 中退款。
  • 退款是否成功可以根据同步响应的 fund_change 参数来判断,返回值为 Y 则表示退款成功。
  • 退款接口会根据外部请求号 out_request_no 幂等返回,因此同一笔交易需要多次部分退款时,必须使用不同的 out_request_no

入参

  • out_trade_no:支付时传入的商户订单号,与trade_no必填一个
  • trade_no:支付时返回的支付宝交易号,与out_trade_no必填一个
  • out_request_no:本次退款请求流水号,部分退款时必传
  • refund_amount:本次退款金额。

出参

  • refund_fee:该笔交易已退款的总金额。

退款到银行卡

由于沙箱不支持银行卡操作,所以未进行测试

对账

流程图

支付宝网页支付对接

代码

    @GetMapping("/dataDataservice")
    public void dataDataservice() throws AlipayApiException {
        AlipayClient client = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
        AlipayDataDataserviceBillDownloadurlQueryRequest alipay_request = new AlipayDataDataserviceBillDownloadurlQueryRequest ();

        alipay_request.setBizContent("{" +
                "\"bill_type\":\"trade\"," +
                "\"bill_date\":\"2016-04-05\"}"); //设置业务参数
        AlipayDataDataserviceBillDownloadurlQueryResponse response = client.execute(alipay_request);//通过alipayClient调用API,获得对应的response类
        System.out.print(response.getBody());
    }

入参

  • bill_type:固定传入 trade。
  • bill_date:需要下载的账单日期,最晚是当期日期的前一天。

出参

  • bill_download_url:账单文件下载地址,有效时长:30 秒

说明

下载账单,根据各自喜欢工具类可进行封装,这里不在提供,或者可以直接参考支付宝官网


源代码

以上就是支付宝支付接口对接了,后续会继续分享支付宝登录、QQ登录等案例

上一篇:asp.net mvc 接入最新支付宝支付+退款


下一篇:spring boot整合支付宝支付(沙箱环境)