阅读 153

对接支付宝App支付接口详解

前言

因工作需要,这几天摸索了很久,网上查找的资料大多不齐全,不详细,只有部分讲解及代码...所有我准备尽可能的把这篇博客写的详细易懂一些...好了..废话不多说..下面开始!!!

1.集成支付宝app支付,首先去申请一个支付宝账户.. open.alipay.com/platform/ma… 申请完了以后登录 再这里可以看到一个沙箱 看下图

image.png 点击进去

image.png

到这里我们在沙箱环境下的网页工作差不多就做完了...接下来就应该下载ali支付的jar包了..

下载地址:docs.open.alipay.com/54/106370/

下载完成后,添加到你的maven仓库中,如果项目是maven项目,还需要在pom文件中添加

image.png 2.我们需要先看一些支付宝的一些文档.

app支付官方文档地址:docs.open.alipay.com/204 

1、参数说明

(1)out_trade_no:商户订单号,由商户自定义设置;

(2)subject:商品标题;

(3)product_code:固定产品码值:QUICK_MSECURITY_PAY;

(4)total_amount:交易订单金额,精确到小数点后2位,最小设置为0.01;

2、接口请求示例

沙箱账号查看地址:openhome.alipay.com/platform/ap…

① controller层

/**
 * 充值
 * @param payDto payDto
  * @return R
 */
@PostMapping(value = "/charge")
public R charge(@RequestBody PayDto payDto){
    //payDto就是你前端传过来的值,比如充值金额是多少 用户id是多少..
    //这个实体类根据你们自己的业务需求去写就好
    String orderString = aliPayService.order(payDto);
    return R.ok("orderString",orderString);
}
复制代码

② service层

/**
 * 支付宝下单
 * @param payDto payDto
 * @return String
 */
 String order(PayDto payDto);
复制代码

③serviceImpl

重点 重点 重点 重点 重点 重点 重点 请各位仔细阅读这里的每一行代码

首先这里我们先新建一个AlipayConfig实体类代码我贴出来.有些东西需要你们自己修改我会在代码上方注释的..仔细看...

package com.wenliao.cloud.config;
 
/**
 * @ClassName: AliPayConfig
 * @Description: 需要传给支付宝SDK的公共基本参数
 * @author: Linn
 * @Date: 2019/4/3 9:22
 */
public class AliDevPayConfig {
 
    /**
     * 1.商户appid
     */
    public String APPID = "这个就是在沙箱环境下你看到你的appId的那一串数字";
 
    /**
     * 私钥 pkcs8格式的
     */
    public static String RSA_PRIVATE_KEY ="这个就是我上面说的应用私钥生成 注意这里是私钥";
 
    /**
     * 3.支付宝公钥
     */
    public static String ALIPAY_PUBLIC_KEY = "这个就是你把生成的应用公钥在沙箱网页哪里输入后,就可以查看到支付宝公钥..把看到的支付宝公钥copy过来放这里就ok";
 
    /**
     * 4.服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
     */
//这个着重讲一下..支付完成后,支付宝会通过这个url请求到你的服务端..
//这个url一定是要公网可以访问才行...如果需要测试的话..我后面有讲到..
//这里你可以先写你本地项目的url 例如:localhost:8080/项目名/访问路径
    public static String notify_url = "http://2hu4349021.wicp.vip/pay/aliNotify";
 
    /**
     * 5.页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
     */
       //这里同上..不做详细说明了..
     public static String return_url = "http://2hu4349021.wicp.vip/pay/returnUrl";
 
    /**
     * 正式环境支付宝网关,如果是沙箱环境需更改成https://openapi.alipaydev.com/gateway.do
     */
    public static String URL = "https://openapi.alipaydev.com/gateway.do";
 
    /**
     * 7.编码
     */
    public static String CHARSET = "UTF-8";
 
    /**
     * 私钥 pkcs8格式的
     */
    // 8.返回格式
    public static String FORMAT = "json";
 
    /**
     * //签名方式 加密类型
     */
    public static String SIGNTYPE = "RSA2";
复制代码

上面的代码我写了一些注释..希望大家好好看一下..特别是一些刚刚接触支付宝对接的人..有很大帮助的

接下来我们就是在impl中实现了..

