前言
这篇文章主要讲诉系统调用支付宝手机网页即时到账授权接口获取支付宝返回的request_token。
上篇文章地址:支付宝手机网页即时到账接口(1)之相关信息介绍。
这是上篇文章结尾调用授权接口的图解。
官方文档中对授权接口的说明是:
- 商户利用编程方法来模拟http请求远程解析html,获取支付宝返回的结果数据后,可以结合自身网站的业务逻辑进行数据处理。
说明中不难看出我们的代码中需要模拟http提交参数,然后解析支付宝返回的结果再进行处理。该项目是用java编写的,所以后续代码也是用java展现。该项目中模拟http需要两个jar包,httpclient.jar和httpcore.jar,我已经上传,点击下载即可。
授权接口请求参数说明
- 请求参数是商户在与支付宝进行数据交互时,提供给支付宝的请求数据,以便支付宝根据这些数据进一步处理。
从上面的图片可以看到参数比较多,这边简单介绍下(注:下面没有写出字符长度)。
- service=alipay.wap.trade.create.direct
- 授权接口名称(固定)
- format=xml
- 请求参数格式(固定)
- v=2.0
- 接口版本号(固定)。注当前版本,以后说不定会更新
- partner=2088000000000000
- 合作者身份ID(开通支付宝商家服务后,支付宝会提供)
- req_id=20150512203545
- 请求号(必须唯一,可以用当前时间)
- sec_id=MD5
- 签名方式(MD5、0001(RSA))。本篇是用MD5
- sign=VRVr7adPfsHblFjiBkGWryhKI
- 对请求或响应中参数签名后的值。
- req_data
- 示例
彩票 1282889603601 10.01 [email protected] http://www.yoursite.com/waptest0504/servlet/CallBack http://www.yoursite.com/waptest0504/servlet/NotifyReceiver 123456789 http://www.yoursite.com 3600 11397568a1
- 请求业务参数
- subject=彩票
- 商品名称(不可空)
- out_trade_no=1282889603601
- 商户网站唯一订单号(不可空)
- total_fee=0.01
- 交易金额(不可空)
- [email protected]
- 卖家支付宝账号(不可空)
- call_back_url=http://www.yoursite.com/waptest0504/servlet/CallBack
- 支付成功跳转页面路径(不可空)
- notify_url=http://www.yoursite.com/waptest0504/servlet/NotifyReceiver
- 服务器异步通知页面路径(可空,但是不建议为空)
- out_user=123456789
- 商户系统用户唯一标识(可空)
- merchant_url=http://www.yoursite.com
- 操作中断返回地址(可空)
- pay_expire=3600
- 交易自动关闭时间(可空,默认值21600(即15天))。
- agent_id=11397568a1
- 代理人ID(可空)
http://wappaygw.alipay.com/service/rest.htm?req_data=彩票 1282889603601 10.01 [email protected] http://www.yoursite.com/waptest0504/servlet/CallBack http://www.yoursite.com/waptest0504/servlet/NotifyReceiver 123456789 http://www.yoursite.com 3600 11397568a1 &service=alipay.wap.trade.create.direct&sec_id=0001&partner=2088101000137799&req_id=1282889689836&sign=VRVr7adPfsHblFjiBkGWryhKIKt+CaI4Cq2MA2wG1ENVuBAyFDlp3FbttndmID0USlfn22a9/6fQ+X+KPDE09hcTNz3gJ1edUiDWxHXY/ahTexCP79SDtoHx29uepXsHBe32DP0k9jZbfhpT8Ly0+ksuo5VJO0iymxQ87hQPjJw=&format=xml&v=2.0
partner=2088101000137799&
req_id=1282889689836&
res_data=
20100830e8085e3e0868a466b822350ede5886e8
&
sec_id=MD5&
service=alipay.wap.trade.create.direct&
v=2.0&
sign=72a64fb63f0b54f96b10cefb69319e8a
partner=208810100013779&
req_id=1282889689836&
res_error=
0005
0005
partner illegal
合作伙伴没有开通接口访问权限
&
sec_id=0001&
service=alipay.wap.trade.create.direct&
v=2.0
代码示例
public class AlipayAuth {
// 支付宝网关
private final static String alipayGatewayNew = "http://wappaygw.alipay.com/service/rest.htm?";
private final static String inputCharset = "utf-8";
private String key = "";//从支付宝获取的密钥
//接口名称
private final static String service = "alipay.wap.trade.create.direct";
//请求参数格式
private final static String format = "xml";
//接口版本号
private final static String v = "2.0";
//合作者身份id
public String partner = "2088000000000000";//填写从支付宝得到的id
//请求号
private String reqId;
//签名方式
private final static String secId = "MD5";
//签名
private String sign;
//请求业务参数
private String reqData;
//商品名称
private String subject;
//商务网站唯一订单号
private String outTradeNo;
//交易金额
private String totalFee;
//卖家支付宝账号
private String sellerAccountName;
//支付成功跳转路径
private String callBackUrl = "callBack";
//服务器异步通知页面路径 (可空)
private String notifyUrl = "notify";
//商户系统唯一标示(可空)
private String outUser;
//操作中断返回地址(可空)
private String merchantUrl;
//交易自动关闭时间(可空)
private String payExpire;
//代理人id(可空)
private String agentId;
public String getBasePath() {
return basePath;
}
public void setBasePath(String basePath) {
this.basePath = basePath;
}
public String getAlipayGatewayNew() {
return alipayGatewayNew;
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getInputCharset() {
return inputCharset;
}
public String getService() {
return service;
}
public String getFormat() {
return format;
}
public String getV() {
return v;
}
public String getPartner() {
return partner;
}
public void setPartner(String partner) {
this.partner = partner;
}
public String getReqId() {
return reqId;
}
public void setReqId(String reqId) {
this.reqId = reqId;
}
public String getSecId() {
return secId;
}
public String getSign() {
return sign;
}
public void setSign(String sign) {
this.sign = sign;
}
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getOutTradeNo() {
return outTradeNo;
}
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
public String getTotalFee() {
return totalFee;
}
public void setTotalFee(String totalFee) {
this.totalFee = totalFee;
}
public String getSellerAccountName() {
return sellerAccountName;
}
public void setSellerAccountName(String sellerAccountName) {
this.sellerAccountName = sellerAccountName;
}
public String getCallBackUrl() {
return callBackUrl;
}
public void setCallBackUrl(String callBackUrl) {
this.callBackUrl = callBackUrl;
}
public String getNotifyUrl() {
return notifyUrl;
}
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
public String getOutUser() {
return outUser;
}
public void setOutUser(String outUser) {
this.outUser = outUser;
}
public String getMerchantUrl() {
return merchantUrl;
}
public void setMerchantUrl(String merchantUrl) {
this.merchantUrl = merchantUrl;
}
public String getPayExpire() {
return payExpire;
}
public void setPayExpire(String payExpire) {
this.payExpire = payExpire;
}
public String getAgentId() {
return agentId;
}
public void setAgentId(String agentId) {
this.agentId = agentId;
}
public void setReqData(String reqData) {
this.reqData = reqData;
}
public String getReqData() {
reqData = ""
+ "" + subject + " "//商品名称
+ "" + outTradeNo + " "//商户网站唯一订单号
+ "" + totalFee + " "//交易金额
+ "" + sellerAccountName + " "//卖家支付宝账号
+ "" + callBackUrl + " "//支付成功跳转页面
+ "" + notifyUrl + " "//异步通知页面
//+ "" + merchantUrl + " "//操作终端返回地址(可空)
+ " ";
return reqData;
}
}
public String pay() throws Exception {
AlipayAuth alipayAuth = new AlipayAuth();
alipayAuth.setReqId("请求号:可以用系统当前时间(精确到毫秒),作为一个唯一的请求号");
alipayAuth.setSubject("商品名称");
alipayAuth.setOutTradeNo("商户网站唯一订单号");
alipayAuth.setTotalFee("交易金额");
Map param = getAuthParam(alipayAuth);
// 拼接后字符串
String prestr = PayUtils.createLinkString(param);
// sign签名
alipayAuth.setSign(getSign(prestr, alipayAuth.getKey(), alipayAuth.getInputCharset()));
// 通过授权接口获取token
// 1.拼接url字符串
StringBuffer urlStr = new StringBuffer();
urlStr.append(alipayAuth.getAlipayGatewayNew()).append(prestr).append("&sign=" + alipayAuth.getSign());
// 2.获取token
return getToken(urlStr.toString(), alipayAuth.getInputCharset());
}
获取request_token代码中使用到的
代码块getAuthParam
- 组成需要生成sign的map集合
private static Map getAuthParam(AlipayAuth alipayAuth) {
Map param = new HashMap();
param.put("service", alipayAuth.getService());
param.put("partner", alipayAuth.getPartner());
param.put("_input_charset", alipayAuth.getInputCharset());
param.put("sec_id", alipayAuth.getSecId());
param.put("format", alipayAuth.getFormat());
param.put("v", alipayAuth.getV());
param.put("req_id", alipayAuth.getReqId());
param.put("req_data", alipayAuth.getReqData());
return PayUtils.paraFilter(param);
}
工具类PayUtils.paraFilter(param);
- 去掉空值与签名参数后的新签名参数组
public static Map paraFilter(Map sArray) {
Map result = new HashMap();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key);
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")
|| key.equalsIgnoreCase("sign_type")) {
continue;
}
result.put(key, value);
}
return result;
}
工具类PayUtils.createLinkString(param)
- 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
public static String createLinkString(Map params) {
List keys = new ArrayList(params.keySet());
Collections.sort(keys);
String prestr = "";
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
String value = params.get(key);
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
代码块getSign(prestr, alipayAuth.getKey(), alipayAuth.getInputCharset())
private static String getSign(String text, String key, String input_charset) {
text = text + key;
return DigestUtils.md5Hex(getContentBytes(text, input_charset));
}
代码块getToken(urlStr.toString(), alipayAuth.getInputCharset())
private static String getToken(String urlStr, String charset) throws Exception {
HttpClient httpClient = new DefaultHttpClient();// client
HttpResponse remoteResponse = null;// response
int responseState = 0;// 返回状态码
BufferedReader bufferedReader = null;
StringBuilder entityStringBuilder = new StringBuilder();
// url存在非法字符->需转换成uri
URL url = new URL(urlStr.toString());
URI uri = new URI(url.getProtocol(), url.getHost(), url.getPath(), url.getQuery(), null);
HttpGet httpost = new HttpGet(uri);// GET
remoteResponse = httpClient.execute(httpost);
if (remoteResponse != null) {
responseState = remoteResponse.getStatusLine().getStatusCode();
if (HttpStatus.SC_OK == responseState) {
// 请求成功
HttpEntity httpEntity = remoteResponse.getEntity();
if (httpEntity != null) {
bufferedReader = new BufferedReader(new InputStreamReader(httpEntity.getContent(), "utf-8"));
String line = null;
while ((line = bufferedReader.readLine()) != null) {
entityStringBuilder.append(line);
}
}
} else {
// 请求失败
throw new Exception("页面访问错误,状态码:" + remoteResponse);
}
}
// 从授权页面返回的数据中获取到token
String entityString = URLDecoder.decode(entityStringBuilder.toString(), charset);
String token = getRequestToken(entityString);
return token;
}
代码块getRequestToken(entityString)
private static String getRequestToken(String text) throws Exception {
String request_token = "";
// 以“&”字符切割字符串
String[] strSplitText = text.split("&");
// 把切割后的字符串数组变成变量与数值组合的字典数组
Map paraText = new HashMap();
for (int i = 0; i < strSplitText.length; i++) {
// 获得第一个=字符的位置
int nPos = strSplitText[i].indexOf("=");
// 获得字符串长度
int nLen = strSplitText[i].length();
// 获得变量名
String strKey = strSplitText[i].substring(0, nPos);
// 获得数值
String strValue = strSplitText[i].substring(nPos + 1, nLen);
// 放入MAP类中
paraText.put(strKey, strValue);
}
if (paraText.get("res_data") != null) {
String res_data = paraText.get("res_data");
// token从res_data中解析出来(也就是说res_data中已经包含token的内容)
Document document = DocumentHelper.parseText(res_data);
request_token = document.selectSingleNode("//direct_trade_create_res/request_token").getText();
}
return request_token;
}
上面代码图解
本篇到此结束,敬请期待下篇-------支付宝手机网页即时到账接口(3)之交易接口请求