网站设计模板免费建站,凡科建站快车登录,新闻发稿114,新手怎么开传媒公司背景 在移动支付领域#xff0c;支付宝支付占用巨大份额#xff0c;根据艾瑞咨询公布的报告数据#xff1a;2014Q3#xff0c;支付宝斩获了82.6%的市场份额#xff0c;在移动支付的霸主地位越来越稳固。财付通支付的发力点在微信支付和手Q支付#xff0c;在移动支付…背景 在移动支付领域支付宝支付占用巨大份额根据艾瑞咨询公布的报告数据2014Q3支付宝斩获了82.6%的市场份额在移动支付的霸主地位越来越稳固。财付通支付的发力点在微信支付和手Q支付在移动支付格局中取得了10.0%的市场份额排名第二。 支付宝在移动支付领域的统治地位使得我们有必要梳理支付宝移动开发流程。本文写作的目的就是梳理支付流程从架构层面讲述如何在移动应用中嵌入支付宝支付功能以及指出哪些地方存在开发陷阱。 准备 首先支付宝SDK下载主页的地址是https://b.alipay.com/order/productDetail.htm?productId2013080604609654tabId4#ps-tabinfo-hash。这个地址隐藏很深所以这里有必要指出。 按照说明首先需要申请支付宝支付账号。这方面根据网站说明进行申请即可。一般需要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版流程类似。从操作角度看支付流程操作2调用支付接口和操作7接口返回支付结果App与支付宝API的交互。 操作5异步发送支付通知支付宝服务器与App后台的交互。 从数据流角度看支付流程 客户端实现 本文结合操作流程和数据流程讲述主要的实现方案。 首先假设订单数据都已经存储在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() {Overridepublic 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);}}Overridepublic void onFailure(Throwable error, String content) {PayStateMachine.getInstance().reportError(PayError.PAY_APPLY_ID_FAIL,failed to get order id);};Overridepublic void onFinish() {LogUtil.LogDebug(Payment, on get order id finish,null);};});}第二步组装订单数据包括以下几个子步骤 创建订单数据。private String getOrderInfo(String partner, String seller) {String orderInfo;// 合作者身份IDorderInfo 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分钟一旦超时该笔交易就会自动被关闭。// 取值范围1m15d。// 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”代表等待支付结果确认这可能由于系统原因或者渠道支付原因。支付的最终结果需要由服务器端的异步通知为准支付宝将向。 值为其他代表失败。客户端需要提示用户。 注意事项 本文特别需要指出的是也就是最容易出问题的就是订单数据的生成。在demo代码的 PayDemoActivity类中定义了getOrderInfo方法。 其中“orderInfo return_url\m.alipay.com\”;”在该demo代码的注释中虽然说是可以为空但实际情况如果为空将导致支付失败。而且凭借失败状态码难以识别具体原因。 支付结果除了支付宝服务器发通知到客户端外也会异步通知应用服务器。考虑到安全性客户端可以根据支付宝服务器的通知进行商业逻辑的处理比如订单更新等但是支付的数据入库需要由应用服务器端根据异步通知进行操作。 服务端实现 服务端基本操作包括获取支付宝账号信息为了安全该信息放置在服务器而不是客户端创建订单支付结果异步回调申请退款等基本操作外。另外也可能包括更新订单对于支持订单可修改的应用验证消费码查询订单记录删除订单等操作。 本文介绍基于Java平台的服务器方案。目前比较流行的框架组合是SpingMVCMybatisMysql。 订单的创建。当用户下订单时如果是新订单请求的数据没有包括订单编号信息需要创建,并返回订单号给客户端。订单类示例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; //用户idpublic Integer id; //主键public String pId; //商品idpublic int buyNumber; //存储购买数量public int vendorId; //商家ID
} tradeNo代码订单编号。payNo代码消费编号消费码。orderNo是支付宝服务器端生成的订单号。 RequestMapping(value /payorder)
ResponseBody
public MapString, Object pay(HttpServletRequest request, HttpServletResponse response) {MapString, Object map JsonPUtil.pToMap(request);MapString, Object msgMap new HashMapString, 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);MapString, Object m new HashMapString, 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);elsemsgMap 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)ResponseBodypublic String payOver(HttpServletRequest request, HttpServletResponse response) {MapString, 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)) {// 支付成功ListAlipay 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;}