tyle="margin:20px 0px 0px; line-height:26px; font-family:Arial">

在这些服务中,服务类型大致可以分为以下几类:

  1. WebService查询服务:

    通过服务器后台发起一个http请求,然后从服务器上返回一个Xml类型的返回结果。比如,user_query 服务,支付宝id 或者支付宝的账户email通过服务器后台查询一个支付宝会员信息。

  2. 带有页面跳转的交互服务:

    用户在实现一个web功能的过程中需要调用到支付宝的几个web页面作为,服务流程中的一部分。比如,user_authentication服务需要调用支付宝的一个用户认证页面。Custome_sign 需要使用支付的代扣协议签订页面。

    另外,在支付宝协作页面跳转回原页面的时候,需要对参数签名进行验证,或者对notifyId进行验证是否是合法的web回调请求。

    2.业务场景分析

现在支付宝提供的这些服务接口,调用端只能通过查询支付宝提供api文档,通过api文档进行接口开发。

偶在开发口碑卡项目中需要用到user_query,user_authentication,customer_sign等支付宝服务,以前,口碑的业务也有调用过支付宝的接口,于是我就想重用以前其他同学已经写过的调用支付宝服务的代码。结果发现,有很多参数已经写死了,比如key,partnerid,还有sign的算法。所以代码根本没有办法重用,只能ctrl+C加ctrl+V,而且我在开发过程中为了解决参数签名匹配不上的问题搞了很长时间。

所以,我认为应该开发一个类似淘宝TOP平台提供的API代码接口,这个api接口的开发难度比淘宝open api 应该简单,因为,在和支付宝交互的数据结构比较简单。

2.1.Api所要实现的目标

解决参数签名,调用支付宝服务过程中,参数签名的作用是保证用户请求的参数没有被黑客截取篡改参数值,在所有的请求中都会有参数签名。为了代码实现简单,先默认参数签名方式为MD5签名。参数签名应该像面向切面编程一样,在开发一个具体的结果过程中程序员不用关心参数签名,这也是做这个框架的重要意义所在。当初,我照着api文档的时候为了参数签名真是折腾了好长时间,为了避免其他同学重蹈我的覆辙。必须要将参数签名封装成一个模块能够重复调用。

2.2.支持多种字符集

这个API框架能够在多种字符集环境下使用,所以这个框架要能够支持UTF8,GBK等多种环境,只需要简单配置就能切换。

2.3.新功能容易扩充

现在实现的接口还只是支付宝提供的所有web服务中的小部分,但是已经涵盖到了所有前面提到的所有种类的服务(服务器后台请求,协同页面),如果想通过此框架实现其余的页面只需要实现少部分代码就能实现功能。

3. 实现

3.1.整体类图

3.2.核心类

3.2.1 BasicAlipayToolkit

该类是所有支付宝服务的基类,他提供了一些所有服务接口都要调用的方法。

方法有:

  • urlEncode()

    将传输的值进行编码,按照GBK或者UTF8或者其他编码格式进行编码。

  • sign()

    将传输的参数集合进行签名

  • getPartner()

    取得支付宝分配给用户的partnerid

3.2.2.AlipayApply

支付宝的所有web服务都是通过http协议请求发送的,通过这个类可以通过用户设置的一些基本的参数组装出发送给支付宝的http的url,如果当请求是在页面中需要使用标签<form>来发送的话,就可以通过buildSubmitForm方法生成一个html的form表单。

这些方法有:

  •  prepareParamMap()

    将除partner,_input_charset,service参数字段放到map的数据结构中。

  •  buildSubmitForm()

    创建出一个from表单,可以在html页面中使用,用于在想支付宝发起请求。

  •  getPayGateWay()

    取得支付宝请求地址,如https://www.alipay.com/cooperate/gateway.do

  •  buildHref()

    取得向支付宝请求的url。

3.2.3 BasicWebServiceApply

  • getMapResult()

    解析支付宝远端的返回的XML结果,封装成一个pojo对象。

  • getValueElementName()

    设置支付宝返回结果中代表结果值的xml节点名称。

  • createResult()

    创建一个远端结果对象。

  • resultCallback()

    返回一个结果之后设置返回结果对象的值。

