Android支付宝支付设计开发

在移动支付领域,支付宝支付占用巨大份额,根据艾瑞咨询公布的报告数据:2014Q3,支付宝斩获了82.6%的市场份额,在移动支付的霸主地位越来越稳固。财付通支付的发力点在微信支付和手Q支付,在移动支付格局中取得了10.0%的市场份额,排名第二。

支付宝在移动支付领域的统治地位,使得我们有必要梳理支付宝移动开发流程。本文写作的目的就是梳理支付流程,从架构层面讲述如何在移动应用中嵌入支付宝支付功能,以及指出哪些地方存在开发陷阱。

准备 
     按照说明,首先需要申请支付宝支付账号。这方面根据网站说明进行申请即可。一般需要2周左右的时间批准下来。

申请成功后账号信息包括 合作者身份ID partner, 卖家支付宝账号 seller_id,以及私钥 privateKey等。这三项将用于开发过程。

在官网上下载移动支付集成开发包。解压后, 发现其下包括三个文件夹(在英文Mac系统下文件名显示为乱码):

  • “商户接入支付宝收银台界面展示标准”:讲的是如何使用支付宝Logo。
  • “支付宝钱包支付接口开发包2.0标准版”:用于支付,包括客户端和服务器端开发。
  • “即时到账批量退款有密接口refund_fastpay_by_platform_pwd”:用于到账及批量退款,只需要服务器端操作处理。

后两个文件夹,都包括4方面内容:接口文档,接入与使用规则,demo代码,以及版本更新说明。
架构设计
首先,对于一个实际的App应用而言,可能会包括多种支付方式,因此可以采用设计模式中的策略Strategy模式来设计支付功能模块,支付宝支付作为其中的一个策略,pay方法是支付算法。
如果除了支付方式payment method变化,订单order也可能会有不同的形式,如格式可能不同,有些支持可退款,有的不允许退款等,在这种多维度可变的情况下,支付模块的架构可以基于桥接模式。
其次,可以把支付宝支付的各个操作步骤,比如获取订单号,生成订单数据,进行支付,获取支付结果,处理异常等操作,根据状态进行划分。这样采用状态模式,提供设计的灵活性和扩展性。另外也可以设计状态机进行统一的状态切换管理。下面为参考代码:

public class PayStateMachine {
  /* all possible state of payment */
  public enum PayState { PAY_INIT, PAY_GOT_CONTEXT, PAY_UPDATED_ORDER, PAY_APPLIED_
   ID, PAY_ORDER_CREATED, PAY_SUCCEED, ERROR_OCCURRED}

  /* errors may occurred during payment */
  public enum PayError {
    PAY_GET_CONTEXT_FAIL, PAY_UPDATE_ORDER_FAIL, PAY_APPLY_ID_FAIL, PAY_FAIL
  }

  private static PayStateMachine instance;
  private PayState state;
  private IOrder order;
  private IPayment payment;

  private PayStateMachine() {
  }

  public static PayStateMachine getInstance() {
    if (instance == null) {
      instance = new PayStateMachine();
    }

    return instance;
  }

  public void initPayment(IOrder order, IPayment payment) {
    this.order = order;
    this.payment = payment;
    this.state = PayState.PAY_INIT;
  }

  public void startPay() {
    changeState(PayState.PAY_INIT);
  }

  public void changeState(PayState state) {
    onStateChanged(this.state, state);
  }

  public void reportError(PayError error, String detail) {
    LogUtil.printPayLog("the error id is:" + error + " " + detail);
    changeState(PayState.ERROR_OCCURRED);
  }

  private void onStateChanged(PayState oldState, PayState newState) {
    LogUtil.printPayLog("oid state:" + oldState + " new state:" + newState);
    this.state = newState;

    handlePayStateChange();
  }

