最近在做支付宝的app支付功能,那么支付宝app支付的使用场景以及如何接入,请参考支付宝提供的文档说明:
https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.Cgf5tg&treeId=204&articleId=105051&docType=1
本文,入住支付宝商家和签约app支付功能就不详细说了,下文直接按照签约以后的步骤讲。
创建应用的过程详细过程就不说了,说其中要注意的问题:
说了这么多秘钥,都是干啥用的,有点蒙圈,莫要着急:
应用私钥:向支付宝发送请求的时候需要把参数签名,签名的过程会用到私钥
应用公钥:需要配置到你自己建的应用里面
支付宝公钥:支付宝给你发请求的时候要用支付宝公钥验签,这个过程要用到支付宝公钥
3,支付宝网关:这个地址要牢记,我们向支付宝发送的请求地址就是它
配置完以上几步,我们就可以编码测试一下了,怎么测,怎么测,支付宝提供了demo,在此之前可以自己利用httpclient写个请求,要么就用postman验证一下请求对不对,里面sign签名字段我重点说一下,因为这个字段我们还是要手动写代码生成一下,生成的过程如下几步:
1,构建一个map把支付宝请求参数(必填的一定要填)放进去(注意下biz_content)
2,去除一下sign字段和空值,因为签名的时候此字段不参与签名
/**
* 除去数组中的空值和签名参数
* @param sArray 签名参数组
* @return 去掉空值与签名参数后的新签名参数组
*/
public static Map<String, Object> paraFilterRsa2(Map<String, Object> sArray) {
Map<String, Object> result = new HashMap<String, Object>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key).toString();
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
continue;
}
result.put(key, value);
}
return result;
}
3,把过滤后的参数用&连接上,并且key,value用=连接
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, Object> params) {
List<String> keys = new ArrayList<String>(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).toString();
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
然后呢,然后呢,然后就可以签名了
根据你设置的签名方式,如果是RSA2的话:
SignatureUtil.rsa256Sign(content,privateKey,input_charset);
如果是RSA的话:rsaSign(content, privateKey, charset);
此时content就是这个prestr,应用私钥没扔吧,没扔用在这,字符集就不说了,utf-8,
生成完以后我们就获取到了支付宝文档中的sign字段直接,请注意这里是签名的过程,把我原来构建的map别给我丢掉,哥还有用。
把sign也放到map里面去,到此为止我们才把支付宝要的参数构建完成,这个参数肯定不能直接请求啊,人家文档说的很清楚,先把map里面所有的value值都用urlencode编码一下,然后和key用=连接
/**
* 构造支付订单参数信息
*
* @param map
* 支付订单参数
* @return &字符串
*/
public static String buildOrderParam(Map<String,Object> map) {
List<String> keys = new ArrayList<>(map.keySet());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keys.size() - 1; i++) {
String key = keys.get(i);
String value = (String)map.get(key);
sb.append(buildKeyValue(key, value, true));
sb.append("&");
}
String tailKey = keys.get(keys.size() - 1);
String tailValue = map.get(tailKey).toString();
sb.append(buildKeyValue(tailKey, tailValue, true));
return sb.toString();
}
/**
* 拼接键值对
*
* @param key 键
* @param value 值
* @param isEncode 是否编码
* @return 带等号的字符串
*/
private static String buildKeyValue(String key, String value, boolean isEncode) {
StringBuilder sb = new StringBuilder();
sb.append(key);
sb.append("=");
if (isEncode) {
try {
sb.append(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException e) {
sb.append(value);
}
} else {
sb.append(value);
}
return sb.toString();
}
String orderInfo = buildOrderParam(map);
唉唉到此为止这个orderInfo就是我们要发送的参数了,把demo中的orderInfo换成这串,如果是沙箱环境在调用支付前加
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
postman的话直接get请求就可以。
重点说一下,这里面有个notify_url(异步通知的url)支付宝会把处理结果通过这个地址告诉你,这个一定要设置一个公网的ip或者域名,总而言之一定要让支付宝能访问到的。行了,累了,异步通知的处理有空在写一下。
还有你说我不会开通啊签约啊什么的,没关系,用沙箱,沙箱环境的使用经历我也会记录一下的。
https://doc.open.alipay.com/docs/doc.htm?spm=a219a.7629140.0.0.Cgf5tg&treeId=204&articleId=105051&docType=1
本文,入住支付宝商家和签约app支付功能就不详细说了,下文直接按照签约以后的步骤讲。
创建应用的过程详细过程就不说了,说其中要注意的问题:
1,配置网关,需要选择加密方式,在你接下来编码的过程中,涉及到签名和验签的方式请跟这里的选择保持一致,如图:
说了这么多秘钥,都是干啥用的,有点蒙圈,莫要着急:
应用私钥:向支付宝发送请求的时候需要把参数签名,签名的过程会用到私钥
应用公钥:需要配置到你自己建的应用里面
支付宝公钥:支付宝给你发请求的时候要用支付宝公钥验签,这个过程要用到支付宝公钥
3,支付宝网关:这个地址要牢记,我们向支付宝发送的请求地址就是它
配置完以上几步,我们就可以编码测试一下了,怎么测,怎么测,支付宝提供了demo,在此之前可以自己利用httpclient写个请求,要么就用postman验证一下请求对不对,里面sign签名字段我重点说一下,因为这个字段我们还是要手动写代码生成一下,生成的过程如下几步:
1,构建一个map把支付宝请求参数(必填的一定要填)放进去(注意下biz_content)
2,去除一下sign字段和空值,因为签名的时候此字段不参与签名
/**
* 除去数组中的空值和签名参数
* @param sArray 签名参数组
* @return 去掉空值与签名参数后的新签名参数组
*/
public static Map<String, Object> paraFilterRsa2(Map<String, Object> sArray) {
Map<String, Object> result = new HashMap<String, Object>();
if (sArray == null || sArray.size() <= 0) {
return result;
}
for (String key : sArray.keySet()) {
String value = sArray.get(key).toString();
if (value == null || value.equals("") || key.equalsIgnoreCase("sign")) {
continue;
}
result.put(key, value);
}
return result;
}
3,把过滤后的参数用&连接上,并且key,value用=连接
/**
* 把数组所有元素排序,并按照“参数=参数值”的模式用“&”字符拼接成字符串
* @param params 需要排序并参与字符拼接的参数组
* @return 拼接后字符串
*/
public static String createLinkString(Map<String, Object> params) {
List<String> keys = new ArrayList<String>(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).toString();
if (i == keys.size() - 1) {//拼接时,不包括最后一个&字符
prestr = prestr + key + "=" + value;
} else {
prestr = prestr + key + "=" + value + "&";
}
}
return prestr;
}
然后呢,然后呢,然后就可以签名了
根据你设置的签名方式,如果是RSA2的话:
SignatureUtil.rsa256Sign(content,privateKey,input_charset);
如果是RSA的话:rsaSign(content, privateKey, charset);
此时content就是这个prestr,应用私钥没扔吧,没扔用在这,字符集就不说了,utf-8,
生成完以后我们就获取到了支付宝文档中的sign字段直接,请注意这里是签名的过程,把我原来构建的map别给我丢掉,哥还有用。
把sign也放到map里面去,到此为止我们才把支付宝要的参数构建完成,这个参数肯定不能直接请求啊,人家文档说的很清楚,先把map里面所有的value值都用urlencode编码一下,然后和key用=连接
/**
* 构造支付订单参数信息
*
* @param map
* 支付订单参数
* @return &字符串
*/
public static String buildOrderParam(Map<String,Object> map) {
List<String> keys = new ArrayList<>(map.keySet());
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keys.size() - 1; i++) {
String key = keys.get(i);
String value = (String)map.get(key);
sb.append(buildKeyValue(key, value, true));
sb.append("&");
}
String tailKey = keys.get(keys.size() - 1);
String tailValue = map.get(tailKey).toString();
sb.append(buildKeyValue(tailKey, tailValue, true));
return sb.toString();
}
/**
* 拼接键值对
*
* @param key 键
* @param value 值
* @param isEncode 是否编码
* @return 带等号的字符串
*/
private static String buildKeyValue(String key, String value, boolean isEncode) {
StringBuilder sb = new StringBuilder();
sb.append(key);
sb.append("=");
if (isEncode) {
try {
sb.append(URLEncoder.encode(value, "UTF-8"));
} catch (UnsupportedEncodingException e) {
sb.append(value);
}
} else {
sb.append(value);
}
return sb.toString();
}
String orderInfo = buildOrderParam(map);
唉唉到此为止这个orderInfo就是我们要发送的参数了,把demo中的orderInfo换成这串,如果是沙箱环境在调用支付前加
EnvUtils.setEnv(EnvUtils.EnvEnum.SANDBOX);
postman的话直接get请求就可以。
重点说一下,这里面有个notify_url(异步通知的url)支付宝会把处理结果通过这个地址告诉你,这个一定要设置一个公网的ip或者域名,总而言之一定要让支付宝能访问到的。行了,累了,异步通知的处理有空在写一下。
还有你说我不会开通啊签约啊什么的,没关系,用沙箱,沙箱环境的使用经历我也会记录一下的。