3.2.4 Profile,DefaultProfile

支付宝服务请求的用户信息封装,能够取到PartnerId和getGateway,不同的用户需要通过调用。

[java]  view plain copy

 
  1. Profile profile = new DefaultProfile("adfasdfasdq24234sdf3434","http://aliapi.alipay.net/gateway.do"
  2. ,"2088101010199999");
  3. BasicAlipayToolkit.setProfile(profile);

3.3. 时序图分析

支付宝提供了两种服务,webService和页面协作,根据两种服务类型,选取两个服务分析一下服务的流程。

3.3.1 user_query服务

  1. 单元测试Test启动,调用BasicAlipayToolkit的静态方法setProfile()设置连接需要用到的key,gateway,和partnerid
  2. 调用者设置查询参数,然后调用getAlipayPojo方法,向支付宝发起查询请求。
  3. 支付宝返回查询结果对象AlipayQuery调用getMapResult()生成查询结果
  4. 封装查询结果的过程中先要生成包装查询结果的对象。
  5. 创建查询结果
  6. 根据支付宝返回的结果设置查询结果是否成功
  7. 如果查询有错误的话设置错误编码
  8. 没够成功拿到查询结果,设置查询结果对象的属性值

3.4. 功能说明

3.4.1.支付宝会员登陆验证

用户需要通过支付宝认证用户信息,代码如下:

[java]  view plain copy

 
  1. AlipayAuthenticateCooperate  cooperate =  return new AlipayAuthenticateCooperate(
  2. "http://localhost/callbackUrl.html",
  3. CharSet.GBK);

在页面上打印超链接

[xhtml]  view plain copy

 
  1. <a href="<s:property escape="false" value="alipayAuthenticateCooperate.buildHref()" />">支付宝认证登录</a>

在页面上打印一个form表单

[xhtml]  view plain copy

 
  1. <s:property  escape="false" value="alipayAuthenticateCooperate.buildSubmitForm(‘提交’)" />

当用户在支付宝用户认证之后,跳转到原网站页面,需要取得支付宝会员信息:

[java]  view plain copy

 
  1. HttpServletRequest request = ServletActionContext.getRequest();
  2. AlipayAuthenticateCallback authenticateCallback = new AlipayAuthenticateCallback(
  3. CharSet.UTF8);
  4. AlipayResult alipayResult = authenticateCallback
  5. .getAlipayResult(request.getParameterMap());
  6. if (!alipayResult.isSuccess()) {
  7. throw new BizException("alipayResult is false,error code:"
  8. + alipayResult.getErrorCode() + "request url:["
  9. + request.getQueryString() + "]");}
  10. String alipayid = alipayResult.getUserid();
  11. AlipayAccount account = new AlipayAccount(alipayid, bizContext);
  12. account.setAccountId(alipayid + "0156");
  13. account.setEmail(alipayResult.getEmail());
  14. account.setMobile(alipayResult.getMobile());

注意:在使用该服务api代码必要代码中设置的CharSet需要和当前tomcat URLencode要一致,否则,跳转会原页面会有sign不一致的问题。

3.4.2. 即时到帐

在页面中要发起一个即时到帐的请求,代码如下:

[java]  view plain copy

 
  1. AlipayPayment patment =  return new AlipayPayment("mozhenghua19811109@126.com",
  2. "http://localhost/return_url.html",
  3. "http://localhost/notify_url.html",
  4. "http://localhost/showurl.html",
  5. "123456", // out_trade_no
  6. 12f, //单价
  7. 3,//数量
  8. CharSet.GBK,
  9. Configuration.GetConfig("sellerEmail")// 卖家email账户
  10. );
  11. // 设置跳转的url
  12. action.setRedirectUrl(String.valueOf(payment.buildHref()));

用户在支付宝完成即时到帐功能之后跳转到原页面