  private void handlePayStateChange() {
    if (this.order == null || this.payment == null) {
      LogUtil.printPayLog("Have not initiated payment");
      return;
    }

    switch (this.state) {
      case PAY_INIT:
        order.getPayContext();
        break;
      case PAY_GOT_CONTEXT:
        order.createOrder();
        break;
      case PAY_UPDATED_ORDER:
      case PAY_APPLIED_ID:
      case PAY_ORDER_CREATED:
        payment.pay(order);
        break;

      case PAY_SUCCEED:
      case ERROR_OCCURRED:
        finishProcess();
        break;
      default:
        LogUtil.printPayLog("state is not correct!");
        finishProcess();
     }
  }

  private void finishProcess() {
    this.order = null;
    this.payment = null;
    this.state = PayState.PAY_INIT;
  }
}

最后,订单类层次可以参考模板模式来设计,例如抽象基类负责定义订单的操作框架和流程,具体订单数据的生成延迟到子类中实现。

支付流程
本文针对Android版进行讲解主要的支付流程,IOS版流程类似。
1、客户端实现
本文结合操作流程和数据流程,讲述主要的实现方案。
首先假设订单数据都已经存储在OrderPayModel中。
第一步:App客户端访问应用服务器,后者生成订单编号并返回客户端。

private void getOrderIdRequest() {
 JSONObject ob = new JSONObject();
 ob.put("amount", orderPayModel.getOrderPriceTotal());

 ob.put("productDescription", orderPayModel.getOrderName());

 ob.put("userId", orderPayModel.getUserId());
 ob.put("barCoupon", orderPayModel.getOrderId());
 ob.put("barId", orderPayModel.getBarId());
 ob.put("count", orderPayModel.getOrderNums());
 LogUtil.printPayLog("get order id request data:"
  + orderPayModel.toString());

 HttpRequestFactory.getInstance().doPostRequest(Urls.ALI_PAY_APPLY, ob,
  new AsyncHttpResponseHandler() {

   @Override
   public void onSuccess(String content) {
   super.onSuccess(content);

   LogUtil.printPayLog("get order id request is handled");

   PayNewOrderModel rm = new PayNewOrderModel();
   rm = JSON.parseObject(content, PayNewOrderModel.class);

   if (rm.getCode() != null
    && "200".equalsIgnoreCase(rm.getCode())) {
    tradeNo = rm.getResult().getTrade_no();
    LogUtil.printPayLog("succeed to get order id:"
     + tradeNo);

    orderStr = generateOrder();
    PayStateMachine.getInstance().changeState(
     PayState.PAY_APPLIED_ID);

   } else {
    PayStateMachine.getInstance().reportError(
     PayError.PAY_APPLY_ID_FAIL,
     "code is not right");
   }
   }

   @Override
   public void onFailure(Throwable error, String content) {
   PayStateMachine.getInstance().reportError(
    PayError.PAY_APPLY_ID_FAIL,
    "failed to get order id");

   };

   @Override
   public void onFinish() {
   LogUtil.LogDebug("Payment", "on get order id finish",
    null);

   };
  });
 }

第二步:组装订单数据,包括以下几个子步骤:
创建订单数据。

