在移动支付领域,支付宝支付占用巨大份额,根据艾瑞咨询公布的报告数据: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 pay(HttpServletRequest request, HttpServletResponse response) {

Map map = JsonPUtil.pToMap(request);

Map msgMap = new HashMap();

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 m = new HashMap();

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 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 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软件编程有所帮助。

android支付界面设计,Android支付宝支付设计开发相关推荐

  1. 支付宝支付 第一集:没有营业执照,怎样申请一个支付宝的商家号进行开发?使用支付宝支付开发网页移动应用,一分钟申请注册一个支付宝支付沙箱账号,支付宝支付入驻、创建应用、获取AppID

    支付宝支付 第一集:没有营业执照,怎样申请一个支付宝的商家号进行开发?使用支付宝支付开发网页&移动应用,一分钟申请注册一个支付宝支付沙箱账号,支付宝支付入驻.创建应用.获取AppID 一.资源 ...

  2. android如何实现支付宝,(Android集成支付宝支付)react-native实现支付宝支付

    网上关于RN的支付宝支付组件大部分都是IOS的,Android要实现支付宝支付只剩下走原生这一步了. 整体思路: 1.在蚂蚁金服开放平台申请应用 2.在android原生集成支付宝 3.封装andro ...

  3. android注册界面高级,Android用户注册界面简单设计

    本文实例为大家分享了Android用户注册界面的设计,供大家参考,具体内容如下 I. 实例目标 设计一个用户注册界面,在其中要使用到一些基础控件,如 文本框.编辑框.按钮.复选框等控件 II. 技术分 ...

  4. Android客户端三步完成支付宝支付SDK接入

    迁移最新版本 1.下载SDK 下载地址:https://doc.open.alipay.com/doc2/detail.htm?treeId=54&articleId=104509&d ...

  5. pay-spring-boot 开箱即用的Java支付模块,整合支付宝支付、微信支付

    关于 使用本模块,可轻松实现支付宝支付.微信支付对接,从而专注于业务,无需关心第三方逻辑. 模块完全独立,无支付宝.微信SDK依赖. 基于Spring Boot. 依赖Redis. 我能做什么 支付宝 ...

  6. 微信支付服务器错误,【支付问题】微信支付宝支付超时、支付异常解决办法

    微信支付宝支付异常解决办法 只要用户在手机上支付成功,钱一定会到商户的账户上. 只要用户在手机上支付成功,钱一定会到商户的账户上. 只要用户在手机上支付成功,钱一定会到商户的账户上. 正常情况下,用户 ...

  7. 支付API接口(支付宝支付接口微信支付接口)

    C#(文章随着实现而持续更新,各种产生都是个人遇到并且解决记录,有误地方请告示) 微信支付: 注意: MD5加密注意编码方式,默认使用GBK("GB2312"),因此MD5加密时, ...

  8. php 支付宝支付 简书,PHP支付宝支付的代码分享(TP3.2框架)(一)

    支付宝企业账户注册 注册完之后,进入账户,点击产品中心,点击"电脑网站支付",签署好协议. 产品中心-电脑网站支付 点进支付宝的蚂蚁金服开放平台 开发者中心-网页&移动应用 ...

  9. android登录界面扁平,Android EditText实现扁平化的登录界面

    先来看看登录界面写完的效果图 2 监听editText,可以一键清空 3 checkBox的颜色统一 代码 下面,说说如何实现这个界面的,我将代码全部贴出来. xmlns:app="http ...

  10. android 程序界面美化,Android性能优化之界面优化总结

    一.Android UI渲染机制 人眼所能感觉到流畅的画面,最佳帧数为60帧每秒.在Android中,系统通过VSYNC信号触发对UI的渲染以及重绘,间隔时间为16ms,其实就是1000ms内显示60 ...

最新文章

  1. mooc-IDEA 调试代码--012
  2. Session监听器
  3. Linux debian 11上安装 Google Chrome浏览器教程
  4. 基于java TCP实现网络通信聊天室《建议收藏附完整源码》
  5. 中国女排代言作业帮直播课,作业帮累计用户已超8亿
  6. Javascript中的内置对象:RegExp对象
  7. linux创建分区_在Linux中创建分区-分步指南
  8. 活动报名 | 无限视觉生成模型NUWA-Infinity,可生成超3万像素清明上河图
  9. java数字时钟代码_Java编程小实例—数字时钟的实现代码示例
  10. 计算机期刊在线阅读,2010年计算机领域SCI收录期刊
  11. PS修皮肤去痘痘毛孔,只需要掌握这个技巧就够了
  12. 计算机登录账户删除著名恢复,win10系统删除计算机无用账户的恢复步骤
  13. 二十岁、我的青春散场
  14. 「技术架构」技术风险管理权威指南
  15. [Lintcode]142. O(1) Check Power of 2
  16. 【优化指派】基于matlab禁忌搜索算法求解指派优化问题(耗时最短)【含Matlab源码 2518期】
  17. 超简单的HTML5圣诞树代码哦
  18. 微波技术在计算机的应用论文,计算机数据自动处理在微波实验中的应用.doc
  19. 纪念杰克韦尔奇:职业经理人怎么做变革
  20. 向爱康家园投稿:将“女排精神”发扬到工作中去

热门文章

  1. (二十四)优秀员工 - 6
  2. 金蝶KIS旗舰版基础档案资料建立,金蝶盘点机PDA仓库条码管理
  3. 有关Botton的用法(一)
  4. python autosub_9.1如何使用autosub自动生成音频视频字幕
  5. 平方的和与和的平方之差
  6. Android java.lang.IllegalArgumentException(...contains a path separator)
  7. 双转盘装配机,软件PRO7功能块版 由松下xh和威纶触摸屏制作
  8. 呼哈,很开心终于把我i自己写的一个wp8程序成功部署到手机上喽~~·
  9. docker19.03最新版本安装并配置加速器
  10. 小程序+动易SF制作随手拍实例全景式操作(2)