[java]  view plain copy

 
  1. import com.koubei.kac.alipaytaobaocooperate.CallbackValidate;
  2. llbackValidate validate = new CallbackValidate();
  3. HttpServletRequest request = ServletActionContext.getRequest();
  4. // 判断url sign 是否正确
  5. if (!validate.isValidCallbackApply(request.getParameterMap())) {
  6. getLog().error(
  7. "is invalid callback request from alipay notfiyid:"
  8. + this.getNotify_id()
  9. + " out_trade_no[delivery_detail PK]:"
  10. + this.out_trade_no);
  11. // 跳转到错误页面
  12. return getErrorResult();
  13. }
  14. if (!validate.isValidNotify(this.notify_id)) {
  15. getLog().error(
  16. "not valid notifyid, notify_id:" + this.notify_id
  17. + " out_trade_no:" + out_trade_no
  18. + " trade_status:" + trade_status);
  19. // 非法请求跳转到错误页面
  20. return getErrorResult();
  21. }

3.4.3.CAE代扣协议

[java]  view plain copy

 
  1. CAEAlipayCooperate cooperate =
  2. return new CAEAlipayCooperate(
  3. "http://localhost/callback.html",
  4. "http://localhost/notify.html",
  5. "mozhenghua19811109@126.com", "CAE业务提交", CharSet.UTF8,bizCode
  6. );
  7. cooperate. buildHref();//生成cae代扣协议的url
  8. // 结果:
  9. /**
  10. http://aliapi.alipay.net/gateway.do?sign_type=MD5&sign=d78ce0c98deabe389c0b05dabc1ae1c9&_input_charset=utf-8&customer_email=mozhenghua19811109%40<br />
  11. 126.com&notify_url=http%3A%2F%2Fhangzhou.koubei.com%2Fka%2Fnotify.html&service=customer_sign&partner=2088101010199999&type_code=123456&return_url<br />
  12. =http%3A%2F%2Fhangzhou.koubei.com%2Fka%2Fcallback.html
  13. */
  14. cooperate.buildSubmitForm();//生成cae代扣协议提交的form表单
  15. //结果:
  16. /**
  17. <form  method="post" action="http://aliapi.alipay.net/gateway.do?_input_charset=utf-8">  <input type="hidden" name="_input_charset" value="utf-8" /><br />
  18. <input type="hidden" name="customer_email" value="mozhenghua19811109@126.com" /><br />
  19. <input type="hidden" name="notify_url" value="http://localhost/notify.html"/><br />
  20. <input type="hidden" name="service" value="customer_sign" /><br />
  21. <input type="hidden" name="partner" value="2088101010159999" /><br />
  22. <input type="hidden" name="type_code" value="123456" /><br />
  23. <input type="hidden" name="return_url" value="http://localhost/callback.html" /><br />
  24. <input type="hidden" name="sign" value="d78ce0c98deabe389c0b05dabc1ae1c9" />  <input type="hidden" name="sign_type" value="MD5" /> <input class<br />
  25. ="submitBtn" type="submit"  value="CAE业务提交"/> </form>
  26. */

用户完成支付宝代扣协议跳转到口碑页面

[java]  view plain copy

 
  1. HttpServletRequest request = ServletActionContext.getRequest();
  2. CallbackValidate validate = new CallbackValidate();
  3. boolean isValidApply = validate.isValidCallbackApply(request
  4. .getParameterMap(), new CallbackValidate.KeyIgnorJudgement() {
  5. @Override
  6. public boolean ignor(String key) {
  7. return "sign".equalsIgnoreCase(key)
  8. || "sign_type".equalsIgnoreCase(key)
  9. || "action".equalsIgnoreCase(key);
  10. }
  11. });
  12. // 非法请求
  13. if (!isValidApply) {
  14. return ERROR;
  15. }
  16. // 测试该请求是否合法
  17. boolean isSuccess = "T".equalsIgnoreCase(request
  18. .getParameter("is_success"));
  19. if (!isSuccess) {
  20. return "caesingerror";
  21. }

如果你需要源代码,请点击下载 http://vdisk.weibo.com/s/8C6k,如果有任何疑问请发邮件,baisui@taobao.com

