1.去支付宝官网申请公司企业账号并开通一个应用,在应用里签约APP支付功能
接入网址https://auth.alipay.com/login/ant_sso_index.htm?goto=https%3A%2F%2Fopen.alipay.com%2Fplatform%2Fsetting.htm
开发人员若没有拿到签约之后的秘钥可先进行沙箱测试。使用沙箱提供的测试秘钥进行测试。
2.创建应用
蚂蚁金服开放平台网站https://openhome.alipay.com/platform/appManage.htm#/apps
参考文献https://openclub.alipay.com/read.php?tid=1606&fid=25
应用分为第三方应用以及自用型。
第三方应用是甲方自己登陆企业账号,开发人员创建应用,创建之后发送授权申请,甲方授权之后拿到授权码方可继续发开。参考文章https://docs.open.alipay.com/20160728150111277227/intro
由于拿到了商家账号,本次使用自用型应用。
开发配置

支付宝网关,正式环境则为此配置,沙箱环境见沙箱测试环节。
应用网关、授权回调地址一般不用配置,授权回调地址为第三方应用时使用,这里不详细说了。
重点是加签方式、涉及到开发参数配置
1)点击设置应用公钥

2)下载完成后点击生成秘钥
3)点击之后会在相应文件夹下自动保存生成的私钥公钥。将应用公钥填入后,点击保存会生成支付宝应用公钥。将此应用公钥下载保存。这些信息都是后面请求支付宝接口的重要参数。

4)点击提交审核等待审核。
3.沙盒环境
参考文档https://openhome.alipay.com/platform/appDaily.htm?tab=info
1)开发配置
沙盒支付宝网关为https://openapi.alipay**dev**.com/gateway.do
秘钥使用RSA2方式,RSA已经不支持了,秘钥上传方式和前面所述一样。
2)沙盒环境生成的二维码支付需要使用沙箱专用的支付宝
4.系统集成
4.1.下载官方SDK和demo、
1)先进行demo测试,通过demo测试成功确保我们输入的参数无误再集成到项目中,这可减少不必要的错误,以免耽误开发进度。
2)参数配置
。
这里的参数主要有一下几点需要注意:
1.商户私钥为生成的RSA2秘钥的应用私钥,支付宝公钥为设置应用时上传应用公钥后生成的支付宝公钥。配置错误会导致验签失败。
2.支付宝异步通知需要公网访问,可以在本地进行内网穿透
3、支付宝网关,沙盒模式带dev字段,正式环境需去掉
3)运行demo进行测试。
4.2.将支付集成到项目中
在demo测试无误后方可将支付宝集成到项目中
获取支付宝SDK地址:支付宝SDK下载地址,这里我选择JAVA的SDK。下载解压后的SDK得到:

1)MAVEN配置
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>3.6.0.ALL</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.1.1</version></dependency>
2)流程详解