    @Override
    public String order(PayDto payDto) {
       //这里你可以做一些存表操作..具体根据你们自己的业务来操作...
        String orderString = "";//这个字符串是用来返回给前端的
        String orderNo = record.getOrderId();//这行代码是生成一个商户的订单号..根据你们自己的业务需求去生成就可以了..
        log.info("==================支付宝下单,商户订单号为:" + orderNo);
 
        try {
            AliDevPayConfig aliDevPayConfig= new  AliDevPayConfig(); //实例化上面的那个配置类..
            //实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息
            AlipayClient alipayClient = new DefaultAlipayClient(AliDevPayConfig.URL, aliDevPayConfig.getAPPID(),
                    AliDevPayConfig.RSA_PRIVATE_KEY, AliDevPayConfig.FORMAT, AliDevPayConfig.CHARSET,
                    AliDevPayConfig.ALIPAY_PUBLIC_KEY, AliDevPayConfig.SIGNTYPE);
            //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
            AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();
            //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式
            AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
            //业务参数传入,可以传很多,参考API
            //model.setPassbackParams(URLEncoder.encode(request.getBody().toString())); //公用参数(附加数据)
            //对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
            model.setBody("具体描述信息.例如QQ币充值");
            //商品名称
            model.setSubject("例:QQ币");
            //商户订单号(根据业务需求自己生成)
            model.setOutTradeNo(orderNo);
            //交易超时时间 这里的30m就是30分钟
            model.setTimeoutExpress("30m");
            //支付金额 后面保留2位小数点..不能超过2位
            model.setTotalAmount(10.00);
            //销售产品码(固定值) //这个不做多解释..看文档api接口参数解释
            model.setProductCode("QUICK_MSECURITY_PAY");
            ali_request.setBizModel(model);
            //异步回调地址(后台)//这里我在上面的aliPayConfig有讲..自己去看
            ali_request.setNotifyUrl(AliDevPayConfig.notify_url);
            log.info("====================异步通知的地址为:" + ali_request.getNotifyUrl());
            //同步回调地址(APP)同上
            ali_request.setReturnUrl(AliDevPayConfig.return_url);
            log.info("====================同步通知的地址为:" + ali_request.getReturnUrl());
 
            // 这里和普通的接口调用不同,使用的是sdkExecute
            //返回支付宝订单信息(预处理)
            AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request);
            //就是orderString 可以直接给APP请求,无需再做处理。
            orderString = alipayTradeAppPayResponse.getBody();
            System.out.println(orderString);
        } catch (AlipayApiException e) {
            e.printStackTrace();
            log.info("与支付宝交互出错,未能生成订单,请检查代码!");
        }
        return orderString;
    }
复制代码

好..到这里就拿到了一个orderString返回给前端..

返回信息:

alipay_sdk=alipay-sdk-java-dynamicVersionNo&app_id=2016101800718925&biz_content=%7B%22out_trade_no%22%3A%22201809251015343222843%22%2C%22total_amount%22%3A%220.01%22%2C%22subject%22%3A%22app%E6%94%AF%E4%BB%98%E6%B5%8B%E8%AF%95%22%2C%22passback_params%22%3A%22%25E5%2585%25AC%25E7%2594%25A8%25E5%259B%259E%25E4%25BC%25A0%25E5%258F%2582%25E6%2595%25B0%25E6%25B5%258B%25E8%25AF%259512334%25EF%25BC%2581%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%7D&charset=utf-8&format=JSON&method=alipay.trade.app.pay&notify_url=http%3A%2F%2F106.14.187.178%2Fopendevtools%2Fnotify%2Fdo%2Fa9bed896-0fc0-4b05-ba55-6a2550cacd36&return_url=https%3A%2F%2Fwww.baidu.com%2F&sign=qiOEfMcQoObzuPdZNkMOzavHfJLskTUWJxb08YObj8D0SexDStOw%2BHEwOs7x1hGih8Zs3rsT%2BA3aYVnmwp0FTnTYHx2cTbvz1tkNTzoguOG%2BdNR4b5dsJ%2BvUU4UbHV2KDOxg%2FASUcjcbhqitYraWjBgL02QWgTa%2FpA7dpZnxaOKyksZ1tvp7dR3zYvfDdVnfo3vpXlJxc8QTXsYvZdpODvmKG9odw%2FTsP2fZdt3Up7aiq7Ae8rby%2FNg%2BIMcGJjH%2F5MnUC99%2FU9%2Bjwt%2Biqt7jwU4PVfGimDY6ifIYs3PosGwfwrMTSZkI8AzdcsmwHRcqGJJNzlzegl9jQHw9mBzSAw%3D%3D&sign_type=RSA2&timestamp=2018-09-25+13%3A09%3A52&version=1.0
复制代码