private String getOrderInfo(String partner, String seller) {
 String orderInfo;

  // 合作者身份ID
  orderInfo = "partner=" + "\"" + partner + "\"";

  // 卖家支付宝账号
  orderInfo += "&seller_id=" + "\"" + seller + "\"";

  // 商户网站唯一订单号
  orderInfo += "&out_trade_no=" + "\"" + tradeNo + "\"";

  // 商品名称
  orderInfo += "&subject=" + "\"" + orderName + "\"";

  // 商品详情
  orderInfo += "&body=" + "\"" + orderDetail + "\"";

  // 商品金额
  orderInfo += "&total_fee=" + "\"" + totalPrice + "\"";
  // orderInfo += "&total_fee=" + "\"" + "0.01" + "\"";

  // 服务器异步通知页面路径
  orderInfo += "¬ify_url=" + "\"" + Urls.ALI_PAY_NOTIFY + "\"";

  // 接口名称, 固定值
  orderInfo += "&service=\"mobile.securitypay.pay\"";

  // 支付类型, 固定值
  orderInfo += "&payment_type=\"1\"";

  // 参数编码, 固定值
  orderInfo += "&_input_charset=\"utf-8\"";

  // 设置未付款交易的超时时间
  // 默认30分钟,一旦超时,该笔交易就会自动被关闭。
  // 取值范围:1m~15d。
  // m-分钟,h-小时,d-天,1c-当天(无论交易何时创建,都在0点关闭)。
  // 该参数数值不接受小数点,如1.5h,可转换为90m。
  orderInfo += "&it_b_pay=\"30m\"";

  // 支付宝处理完请求后,当前页面跳转到商户指定页面的路径.
  // orderInfo += "&return_url=\"m.alipay.com\"";
  // Bill: this item must not be empty! though the api demo said it
  // can be.
  orderInfo += "&return_url=\"m.alipay.com\"";

  // 调用银行卡支付,需配置此参数,参与签名, 固定值
  // orderInfo += "&paymethod=\"expressGateway\"";
 }

 return orderInfo;
 }
  • 对订单做RSA签名:  demo代码中提供SingUtils类实现该功能,即SignUtils.sign(content, RSA_PRIVATE);
  • 对签名做 URL编码:  调用java类库接口,即URLEncoder.encode来实现。
  • 将订单数据和签名信息组合,生成符合支付宝参数规范的数据: 
final String payInfo = orderInfo + "&sign=\"" + sign + "\"&" + getSignType();

第三步:在子线程里调用PayTask的pay接口,将请求数据发送出去

PayTask alipay = new PayTask(PayDemoActivity.this);
// 调用支付接口,获取支付结果
String result = alipay.pay(payInfo);

第四步:收到支付处理结果的消息。支付结果的状态码的意义如下:

  •   值为“9000”,代表支付成功;
  •     值为“8000”,代表等待支付结果确认,这可能由于系统原因或者渠道支付原因。支付的最终结果需要由服务器端的异步通知为准(支付宝将向)。
  •     值为其他,代表失败。客户端需要提示用户。

注意事项:
1、本文特别需要指出的是,也就是最容易出问题的就是订单数据的生成。在demo代码的 PayDemoActivity类中,定义了getOrderInfo方法。 其中“orderInfo += "&return_url=\"m.alipay.com\"”;”在该demo代码的注释中,虽然说是可以为空,但实际情况,如果为空,将导致支付失败。而且凭借失败状态码,难以识别具体原因。
2、支付结果,除了支付宝服务器发通知到客户端外,也会异步通知应用服务器。考虑到安全性,客户端可以根据支付宝服务器的通知,进行商业逻辑的处理,比如订单更新等,但是支付的数据入库,需要由应用服务器端根据异步通知进行操作。
2、服务端实现
服务端基本操作包括:获取支付宝账号信息(为了安全,该信息放置在服务器,而不是客户端),创建订单,支付结果异步回调,申请退款等基本操作外。另外也可能包括:更新订单(对于支持订单可修改的应用),验证消费码,查询订单记录,删除订单等操作。
本文介绍基于Java平台的服务器方案。目前比较流行的框架组合是SpingMVC+Mybatis+Mysql。
订单的创建。当用户下订单时,如果是新订单(请求的数据没有包括订单编号信息),需要创建,并返回订单号给客户端。订单类示例:

public class PayOrder {

