支付宝APP支付

一、基础说明

现在开发一个电商APP,最少不了的就是支付,目前最常见的支付有微信支付和支付宝支付,先来介绍支付宝APP支付,其实支付宝的文档说明已经很清楚了,里面有很多demo,你还可以通过沙箱环境去调试支付。蚂蚁金服开放平台地址:https://open.alipay.com/developmentAccess/developmentAccess.htm

下面先贴出一张流程图:

支付宝APP支付

 

第一步:用户提交支付,APP去带着订单信息请求服务端

第二步:服务端对订单信息进行处理后去请求支付宝(这一步可以设置异步回调和同步回调地址)获取签名后的订单信息,我的理解就是预支付订单信息,(支付宝不存在预付单,可以理解为预付单)

第三步:返回签名后的订单信息给APP客户端

第四步:APP客户端携带预支付订单信息唤起支付宝APP进行支付

第五步:支付完成后,支付宝会同步回调和异步回调,其中异步回调是最重要的,也是回调到服务端的信息,同步回调因为客户端APP和网络的原因,不是十分可靠。

第六步:服务端接收到支付宝异步回调请求,根据请求信息去更新订单信息

第七步:APP客户端通过支付宝交易查询接口去查询刚刚支付的订单状态

第八步:APP客户端根据第七步的结果,处理相应的业务逻辑。例如交易成功显示页面A,交易失败显示页面B。

 

  • 服务端支付实现

 

作为服务端,我们需要做的是第二步、第三步、第五步,下面详细介绍这几步该如何实现。

第二步:APP客户端提交订单信息到服务端,服务端首先对订单信息进行校验,校验通过后再调用alipay.trade.order.settle(统一收单交易结算接口),操作成功后会返回必要的预支付信息。

public String orderAliPay(String payAmount, String outTradeNo) {
    String orderStr = "";
    try {
        // 实例化客户端
        AlipayClient alipayClient = new DefaultAlipayClient(aliPayUrl, APP_ID,
                APP_PRIVATE_KEY, "json", CHARSET, APP_PUBLIC_KEY, "RSA2");
        // 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
        AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
        // SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
        AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
        // model.setPassbackParams(URLEncoder.encode(body.toString()));
        // 描述信息 添加附加数据
        model.setSubject("x"); // 商品标题
        model.setOutTradeNo(outTradeNo); // 商家订单编号
        model.setTimeoutExpress("30m"); // 超时关闭该订单时间
        model.setTotalAmount(payAmount); // 订单总金额
        model.setProductCode("QUICK_MSECURITY_PAY"); // 销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
        request.setBizModel(model);
        request.setNotifyUrl(notifyUrl); // 回调地址

        try {
            // 这里和普通的接口调用不同,使用的是sdkExecute
            AlipayTradeAppPayResponse response = alipayClient
                    .sdkExecute(request);
            orderStr = response.getBody();
            logger.info("支付宝支付预处理-商户订单号:" + outTradeNo);
            logger.info("支付宝支付预处理-结果:" + response.isSuccess());
            // 可以直接给客户端请求,无需再做处理。
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
    } catch (Exception e) {
        logger.error("Exception", e);
    }
    return orderStr;
}

 

 

参数说明:

payAmount支付金额  

outTradeNo:订单流水号(系统唯一)

aliPayUrl  支付宝支付接口https://openapi.alipay.com/gateway.do

APP_ID  支付宝分配给开发者的应用ID  

APP_PRIVATE_KEY 应用私密匙

APP_PUBLIC_KEY 应用公密匙

notifyUrl  异步回调地址 必须外网环境下可以正常访问的地址

 

正确的返回结果是这样的:

{

    "alipay_trade_order_settle_response": {

        "code": "10000",

        "msg": "Success",

        "trade_no": "2015070921001004130000127421"

    },

    "sign": "ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE"

}

把这个信息返回给APP开发人员就行了。如果返回信息错误,就要参考具体的返回码:https://docs.open.alipay.com/api_1/alipay.trade.order.settle

https://docs.open.alipay.com/54/106370/

 

 

 

  • 服务端回调实现

 

@RequestMapping(value = "/aliPayNotify", produces = "text/html;charset=UTF-8", method = RequestMethod.POST)
public String aliPayNotify(HttpServletRequest request,HttpServletResponse response) {
   logger.info("支付宝支付完成回调,进入 aliPayNotify 方法");
       Map<String, String[]> requestParams = request.getParameterMap();

   // 获取支付宝POST过来反馈信息
   Map<String, String> params = new HashMap<String, String>();
   logger.info("遍历支付成功后支付宝返回的参数requestParams,进行设值");
   for (Iterator<String> 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);
   }

 

获取返回信息后,需要对信息进行签名进行验证:

//获取支付宝POST过来反馈信息

Map<String,String> params = new HashMap<String,String>();

Map requestParams = request.getParameterMap();

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);

}

//切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。

//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)

boolean flag = AlipaySignature.rsaCheckV1(params, alipaypublicKey, charset,"RSA2")

 

签名校验通过后再进行订单更新业务逻辑处理,注意支付宝建议服务端返回success状态

支付宝是用POST方式发送通知信息,因此该页面中获取参数的方式,如:request.Form(“out_trade_no”) $_POST[‘out_trade_no’];

支付宝主动发起通知,该方式才会被启用;

只有在支付宝的交易管理中存在该笔交易,且发生了交易状态的改变,支付宝才会通过该方式发起服务器通知(即时到账交易状态为“等待买家付款”的状态默认是不会发送通知的);

服务器间的交互,不像页面跳转同步通知可以在页面上显示出来,这种交互方式是不可见的;

第一次交易状态改变(即时到账中此时交易状态是交易完成)时,不仅会返回同步处理结果,而且服务器异步通知页面也会收到支付宝发来的处理结果通知;

程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h);

程序执行完成后,该页面不能执行页面跳转。如果执行页面跳转,支付宝会收不到success字符,会被支付宝服务器判定为该页面程序运行出现异常,而重发处理结果通知;

cookies、session等在此页面会失效,即无法获取这些数据;

该方式的调试与运行必须在服务器上,即互联网上能访问;

该方式的作用主要防止订单丢失,即页面跳转同步通知没有处理订单更新,它则去处理;

当商户收到服务器异步通知并打印出success时,服务器异步通知参数notify_id才会失效。也就是说在支付宝发送同一条异步通知时(包含商户并未成功打印出success导致支付宝重发数次通知),服务器异步通知参数notify_id是不变的。

支付宝APP支付大概就是这样子,不懂得可以留言我。

 

转载于:https://my.oschina.net/u/3387320/blog/2980801