【JAVA版】支付宝支付方案一详解
【摘要】 在使用“aliPayPlus”模块进行接入支付宝支付过程中,如果采用方案一(推荐)进行支付时,重要组装orderInfo字段数据。APICloud的文档中,没有提及太多,示例代码中的数据也有一定的问题。参考蚂蚁金服接口参数文档,终于接入成功。后台采用Java代码书写,特将信息整理出来,避免新接入的朋友,重新趟雷。接口参数参考地址:https://doc.open.alipay.com/doc...
在使用“aliPayPlus”模块进行接入支付宝支付过程中,如果采用方案一(推荐)进行支付时,重要组装orderInfo字段数据。APICloud的文档中,没有提及太多,示例代码中的数据也有一定的问题。参考蚂蚁金服接口参数文档,终于接入成功。后台采用Java代码书写,特将信息整理出来,避免新接入的朋友,重新趟雷。
接口参数参考地址:https://doc.open.alipay.com/docs ... Id=105465&docType=1
直接上代码:
/**
* 调用支付宝的SDK,封装发送给支付宝服务器的数据参数。 <br>
* 返回数据供APICloud支付方式一调用。 <br>
* 调用签名方法进行数据签名,步骤如下:
* <ol>
* <li>参考接口参数文档,对于sign之外的数据,进行封装,存入到map中</li>
* <li>调用AlipaySignature.rsaSign方法,进行数据签名。方法内部会自动完成排序。</li>
* <li>将得到的sign内容,赋值给sign。加入到map中。
* <li>
* <li>将所有的参数数据,进行URLEncoder编码。</li>
* <li>最后调用SDK方法,将map转换成排序后的字符串,返回给客户端</li>
* </ol>
* <p>
* 注意:坑比较多,文档中也有错误,不需要Base64的编码。
* </p>
*
* @param request
* @param response
* @return
* @author
* @throws AlipayApiException
* @throws FrameworkException
* @throws UnsupportedEncodingException
* @see 蚂蚁金服接口参数文档
*/
@ResponseBody
@RequestMapping(value = "alipay-order-info")
public String getPayOrderInfo(HttpServletRequest request, HttpServletResponse response)
throws AlipayApiException, FrameworkException, UnsupportedEncodingException
{
// 从客户端传递得到订单数据
String tradeId = request.getParameter("out_trade_no");
String amount = request.getParameter("total_amount");
String notifyUrl = request.getParameter("notify_url");
// 组装发送给支付宝服务器的数据串
AlipayBizContent bizContent = new AlipayBizContent();
bizContent.setOut_trade_no(tradeId);
bizContent.setProduct_code(AlipayHelper.PRODUCT_CODE);
bizContent.setSeller_id(prop.getAliSellerId());
bizContent.setSubject(AlipayHelper.SUBJECT);
bizContent.setTotal_amount(amount);
Map<String, String> infoMap = new HashMap<String, String>();
infoMap.put("app_id", prop.getAliAppId());
infoMap.put("biz_content", JsonUtils.fromObject(bizContent));
infoMap.put("charset", AlipayHelper.CHARSET);
infoMap.put("method", AlipayHelper.METHOD);
infoMap.put("notify_url", notifyUrl);
infoMap.put("sign_type", AlipayHelper.SIGN_TYPE);
infoMap.put("timestamp", DateTimeUtils.getNowTimeStanderd());
infoMap.put("version", AlipayHelper.VERSION);
// 对于数据进行签名操作
String sign = AlipaySignature
.rsaSign(infoMap, prop.getAliRsaPriKey(), AlipayHelper.CHARSET);
infoMap.put("sign", sign);
// 将参数内容进行URL格式编码
for (Map.Entry<String, String> entry : infoMap.entrySet())
{
entry.setValue(URLEncoder.encode(entry.getValue(), AlipayHelper.CHARSET));
}
// 将Map数据按照规则排列转换成字符串,发送给支付宝服务端
String orderInfo = AlipaySignature.getSignContent(infoMap);
logger.info("【支付宝支付请求参数】" + orderInfo);
JSONObject json = new JSONObject();
json.put("orderInfo", orderInfo);
return JsonUtils.fromObject(json);
}
其中, AlipayBizContent 的类代码如下,参考接口文档
public class AlipayBizContent
{
/**
* 对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。
*/
private String body;
/**
* 商品的标题/交易标题/订单标题/订单关键字等。
*/
private String subject;
/**
* 商户网站唯一订单号
*/
private String out_trade_no;
/**
* 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]
*/
private String total_amount;
/**
* 收款支付宝用户ID。 如果该值为空,则默认为商户签约账号对应的支付宝用户ID
*/
private String seller_id;
/**
* 销售产品码,商家和支付宝签约的产品码,为固定值QUICK_MSECURITY_PAY
*/
private String product_code;
注意代码中的签名、编码和排序。要使用支付宝提供的接口jar方法实现。
这样,通过getPayOrderInfo方法得到的字符串数据,就可以供API中的方法调用了。
另外,如果电商订单,关于订单的后处理,要在回调接口方法中完成,如下示例:
/**
* 支付宝支付完成之后,返回数据到客户服务端。
* <p>
* 程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25
* 小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h);
* </p>
*
* @param request
* @param response
* @author JiangZhongyan
* @throws IOException
*/
@RequestMapping(value = "/alipay-finish-notify")
@SystemControllerLog
public void alipayNotify(HttpServletRequest request, HttpServletResponse response)
throws IOException
{
Map<String, String> reqMap = getParamMap(request.getParameterMap());
// 校验支付返回数据状态&&变更订单状态
if (alipayService.isPaySuccess(reqMap)
&& payService.dealOrder(reqMap.get("out_trade_no"), ConstantHelper.ORDER_PAY_ALI))
{
logger.info("【支付宝回调成功】-返回success");
response.getOutputStream().write("success".getBytes());
}
else
{
response.getOutputStream().write("fail".getBytes());
}
}
在notify_url中,去完成你想要在支付成功之后做的事情。尽量不要在JS一侧执行。
以上是服务器端的代码,因为代码不全,仅供讲解过程,具体逻辑代码,根据实际情况调整。拼装的数据,示例如下:
【支付宝支付请求参数】app_id=<自己的ID号>&biz_content=%7B%22body%22%3A%22%22%2C%22out_trade_no%22%3A%2220170829093417364%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22seller_id%22%3A%222088221616699040%22%2C%22subject%22%3A%22%E6%98%9F%E6%B1%89%E6%9E%9C%E5%9B%AD%22%2C%22total_amount%22%3A%220.01%22%7D&charset=utf-8&method=alipay.trade.app.pay¬ify_url=http%3A%2F%2Fxinghansoft.com%2Ffruitshop%2Fapp%2Falipay-finish-notify.action&sign=<用私钥加密的签名数据>&sign_type=RSA×tamp=2017-08-29+09%3A34%3A21&version=1.0
从支付宝一侧返回的数据,示例如下:
【支付宝支付回调参数】{subject=<应用名称>, sign_type=RSA, buyer_logon_id=144***@qq.com, auth_app_id=<ID号>, notify_type=trade_status_sync, out_trade_no=20170829093417364, point_amount=0.00, version=1.0, fund_bill_list=[{"amount":"0.01","fundChannel":"ALIPAYACCOUNT"}], buyer_id=2088212389597532, total_amount=0.01, trade_no=2017082921001004530224695960, notify_time=2017-08-29 09:34:33, charset=utf-8, invoice_amount=0.01, trade_status=TRADE_SUCCESS, gmt_payment=2017-08-29 09:34:33, sign=<签名字符串>, gmt_create=2017-08-29 09:34:32, buyer_pay_amount=0.01, receipt_amount=0.01, app_id=2016050401362525, seller_id=<商户ID号>, notify_id=47a0e3508c7296c4f079a04043d2163k3a, seller_email=<商户邮箱>}
在APP一侧的JS代码如下:
/**
* 阿里支付宝支付
* 支付宝支付的金额单位为元
* @param tradeNo 商户系统内部的订单号
* @param price 订单总金额,只能为整数,单位:分(¥)
*/
function execAlipay(tradeNo, price) {
var data = {
out_trade_no : tradeNo,
total_amount : price,
notify_url : extApi.MainUrl + 'app/alipay-finish-notify.action'
};
ajax.post('app/alipay-order-info.action', data, function(ret) {
var aliPayPlus = api.require('aliPayPlus');
aliPayPlus.payOrder({
orderInfo : ret.orderInfo
}, function(ret, err) {
if (ret.code == '9000') {
closePayWin();
}else{
extApi.alert(getAliRetCodeMsg(ret.code), '支付结果');
}
});
});
}
/**
* 阿里支付返回的错误码,取值范围如下:
* 9000:支付成功
* 8000:正在处理中,支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
* 4000:订单支付失败
* 5000:重复请求
* 6001:用户中途取消支付操作
* 6002:网络连接出错
* 6004:支付结果未知(有可能已经支付成功),请查询商户订单列表中订单的支付状态
*/
function getAliRetCodeMsg(code) {
switch(code) {
case '9000':
return '支付成功';
case '8000':
return '正在处理中';
case '4000':
return '订单支付失败';
case '5000':
return '重复请求';
case '6001':
return '用户中途取消支付操作';
case '6002':
return '网络连接出错';
case '6004':
return '未知错误';
default:
return '未知错误';
}
}
到此,如果您账号正确,基本上就可以测试联通了。希望能够对你有帮助。
附件中,携带了两个Java文件,供参考。
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
作者其他文章
评论(0)