 public String tradeNo;   //随机编号
 public String amount;   //付款金额
 public String status;   //操作状态
 public String statusCode;   //操作状态代码,0-未支付,10-已支付,4000-退款中,5000-已退款,6000-付款失败,6001-取消付款,7000-已消费
 public String orderNo;   //支付宝流水号
 public String productDescription;  //商品名称
 public String payNo;   //消费码
 public String isRefund;   //是否申请退款
 public String createTime;   //创建时间
 public String modifyTime;   //修改时间
 public String userId;   //用户id
 public Integer id;    //主键
 public String pId;    //商品id
 public int buyNumber;    //存储购买数量
 public int vendorId;    //商家ID
}
tradeNo代码订单编号。payNo代码消费编号(消费码)。orderNo是支付宝服务器端生成的订单号。
@RequestMapping(value = "/payorder")
@ResponseBody
public Map<String, Object> pay(HttpServletRequest request, HttpServletResponse response) {
 Map<String, Object> map = JsonPUtil.pToMap(request);
 Map<String, Object> msgMap = new HashMap<String, Object>();
 if (!map.isEmpty()) {
 try {
  log.info("执行购买前确认操作:" + map);
  String now = String.valueOf(System.currentTimeMillis());
  String trade_no = map.get("barId").toString() + "-" + map.get("barCoupon").toString() + "-" + map.get("count").toString() + "-" + now.substring(now.length() - 6);

  PayOrder alipay = new PayOrder();
  alipay.setAmount(map.get("amount").toString());
  alipay.setTradeNo(trade_no);
  alipay.setProductDescription(map.get("productDescription").toString());
  alipay.setCreateTime(now);
  alipay.setStatus("待支付");
  alipay.setStatusCode("0");
  alipay.setExtInt1(Integer.parseInt(map.get("count").toString()));
  alipay.setUserId(map.get("userId").toString());
  alipay.setpId(map.get("barCoupon").toString());
  alipay.setExtInt2(Integer.parseInt(map.get("barId").toString()));

  int flag = alipayServiceImpl.pay(alipay);
  log.info("确认操作执行结果:" + flag);

  Map<String, Object> m = new HashMap<String, Object>();
  m.put("trade_no", trade_no);
  m.put("seller", new String(Base64.encode(AlipayConfig.SELLER.getBytes())));
  m.put("partner", new String(Base64.encode(AlipayConfig.partner.getBytes())));
  m.put("privateKey", new String(Base64.encode(AlipayConfig.ios_private_key.getBytes())));

  if (flag > 0)
  msgMap = ResponseMessageUtil.respMsg(Constance.BASE_SUCCESS_CODE, "success", m);
  else
  msgMap = ResponseMessageUtil.respMsg(Constance.BASE_SERVER_WRONG_CODE, "fail");
 } catch (Exception e) {
  e.printStackTrace();
  msgMap = ResponseMessageUtil.respMsg(Constance.BASE_SERVER_WRONG_CODE, "fail");
  log.error("购买前确认失败", e);
 }
 } else {
 log.info("请求参数不完整");
 msgMap = ResponseMessageUtil.respMsg(Constance.ILLEGAL_OPERATE, "fail");
 }
 return msgMap;
}

支付宝服务器回调App服务器,通知支付结果。App服务器将相应的数据入库后,通知支付宝服务器"success" or "fail"。

@RequestMapping(value = "/payOver")
 @ResponseBody
 public String payOver(HttpServletRequest request, HttpServletResponse response) {
 Map<String, String> map = JsonPUtil.buildMap(request);
 String result_str = "fail";
 if (!map.isEmpty()) {
  if (AlipayUtils.checkAlipay(map, false) > 0) {// 通过支付宝验证
  try {
   log.info("执行付款的回调函数传递参数:" + map);
   String now = String.valueOf(System.currentTimeMillis());
   String status = map.get("trade_status").toString();
   PayOrder alipay = new PayOrder();
   alipay.setTradeNo(String.valueOf(map.get("out_trade_no")));
   log.info("支付状态:" + status);
   if (Constance.ALIPAY_SUCCESS_CODE.equals(status) || Constance.ALIPAY_FINISHED_CODE.equals(status)) {// 支付成功
   List<Alipay> ali = alipayServiceImpl.search(alipay);
   if (ali.size() == 1 && (ali.get(0).getPayNo() == null || ali.get(0).getPayNo().equals(""))) {// 消息未处理
    Alipay pay = new Alipay();
    pay.setTradeNo(String.valueOf(map.get("out_trade_no")));
    pay.setStatus("已支付");
    pay.setStatusCode("10");
    pay.setIsRefund("0");
    pay.setModifyTime(String.valueOf(System.currentTimeMillis()));
    pay.setPayNo(new String(Base64.encode(now.substring(now.length() - 10).getBytes())));
    pay.setOrderNo(String.valueOf(map.get("trade_no")));
    int flag = alipayServiceImpl.payOver(pay);
    log.info("用户付款成功" + map);
    if (flag > 0)
    result_str = "success";
   }
   } else {
   return result_str;
   }
  } catch (Exception e) {
   e.printStackTrace();
   log.error("回调函数获取参数失败", e);
   return result_str;
  }
  }
 }
 return result_str;
 }

