【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)