客户端调试工具

前端调用支付宝接口进行支付....这里提供一个支付宝的测试App

测试服务端生成的请求参数是否正常,可使用客户端调试工具。

客户端调试工具:openclub.alipay.com/read.php?ti…

显示效果

image.png 注意:未输入密码之前,支付宝订单还是为创建状态,只有输入密码之后,才会生成支付宝订单,所以这个时候用查询接口查询会报错“订单不存在”

到这里支付成功后,支付宝那边会有一个同步返回和异步返回接口

这个同步我暂时还没有弄太明白...同步也只是告诉你,这个订单有没有支付...并不代表支付成功..支付成功还是得看异步通知返回...

controller层

    /**
     * 支付宝支付成功后.异步请求该接口
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping(value="/aliNotify",method= RequestMethod.POST)
    @ResponseBody
    public String aliNotify(HttpServletRequest request, HttpServletResponse response) throws IOException {
        System.out.println("=支付宝异步返回支付结果开始");
        //1.从支付宝回调的request域中取值
        //获取支付宝返回的参数集合
        Map<String, String[]> aliParams = request.getParameterMap();
        //用以存放转化后的参数集合
        Map<String, String> conversionParams = new HashMap<String, String>();
        for (Iterator<String> iter = aliParams.keySet().iterator(); iter.hasNext();) {
            String key = iter.next();
            String[] values = aliParams.get(key);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            // 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化
            //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "UTF-8");
            conversionParams.put(key, valueStr);
        }
        System.out.println("==返回参数集合:"+conversionParams);
        String status=aliPayService.aliNotify(conversionParams);
        return status;
    }
复制代码

service层

    /**
     * 支付宝异步回调
     * @param conversionParams conversionParams
     * @return String
     */
    String aliNotify( Map<String, String> conversionParams);
复制代码

serviceImpl层

/**
     * 支付宝异步请求逻辑处理
     *
     * @param
     * @return
     * @throws IOException
     */
    @Override
    public String aliNotify(Map<String, String> conversionParams) {
        log.info("=支付宝异步请求逻辑处理=");
        //签名验证(对支付宝返回的数据验证,确定是支付宝返回的)
        boolean signVerified = false;
        try {
            //调用SDK验证签名
        String alipayPublicKey = AliDevPayConfig.ALIPAY_PUBLIC_KEY;
        String charset = AliDevPayConfig.CHARSET;
        String signType = AliDevPayConfig.SIGNTYPE;
 
            signVerified = AlipaySignature.rsaCheckV1(conversionParams, alipayPublicKey, charset, signType);
            //对验签进行处理.
            if (signVerified) {
                log.info("+支付宝回调签名认证成功+");
                // 按照支付结果异步通知中的描述,对支付结果中的业务内容进行1\2\3\4二次校验,校验成功后在response中返回success,校验失败返回failure 支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)
                this.check(conversionParams);
                //验签通过 获取交易状态
                String tradeStatus = conversionParams.get("trade_status");
 
                //只处理支付成功的订单: 修改交易表状态,支付成功
                //只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功。
                if (tradeStatus.equals("TRADE_SUCCESS") ||tradeStatus.equals("TRADE_FINISHED")) {
                    //TODO 获取支付宝通知完成充值后续业务
                    //交易成功 获取商户订单号
                   
                        /**修改订单信息*/
                      
                        /**余额到账*/
                       //这里就主要是做你们自己的业务需求了,修改一些表什么的..
                    }
                    return "success";
                } else {
                    return "fail";
                }
            } else{  //验签不通过
                log.info("++验签不通过 !++");
                return "fail";
            }
        } catch (AlipayApiException e) {
            log.info("+++验签失败 !+++");
            e.printStackTrace();
        }
        return "fail";
    }
复制代码

到这里一整个支付就完了......多注意细节就ok...

如果大家有什么疑问,可以在评论区评论.我看到后会及时回复...有不对的地方请指出..我会及时修改.谢谢~

总结:

遇到新需求和新技术,多看官方文档...基本都能解决问题
复制代码

另外目前在努力筹备自己的开源博客中,寻一位前端工程师共同完成...谢谢~

文章分类
后端
文章标签