以上就是基于Android支付宝支付设计和开发方案,希望对大家学习Android软件编程有所帮助。

(0)

相关推荐

  • Android仿支付宝支付从底部弹窗效果

    我们再用支付宝支付的时候,会从底部弹上来一个对话框,让我们选择支付方式等等,今天我们就来慢慢实现这个功能 效果图 实现 主界面很简单,就是一个按钮,点击后跳到支付详情的Fragment中 package com.example.hfs.alipayuidemo; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.wi

  • Android支付宝支付的示例代码

    上一篇,我们已经详细讲解了Android微信支付,今天接着为大家带来支付宝支付,支付宝支付相对微信支付要简单一些,吐槽一下,而且支付宝文档确实比微信的文档好了不少,下面开始讲解支付流程. 1.首先给出官方文档的地址 Android集成支付宝流程 2.在开始集成和开发前,首先了解一下常用的接入方式和架构建议: 支付流程.png 在开始下一步之前,给大家看看网上的很多操作. 网上的代码.png 这一大堆代码,后面还有,百来行吧,而且支付宝Demo貌似也是这么干的,估计一些新司机就有点懵逼了,至于吗?

  • Android支付宝支付封装代码

    在做Android支付的时候肯定会用到支付宝支付, 根据官方给出的demo做起来非常费劲,所以我们需要一次简单的封装. 封装的代码也很简单,就是将官网给的demo提取出一个类来方便使用. public class Alipay { // 商户PID public static final String PARTNER = "123456789"; // 商户收款账号 public static final String SELLER = "qibin0506@gmail.co

  • Android app第三方支付宝支付接入教程

    支付宝的接入相对比较简单,看看支付宝官网的文档基本都能搞定,但是切记一点让你们的后台也要搞清楚支付宝的流程,重中之重. 1.注意事项 开发前一定要阅读支付宝官方文档 强烈建议签名等处理在后台处理,我这个是测试是在自己本地写的,不要吐槽 想获取支付宝合作商户ID,及支付宝公钥请点击支付宝链接,生成密钥及PKCS8转码工具在文档中 添加Android.permission.INTERNET权限和android.permission.ACCESS_NETWORK_STATE权限 要导入支付宝的包 2.

  • Android接入支付宝实现支付功能实例

    我本来是想直接讲Android支付这一块的,包括支付宝,微信,其他第三方整合支付等,但是微信开放平台他对我的账号做了限制,所有我今天就先把重心放在支付宝的支付上,也算是写得尽可能详细些吧,毕竟是第三方的SDK,只要我们耐心的阅读文档和开发引导,这个其实不是很难的,我也是没有用过支付宝的支付,但是我相信,你看完这篇博客,也会对他了如指掌的,好的,我们正文开始 一.准备步骤 1.登录官网 他的官网就是蚂蚁金服的开放平台了,我们可以访问 蚂蚁金服开放平台 ,并且注册账号进行登录 创建应用 如果你是现有

  • Android支付宝和微信支付集成

    场景 随着移动支付的兴起,在我们的app'中,会经常有集成支付的需求.这时候一般都会采用微信和支付宝的sdk 来集成 (一)支付宝支付 在使用支付宝支付的过程中,我们是在服务器端生成订单,客户端访问接口,并得到订单信息,调用接口支付,支付成功后支付宝会分别 异步调用服务器端,并向客户端返回支付结果. 开发步骤: ①注册支付宝账号--进行实名认证--提交审核资料--审核通过 支付宝无线快捷支付接口: b.alipay.com/order/productDetail.htm?productId=20

  • Android仿支付宝支付密码输入框

    本文实例为大家分享了Android实现一个仿支付宝支付密码的输入框,主要实现如下: PasswordView.java package com.jackie.alipay.password; import android.annotation.TargetApi; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphic

  • Android支付宝支付设计开发

    在移动支付领域,支付宝支付占用巨大份额,根据艾瑞咨询公布的报告数据:2014Q3,支付宝斩获了82.6%的市场份额,在移动支付的霸主地位越来越稳固.财付通支付的发力点在微信支付和手Q支付,在移动支付格局中取得了10.0%的市场份额,排名第二. 支付宝在移动支付领域的统治地位,使得我们有必要梳理支付宝移动开发流程.本文写作的目的就是梳理支付流程,从架构层面讲述如何在移动应用中嵌入支付宝支付功能,以及指出哪些地方存在开发陷阱. 准备       按照说明,首先需要申请支付宝支付账号.这方面根据网站说

  • Android 支付宝支付、微信支付、银联支付 整合第三方支付接入方法(后台订单支付API设计)

    客户端获取后台支付API请求参数的设计 参数样例: { data: { method: 1, platform: 1, version:"1.0", relate_orders:"B201602031023,B2016020310231", order_no: "BZY201604200952100", order_type: 1, total_fee: 1, description: "商品购买", client_ip:'1

  • java对接支付宝支付接口开发详细步骤

    目录 第一步 第二步 第三步 第四步 对接支付宝支付接口,官方文档已经写的很清楚了,但是也有很多像我一样的小白,第一次对接支付宝支付接口,会有些迷茫,所以我在此写下这篇文章,给我和我一样的同学,一点思路吧. 第一步 (先要在支付宝进行操做,拿到我们需要开发的信息后在动代码) 进入蚂蚁金服,我们先要创建应用 看到图下的应用按钮了吗? 点击应用(如下图) 创建应用(创建应用需要审核)提供资料审核吧,这个时候我们就不用管他了.审核通过就可以用了. 但是他审核我们也不能闲着着 ,我们先弄个测试把代码写出

  • Android支付宝支付开发实例

    在移动应用满天飞的时代,随着移动支付的盛行,很多应用中都集成了支付功能.之前的支付一直不是我负责,近期这个项目我负责订单模块少不了要做支付,每每提起支付就觉得怕怕,觉得很难,但当真正做的时候却远远没有想象中的那么难.支付宝的SDK提供了demo,我们只需要配置好一些基本信息,这个demo就可以正常支付.说了这么多,我们还是来看看完整的集成步骤吧! 1.首先得申请支付宝的商家用户,并签约支付宝的相关服务. 移动支付肯定是需要签约 移动支付 了,好像是废话. 2.支付宝商家账号有了之后就好办了,去支

  • Android App支付系列(二):支付宝SDK接入详细指南(附官方支付demo)

    一家移动互联网公司,说到底,要盈利总是需要付费用户的,自己开发支付系统对于资源有限的公司来说显然不太明智,国内已经有多家成熟的移动支付提供商,阿里就是其中之一. 笔者在此总结了下阿里旗下支付宝Android SDK支付的接入流程,供后来者参考. 接入流程如下: 1 签约成为支付宝商户 签约地址:https://b.alipay.com/, 只有成为签约商户的开发者才能具备集成支付宝app支付的资格. 签约资料:1)营业执照 2)APP说明文档 3)商户经营信息.商户联系人等信息 必要时还需提供A

  • Android自定义View实现支付宝支付成功-极速get花式Path炫酷动画

    本文手把手教你图片->SVG->Path的姿势.. 从此酷炫Path动画,如此简单. 效果先随便上几个图,以后你找到的图有多精彩,gif就有多精彩: 随便搜了一个铅笔画的图,丢进去 随手复制的二维码icon 来自大佬wing的铁塔 前文回顾 这里简单回顾一下前文,GIF如下图: PathAnimView接受的唯一数据源是Path(给我一个Path,还你一个动画View) 所以内置了几种将别的资源->Path的方法: 直接传string.(A-Z,0-9 "." &qu

随机推荐