首先,我们来理一理开发的思路,按照我当前项目的需求,关于支付这一块大概操作流程是:用户在APP上选好要购买的商品,点击“立即购买”,跳转到订单详细页面。选择支付方式,点击“确定支付”跳转到支付宝APP,付款完成后,跳转回APP,完成支付。这个过程,当用户点击“确定支付”时,APP需要调用商户后台接口。
这时候就是我们所需要做的事情:先是生成商户系统一笔未支付的订单,获得商户订单ID(商户系统生成)和订单的一些其他信息,然后再调用支付宝的SDK提供的数字签名方法,将需要传给支付宝的信息进行加签,然后把加签后的字符串返回给APP。APP拉起支付宝APP,再把这个加签的字符串传给支付宝,完成支付。APP接收到同步通知后,还需要再次调用商户后台的接口(虽然同步通知也有付款情况,但需要以后台通知为准),校验订单最终的付款情况。按照支付宝API上所说,当完成支付后,支付宝会做2个操作,一个是同步返回信息给APP,一个是异步通知商户后台返回支付状态等信息,并且最终的支付结果是以异步通知为准。所以我们还需要考虑到一点,就是当用户支付成功之后,商户系统暂时没有接收到支付宝的异步通知时。我们需要拿着这个商户订单ID主动调用SDK支付宝的查询接口,去获取该订单的支付情况,并最终返回给APP。这个查询的接口应该是给APP收到同步通知后,请求商户系统后台进行校验的时候调用的。
根据我们上面思考所得,后台只需要对外提供3个接口即可:
1.用户点击“立即购买”时调用商户后台接口,后台返回加签后的订单信息字符串
2.在支付完成之后,支付宝异步通知商户后台订单的付款情况
3.在支付完成之后,跳转回APP时,APP调用商户后台进行最终付款校验
1)和沙箱环境一样,我们先设置参数
public class AlipayConfig {public static String app_id = "2019022563373266";// public static String app_id = "2016092800612951";// 商户私钥,您的PKCS8格式RSA2私钥// public static String merchant_private_key = "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOmT37efurkA/SfMtwUDrCz18CZdfrtSvEGB5aBalZo2utEP9oezHZ5uoqNdHGnzGLhsegzZoavGuRGKN/F9RxF7cMbW665P2w/ymeIIiHXD9SJVguBRMZGFlBTs133Ds6BsBbcXoeCujnXAh6N/jJ/hIbuG84FctA3pusMmcqnbolmzW+BkH8NkF6ZjUBgF7lUpMCp7IfPiB2lJJufSr9kFrS2iu/bNsqXjw9kP7fmpzAY9mo+keKJpVH/WRRtR7x/ctlWaiTTks/Zh5VUMd5NfQN8a1/2MIlVowtR313lPJTYfIbzOP0dspBAQ9/Hu3W6vbzWA4a/L94zCn7tGXjAgMBAAECggEAPTM5rddRkvU2RTE4ItDcF0Xm0eGhxNCxouxzAlHRt93yVYmpBE9zOsDnGQyWJremDOrgfHwhOn5JcDFx4hb5Hzx9XEEPN/kVhEROuUXfMrD9oCTU7pNQ+gFANU470shbRvEk11ohfglSohEWtlWVWiPH48vJN/nqjMG9cC8Fpfz5sePpN5tbDZ2M2u5brVCLXWR5J2uF7mKQiKMIxvhMYcoQ2MS9+XQVjJktbWKlCdJboMQq4DS7diCXQcNmiWJrBh/qHcy9+NU9NRz82laGTyDkUnqnw16LMXZnopf6ZvGAwAL3T672UulLubxmUyq2kOROBtoJeyfR9D+qh6z12QKBgQDt9q8KqX6W432/BxwvYL6iNeUz/ujCODLq22ikSNvoMJAAYLIa39bDs8LHHEugIcpQk6DOxZ1MzkV82CHM0YA26T8bbfZrBiYK7oQO0hHP3oOMbRTB9lLGn9Kdhp/0pAcVVmXLAdRpWqv50BjhzRj3uc5sWeA4swRuZc0E9hvSLwKBgQCZaCXREevz3SnkiJy48z4KSS5+FEuimopgmaMqjdnzkh6E7Krd8sNFl82dt8Yio7dBScnmNuj98rKVObTe9+SN0H0UvdlKOYMHrHPEnOQJXVdii9tTONzHc41xRt0m4pKW+WbK/yem/YM3JutKajF8z7/Qt3K3K0Ap3S64dtn+jQKBgDbu4H+smw2IHKoxoP8K7VcS7ANx0Bet04tF9UUfkKxsMYH00IjFrZVl9Qvz6z1fL44kVlYFZoepgn8Mgdj/cAK9G5VgcCdKtxOE9jVZp0T+UA3lzInuLDOwB3XX8ysNhpkVZdBUbs2XYeX8dRIDP8VIPm/i25EbOmWl2ItRqSB/AoGAct7rwlv7JQZtAjXRtSRfRnB6IeqsoDu8do1VAt5pX9wAgmR9pejMk+YSD5G3CeUxqe/JAVwIp2/+jYNCjtttB0wg/VETzmK2XR6jKYyZrPF6J862EuE3YRqDxVjc7Osn/WkPsd3SIVcf1EKOWZCfMeiWp4FWoxX929tFytckcVkCgYEAhY6IkzJikbQEG7d0+RpC9UFtPlB+EEF+nt5aQxnZhMcTUJXQrNkARjemdqONu0L33BMZjt3jS7MZbn4LA8LdQH/vl7v92x9UX9kfwYwKwvPbWYQ6W1adlr68MDe7nUHoRLJCuFyn/HX8Kytl7f36NCTizWQoi4Owy5qnETIQxzU=";/支付宝公钥// public static String alipay_public_key = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwLes6WOrmxNzjFzjzEtfVqOp8GLbhhE8KXobB5l2L5EoF/8xUPHuyXvKmbQcwabm1tNq/vREeswGwoHbJIk+dlvmh45RKjb0AQMDDtWxaEyAKKDNfe0TVrhMjD2g5FyFvJVqW20OK7bFJ6uFxPP3flLoUL1NjDx0C7CYRlIHxq4I0rqs/TZpdjPZy9txAE5sf2Yx0SdOPBNurS9EuFQYylOfmAkByAchRTCLPl+upndZqT8q7bCGU3J7t87PiU7FHEo1NoXbi5B3p5PoIsEeQXtjAy2lLWEDX4xRASqhyIibR8dv/1obxNgv8zvqzYcnmoPsM5Lbn1y7uuKvGQQyBwIDAQAB";//异步通知public static String notify_url = "http://fdzc.shangyuninfo.com/api/easyBuy/order/notifyUrl";//同步通知public static String return_url = "http://fdzc.shangyuninfo.com";// 签名方式public static String sign_type = "RSA2";// 字符编码格式public static String charset = "utf-8";// 支付宝网关,正式环境需要将dev去电// public static String gatewayUrl = "https://openapi.alipaydev.com/gateway.do";// 支付宝网关public static String log_path = "D:\\";}
2)购买后返回支付链接模块
controller层
/*** 加入众筹接口* 根据订单Id,添加订单详情表内容*/// @RequiresPermissions("easyBuy:orderDetail:add")@Log(title = "订单", businessType = BusinessType.INSERT)@PostMapping("/add")@Transactional(rollbackFor = Exception.class)@ResponseBodypublic AjaxResult addSave(@RequestBody OrderDetail orderDetail){//存订单详情表if (orderDetail.getOrderId() == null){return AjaxResult.error("订单Id不能为空,请联系管理员");}if (orderDetail.getProductNum() == null){return AjaxResult.error("产品数量不能为空");}Integer orderId = orderDetail.getOrderId();Order order = orderService.selectOrderById(orderId);Integer crowdPackageId = order.getCrowdfundingId();Integer AllPeople = crowdfundingPackagesService.selectCrowdfundingPackagesById(crowdPackageId).getPeopleNum();List<OrderDetail> orderDetailList = order.getOrderDetailList();Integer currentPeople = 1;for (OrderDetail item:orderDetailList){currentPeople = currentPeople+1;}if (currentPeople>AllPeople){return AjaxResult.error("人数已满,众筹结束");}else if (currentPeople.equals(AllPeople)){order.setCrowdfundingId(1);orderService.updateOrder(order);}BigDecimal productPrice = order.getProductPrice();orderDetail.setOrderId(orderId);orderDetail.setOrderNo(getUUID.getOrderIdByUUId());BigDecimal sumPrice = productPrice.multiply(new BigDecimal(orderDetail.getProductNum()));orderDetail.setOrderAmount(sumPrice);orderDetail.setCreateUserId(Integer.parseInt(ShiroUtils.getUserId().toString()));orderDetail.setOrderStatus(0);orderDetail.setCreateBy(ShiroUtils.getLoginName());orderDetailService.insertOrderDetail(orderDetail);Integer orderDetailId = orderDetail.getOrderDetailId();//开启支付宝支付}
ps:只要将开启支付后的参数设置对即可,上面的存表和获取信息的逻辑可根据自己项目写相应的逻辑。开启支付这部分可以放在service层,后面直接调用即可
service层
/*** 获取支付宝加签后台的订单信息字符串** @param request* @return*/@Override@Transactional(propagation = Propagation.REQUIRED)public String getAliPayOrderStr(OrderTest orderTest) {//最终返回加签之后的,app需要传给支付宝app的订单信息字符串String orderString = "";logger.info("==================支付宝下单,商户订单号为:"+orderTest.getOutTradeNo());//创建商户支付宝订单(因为需要记录每次支付宝支付的记录信息,单独存一个表跟商户订单表关联,以便以后查证)AlipaymentOrder alipaymentOrder=new AlipaymentOrder();alipaymentOrder.setClubOrderId(orderTest.getId().toString());//商家订单主键alipaymentOrder.setOutTradeNo(orderTest.getOutTradeNo());//商户订单号alipaymentOrder.setTradeStatus((byte) 0);//交易状态alipaymentOrder.setTotalAmount(Double.parseDouble(orderTest.getTotalAmount()));//订单金额alipaymentOrder.setReceiptAmount(0.00);//实收金额alipaymentOrder.setInvoiceAmount(0.00);//开票金额alipaymentOrder.setBuyerPayAmount(0.00);//付款金额alipaymentOrder.setRefundFee(0.00); //总退款金额try{//实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID,AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);//实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.payAlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest();//SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();//业务参数传入,可以传很多,参考API//model.setPassbackParams(URLEncoder.encode(request.getBody().toString())); //公用参数(附加数据)model.setBody(orderTest.getBody()); //对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。model.setSubject(orderTest.getSubjecy()); //商品名称model.setOutTradeNo(orderTest.getOutTradeNo()); //商户订单号(自动生成)// model.setTimeoutExpress("30m"); //交易超时时间model.setTotalAmount(orderTest.getTotalAmount()); //支付金额model.setProductCode("QUICK_MSECURITY_PAY"); //销售产品码(固定值)ali_request.setBizModel(model);logger.info("====================异步通知的地址为:"+alipayment.getNotifyUrl());ali_request.setNotifyUrl(AlipayConfig.notify_url); //异步回调地址(后台)ali_request.setReturnUrl(AlipayConfig.return_url); //同步回调地址(APP)// 这里和普通的接口调用不同,使用的是sdkExecuteAlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request); //返回支付宝订单信息(预处理)orderString=alipayTradeAppPayResponse.getBody();//就是orderString 可以直接给APP请求,无需再做处理。this.createAlipayMentOrder(alipaymentOrder);//创建新的商户支付宝订单} catch (AlipayApiException e) {e.printStackTrace();logger.info("与支付宝交互出错,未能生成订单,请检查代码!");}return orderString;}
支付成功后返回相应的跳转支付宝收银台的链接
3)实现第二个接口:在支付完成之后,支付宝异步通知商户后台订单的付款情况,这个是支付宝每隔一段时间来访问一次的接口,直到你返回success,才会停止访问,这里我分了2个地方进行调用
service层
这里由于有两个模块的存储逻辑处理都要在支付宝回调通知时提醒,所以本地方在生成支付链接是传入了passback_params参数,此参数支付在异步通知时会原样返回,此逻辑可根据实际情况编写。
/*** 支付宝异步请求逻辑处理*/@Override@Transactional(rollbackFor = Exception.class)public String notify(Map<String, String> conversionParams){log.info("==================支付宝异步请求逻辑处理");//签名验证(对支付宝返回的数据验证,确定是支付宝返回的)boolean signVerified = false;try {//调用SDK验证签名signVerified = AlipaySignature.rsaCheckV1(conversionParams, AlipayConfig.alipay_public_key, AlipayConfig.charset, AlipayConfig.sign_type);} catch (AlipayApiException e) {log.info("==================验签失败 !");e.printStackTrace();}//对验签进行处理if (signVerified) {//验签通过//获取需要保存的数据String appId=conversionParams.get("app_id");//支付宝分配给开发者的应用IdString notifyTime=conversionParams.get("notify_time");//通知时间:yyyy-MM-dd HH:mm:ssString gmtCreate=conversionParams.get("gmt_create");//交易创建时间:yyyy-MM-dd HH:mm:ssString gmtPayment=conversionParams.get("gmt_payment");//交易付款时间String gmtRefund=conversionParams.get("gmt_refund");//交易退款时间String gmtClose=conversionParams.get("gmt_close");//交易结束时间String tradeNo=conversionParams.get("trade_no");//支付宝的交易号String outTradeNo = conversionParams.get("out_trade_no");//获取商户之前传给支付宝的订单号(商户系统的唯一订单号)String outBizNo=conversionParams.get("out_biz_no");//商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号)String buyerLogonId=conversionParams.get("buyer_logon_id");//买家支付宝账号String sellerId=conversionParams.get("seller_id");//卖家支付宝用户号String sellerEmail=conversionParams.get("seller_email");//卖家支付宝账号String totalAmount=conversionParams.get("total_amount");//订单金额:本次交易支付的订单金额,单位为人民币(元)String receiptAmount=conversionParams.get("receipt_amount");//实收金额:商家在交易中实际收到的款项,单位为元String invoiceAmount=conversionParams.get("invoice_amount");//开票金额:用户在交易中支付的可开发票的金额String buyerPayAmount=conversionParams.get("buyer_pay_amount");//付款金额:用户在交易中支付的金额String tradeStatus = conversionParams.get("trade_status");// 获取交易状态String payMoudle = conversionParams.get("passback_params"); //请求时传入的付款模块参数,1代表易采购,2代表产品筹//支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id)if (payMoudle.equals("1")){OrderDetail orderDetailPay=orderDetailService.selectOrderDetailByOrderNo(outTradeNo);if(orderDetailPay!=null&&totalAmount.equals(orderDetailPay.getOrderAmount().toString())&&AlipayConfig.app_id.equals(appId)){//修改数据库相应订单详情表,保存订单记录//保存支付记录表Integer userId = orderDetailPay.getCreateUserId();PaymentRecork paymentRecork = new PaymentRecork();paymentRecork.setUserId(userId);paymentRecork.setAmount(BigDecimal.valueOf(Double.parseDouble(totalAmount)));paymentRecork.setPayModule(Integer.parseInt(payMoudle));paymentRecork.setBusinessId(orderDetailPay.getOrderDetailId());switch (tradeStatus) // 判断交易结果{case "TRADE_FINISHED": // 交易结束并不可退款orderDetailPay.setPayStatus(3);paymentRecork.setPaymentStatus(3);break;case "TRADE_SUCCESS": // 交易支付成功orderDetailPay.setPayStatus(1);paymentRecork.setPaymentStatus(1);break;case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款orderDetailPay.setPayStatus(2);paymentRecork.setPaymentStatus(2);break;case "WAIT_BUYER_PAY": // 交易创建并等待买家付款orderDetailPay.setPayStatus(0);paymentRecork.setPaymentStatus(0);break;default:break;}int returnResult=orderDetailService.updateOrderDetail(orderDetailPay); //更新订单详情表中状态paymentRecorkService.insertPaymentRecork(paymentRecork); //增加订单记录表if(tradeStatus.equals("TRADE_SUCCESS")) { //只处理支付成功的订单: 修改交易表状态,支付成功if(returnResult>0){return "success";}else{return "fail";}}else{return "fail";}}else{log.info("==================支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id),不一致!返回fail");return"fail";}}else {CrowdfundingOrder productCrowdOrder=crowdfundingOrderService.selectCrowdfundingOrderByOrderNo(outTradeNo);Integer productId = productCrowdOrder.getProductId();CpcProduct cpcProduct = cpcProductService.selectCpcProductById(productId);BigDecimal currentCrowd = cpcProduct.getCrowdCurrent(); //产品订单前已融资数目if (currentCrowd == null){currentCrowd =BigDecimal.valueOf(0);}BigDecimal targetCrowd = cpcProduct.getCrowdTarget(); //产品目标融资BigDecimal orderCrowd = productCrowdOrder.getOrderAmount(); //订单金额BigDecimal leftFunds = targetCrowd.subtract(currentCrowd); //剩余带融资数if (orderCrowd.compareTo(leftFunds) == 0){ //等于,更新产品表,及其产品状态currentCrowd = currentCrowd.add(orderCrowd);cpcProduct.setCrowdCurrent(currentCrowd);cpcProduct.setProductStatus(1);cpcProduct.setUpdateBy(productCrowdOrder.getCreateBy());}else{currentCrowd = currentCrowd.add(orderCrowd);cpcProduct.setCrowdCurrent(currentCrowd);cpcProduct.setUpdateBy(productCrowdOrder.getCreateBy());}if(totalAmount.equals(productCrowdOrder.getOrderAmount().toString())&&AlipayConfig.app_id.equals(appId)){//修改数据库相应订单详情表,保存订单记录//保存支付记录表Integer userId =productCrowdOrder.getCreateUserId();PaymentRecork paymentRecork = new PaymentRecork();paymentRecork.setUserId(userId);paymentRecork.setAmount(BigDecimal.valueOf(Double.parseDouble(totalAmount)));paymentRecork.setPayModule(Integer.parseInt(payMoudle));paymentRecork.setBusinessId(productCrowdOrder.getOrderId());switch (tradeStatus) // 判断交易结果{case "TRADE_FINISHED": // 交易结束并不可退款paymentRecork.setPaymentStatus(3);break;case "TRADE_SUCCESS": // 交易支付成功paymentRecork.setPaymentStatus(1);cpcProductService.updateCpcProduct(cpcProduct);productCrowdOrder.setCrowdfundingStatus(1);break;case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款paymentRecork.setPaymentStatus(2);break;case "WAIT_BUYER_PAY": // 交易创建并等待买家付款paymentRecork.setPaymentStatus(0);break;default:break;}int returnResult=crowdfundingOrderService.updateCrowdfundingOrder(productCrowdOrder); //更新订单详情表中状态paymentRecorkService.insertPaymentRecork(paymentRecork); //增加订单记录表if(tradeStatus.equals("TRADE_SUCCESS")) { //只处理支付成功的订单: 修改交易表状态,支付成功if(returnResult>0){return "success";}else{return "fail";}}else{return "fail";}}else{log.info("==================支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id),不一致!返回fail");return"fail";}}} else { //验签不通过log.info("==================验签不通过 !");return "fail";}}
controller层,设置noticefy接口,供支付宝异步回调时可访问
/*** 获取支付宝异步通知订单情况,更新订单表*/@Log(title = "订单", businessType = BusinessType.UPDATE)@PostMapping("/notifyUrl")@ResponseBodypublic String notify(HttpServletRequest request, HttpServletResponse response)throws IOException{//1.从支付宝回调的request域中取值//获取支付宝返回的参数集合Map<String, String[]> aliParams = request.getParameterMap();//用以存放转化后的参数集合Map<String, String> conversionParams = new HashMap<String, String>();for (Iterator<String> iter = aliParams.keySet().iterator(); iter.hasNext();) {String key = iter.next();String[] values = aliParams.get(key);String valueStr = "";for (int i = 0; i < values.length; i++) {valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";}// 乱码解决,这段代码在出现乱码时使用。如果mysign和sign不相等也可以使用这段代码转化// valueStr = new String(valueStr.getBytes("ISO-8859-1"), "uft-8");conversionParams.put(key, valueStr);}log.info("==================返回参数集合:"+conversionParams);String status = aliPayService.notify(conversionParams); //payMoudle 1易采购,2产品筹return status;}
支付宝异步回调时只有当我们返回给他们“success”时才会停止访问,否则他会分阶段请求notify网址。一天之内请求8次。
3)实现第三个接口:在支付完成之后,跳转回APP时,APP调用商户后台进行最终付款校验。我把主要的处理逻辑写在Service层了,Controller层直接调用就可以,这里就不放Controller层的代码了。
/*** 向支付宝发起订单查询请求* @param request* @return* @throws IOException*/@Overridepublic Byte checkAlipay(String outTradeNo) {logger.info("==================向支付宝发起查询,查询商户订单号为:"+outTradeNo);try {//实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型)AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.URL, AlipayConfig.APPID,AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT, AlipayConfig.CHARSET,AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.SIGNTYPE);AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest();alipayTradeQueryRequest.setBizContent("{" +"\"out_trade_no\":\""+outTradeNo+"\"" +"}");AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest);if(alipayTradeQueryResponse.isSuccess()){AlipaymentOrder alipaymentOrder=this.selectByOutTradeNo(outTradeNo);//修改数据库支付宝订单表alipaymentOrder.setTradeNo(alipayTradeQueryResponse.getTradeNo());alipaymentOrder.setBuyerLogonId(alipayTradeQueryResponse.getBuyerLogonId());alipaymentOrder.setTotalAmount(Double.parseDouble(alipayTradeQueryResponse.getTotalAmount()));alipaymentOrder.setReceiptAmount(Double.parseDouble(alipayTradeQueryResponse.getReceiptAmount()));alipaymentOrder.setInvoiceAmount(Double.parseDouble(alipayTradeQueryResponse.getInvoiceAmount()));alipaymentOrder.setBuyerPayAmount(Double.parseDouble(alipayTradeQueryResponse.getBuyerPayAmount()));switch (alipayTradeQueryResponse.getTradeStatus()) // 判断交易结果{case "TRADE_FINISHED": // 交易结束并不可退款alipaymentOrder.setTradeStatus((byte) 3);break;case "TRADE_SUCCESS": // 交易支付成功alipaymentOrder.setTradeStatus((byte) 2);break;case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款alipaymentOrder.setTradeStatus((byte) 1);break;case "WAIT_BUYER_PAY": // 交易创建并等待买家付款alipaymentOrder.setTradeStatus((byte) 0);break;default:break;}this.updateByPrimaryKey(alipaymentOrder); //更新表记录return alipaymentOrder.getTradeStatus();} else {logger.info("==================调用支付宝查询接口失败!");}} catch (AlipayApiException e) {// TODO Auto-generated catch blocke.printStackTrace();}return 0;}
4)退款处理
将订单号传入,请求支付宝退款接口进行退款,这里的payMoudle参数和ordertail参数可根据实际需求增加或者去掉
service层
//退款消息处理@Override@Transactional(rollbackFor = Exception.class)public AjaxResult reFund(AlipayTradeRefundResponse respose, Integer payMoudle,OrderDetail orderDetail){if (respose.getCode().equals("10000")){//更新支付记录状态try {PaymentRecork paymentRecork = paymentRecorkService.selectPaymentRecorkByBusinessId(orderDetail.getOrderDetailId());paymentRecork.setPaymentStatus(2);RefundRecord refundRecord = new RefundRecord();refundRecord.setBuyerId(paymentRecork.getUserId());refundRecord.setSellerId(orderDetail.getProduct().getPublisherId());refundRecord.setAmount(paymentRecork.getAmount());refundRecord.setPayModule(payMoudle);refundRecord.setBusinessId(paymentRecork.getBusinessId());refundRecord.setRefundReason(JSON.parseObject(respose.getParams().get("biz_content")).get("refund_reason").toString());refundRecord.setRefundStatus(orderDetail.getOrderStatus());refundRecord.setRefundReason("退款");if (refundRecordService.selectRefundRecordByBussinessId(orderDetail.getOrderDetailId())!=null){paymentRecorkService.updatePaymentRecork(paymentRecork);refundRecordService.updateRefundRecord(refundRecord);}else {paymentRecorkService.updatePaymentRecork(paymentRecork);refundRecordService.insertRefundRecord(refundRecord);}return AjaxResult.success("退款成功");}catch (Exception e){log.info("退款请求出错");return AjaxResult.success("退款成功"); //todo bug 退款记录重复}}else {return AjaxResult.error("退款失败,请求出错");}}
controller层
//商家同意退款@Log(title = "订单", businessType = BusinessType.INSERT)@ResponseBody@PostMapping("/reFund")public AjaxResult refund(Integer orderDetailId) {OrderDetail orderDetail = orderDetailService.selectOrderDetailById(orderDetailId);//获得初始化的AlipayClienttry{AlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.gatewayUrl, AlipayConfig.app_id,AlipayConfig.merchant_private_key, "json", AlipayConfig.charset, AlipayConfig.alipay_public_key,AlipayConfig.sign_type);//设置请求参数AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest();alipayRequest.setReturnUrl(AlipayConfig.return_url);alipayRequest.setNotifyUrl(AlipayConfig.notify_url);//商户订单号,商户网站订单系统中唯一订单号String out_trade_no = orderDetail.getOrderNo();//支付宝交易号 暂不用String trade_no = "";//请二选一设置//需要退款的金额,该金额不能大于订单金额,必填BigDecimal refund_amount = orderDetail.getOrderAmount();//退款的原因说明String refund_reason = "买家要求退款,卖家同意";//标识一次退款请求,同一笔交易多次退款需要保证唯一,如需部分退款,则此参数必传String out_request_no = "";alipayRequest.setBizContent("{\"out_trade_no\":\""+ out_trade_no +"\","+ "\"trade_no\":\""+ trade_no +"\","+ "\"refund_amount\":\""+ refund_amount +"\","+ "\"refund_reason\":\""+ refund_reason +"\","+ "\"out_request_no\":\""+ out_request_no +"\"}");// //请求// String result = alipayClient.pageExecute(alipayRequest).getBody();//get请求方式,返回http链接AlipayTradeRefundResponse respose = alipayClient.execute(alipayRequest,"get");AjaxResult result = aliPayService.reFund(respose,1,orderDetail);return result;}catch (AlipayApiException e){e.printStackTrace();log.info("与支付宝交互出错,未能退款,请检查代码!");return AjaxResult.error("与支付宝交互错误,请联系管理员");}}
5,参考文档
第三方授权
https://docs.open.alipay.com/20160728150111277227/intro
第三方沙盒
https://openclub.alipay.com/read.php?tid=1649&fid=43
电脑网站支付指南
https://openclub.alipay.com/read.php?tid=4869&fid=58
//后台逻辑
https://blog.csdn.net/Ouyzc/article/details/79551714
https://segmentfault.com/a/1190000012700062
//自查错误网站
https://openclub.alipay.com/read.php?tid=4869&fid=58#anchor12