支付宝api指南的更多相关文章

  1. Zookeeper C API 指南四(C API 概览)(转)

    上一节<Zookeeper C API 指南三(回调函数)>重点讲了 Zookeeper C API 中各种回调函数的原型,本节将切入正题,正式讲解 Zookeeper C API.相信大 ...

  2. Zookeeper C API 指南三(回调函数)(转)

    2013-02-21 12:54 by Haippy, 9237 阅读, 0 评论, 收藏, 编辑 接上一篇<Zookeeper C API 指南二(监视(Wathes), 基本常量和结构体介绍 ...

  3. Zookeeper C API 指南一(转)

    Zookeeper 监视(Watches) 简介 Zookeeper C API 的声明和描述在 include/zookeeper.h 中可以找到,另外大部分的 Zookeeper C API 常量 ...

  4. Android开发-API指南-<provider>

    <provider> 英文原文:http://developer.android.com/guide/topics/manifest/provider-element.html 采集(更新 ...

  5. Android开发-API指南-Intent和Intent过滤器

    Intents and Intent Filters 英文原文:http://developer.android.com/guide/components/intents-filters.html 采 ...

  6. 支付宝api教程,支付宝根据交易号自动充值

    最近公司要用php做一个网站支付宝自动充值的功能,具体就是客户把钱直接转到公司的支付宝账号里,然后在我们网站上填写上交易号,我们网站程序自动获取交易信息,自动给网站的账户充值. 我的具体想法就是利用支 ...

  7. Android API 指南

    原文链接:http://android.eoe.cn/topic/android_sdk Android API 指南 - Android API Guides 应用的组成部分 - Applicati ...

  8. RabbitMQ-Java客户端API指南-下

    RabbitMQ-Java客户端API指南-下 使用主机列表 可以将Address数组传递给newConnection().的地址是简单地在一个方便的类com.rabbitmq.client包与主机 ...

  9. RabbitMQ-Java客户端API指南-上

    RabbitMQ-Java客户端API指南-上 客户端API严格按照AMQP 0-9-1协议规范进行建模,并提供了易于使用的附加抽象. RabbitMQ Java客户端使用com.rabbitmq.c ...

随机推荐

  1. sql server 安装后登录服务器

    计算机名\数据库实例名 z*******f-PC\zzf

  2. 一.JSP开发的工具下载与环境搭建

    JSP技术的强势: (1)一次编写,到处运行.在这一点上Java比PHP更出色,除了系统之外,代码不用做任何更改. (2)系统的多平台支持.基本上可以在所有平台上的任意环境中开发,在任意环境中进行系统 ...

  3. Intent相关

    Intent是什么? 翻译为:意图,目的(名词) 其实根本没必要管它是什么,看看它能做什么就好了. 不过后来我知道了,它就是个机制----通信机制-----android的许多组件间的交流要依赖它. ...

  4. Connection failed: NT_STATUS_ACCOUNT_RESTRICTION

    今天在linux机器上想要远程重启一台window的机器,输入命令后报错,如下 Google了下,有说是window禁止远程空密码登录,于是到window系统中添加了密码,这下再运行 这下执行就正常了

  5. Juniti学习总结

    JUnit简介 JUnit是由 Erich Gamma和Kent Beck编写的一个回归测试框架(regression testing framework).JUnit测试是程序员测试,即所谓白盒测试 ...

  6. mysql 全文查找fulltext

    从 Mysql 4.0 开始就支持全文索引功能,但是 Mysql 默认的最小索引长度是 4.如果是英文默认值是比较合理的,但是中文绝大部分词都是2个字符,这就导致小于4个字的词都不能被索引,全文索引功 ...

  7. OperateParticleWithCodes

    [OperateParticleWithCodes] Listing 6-6 shows how you might configure an emitter’s scale property. Th ...

  8. PCB板简易流程

    PCB布线规则设置 在进行布线之前一般要进行布线规则的设置,(因为元器件的封装已经画出了元件实际的轮廓大小,所以放置元件封装时,即使两个元件封装挨着也一般不会影响元件的实际安装,不过一般还是稍留一点距 ...

  9. oracle关键字使用

    v_Describe:=substr(v_Describe,0,length(v_Describe)-1); substr(目标内容,开始位置,截取长度) length(要计算的内容长度) 上述语句可 ...

  10. HDU 4284Travel(状压DP)

    HDU 4284    Travel 有N个城市,M条边和H个这个人(PP)必须要去的城市,在每个城市里他都必须要“打工”,打工需要花费Di,可以挣到Ci,每条边有一个花费,现在求PP可不可以从起点1 ...