APP对接支付宝付款
1、支付宝开发平台:https://openhome.alipay.com/
2、进去沙箱,配置支付密钥


记录下appid,然后设置秘钥;




3、后端代码,配置类
pom文件sdk添加依赖
<!--pom.xml 支付宝sdk -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
@Configuration public class AppPayConfig { /** * 1.商户appid */ public static String APPID = ""; /** * 私钥 pkcs8格式的 * 这个就是我上面说的应用私钥生成 注意这里是私钥 */ public static String RSA_PRIVATE_KEY ="" * 3.支付宝公钥 */ public static String ALIPAY_PUBLIC_KEY = ""; /** * 4.服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 */ //这个着重讲一下..支付完成后,支付宝会通过这个url请求到你的服务端.. //这个url一定是要公网可以访问才行...如果需要测试的话..我后面有讲到.. //这里你可以先写你本地项目的url 例如:localhost:8080/项目名/访问路径 public static String notify_url = "http://4e69yn.natappfree.cc/api/v1/aliPayApp/notify_url"; /** * 5.页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址 */ //这里同上..不做详细说明了.. public static String return_url = "http://4e69yn.natappfree.cc/api/v1/aliPayApp/notify_url"; /** * 正式环境支付宝网关,如果是沙箱环境需更改成https://openapi.alipaydev.com/gateway.do */ public static String URL = "https://openapi.alipaydev.com/gateway.do"; /** * 7.编码 */ public static String CHARSET = "UTF-8"; /** * 私钥 pkcs8格式的 */ // 8.返回格式 public static String FORMAT = "json"; /** * //签名方式 加密类型 */ public static String SIGNTYPE = "RSA2"; }
4、控制层
@RestController @RequestMapping("api/v1/aliPayApp") @Slf4j public class AliPayAppController { @Autowired private AliPayAppService aliPayAppService; /** * 获取支付宝加签后台的订单信息字符串,唤起支付宝APP * @Title: getAliPayOrderStr * @description */ @RequestMapping("/getAliPayOrderStr") @ResponseBody public JsonData getAliPayOrderStr(@RequestParam("userId") Integer userId, @RequestParam("videoId") Integer videoId) { String aliPayOrderStr = aliPayAppService.getAliPayOrderStr(userId, videoId); return JsonData.buildSuccess(aliPayOrderStr); } /** * 支付宝支付成功后.异步请求该接口 * @Title: notify */ @RequestMapping(value="/notify_url",method= RequestMethod.POST) @ResponseBody public JsonData notify(HttpServletRequest request, HttpServletResponse response) throws IOException { log.info("支付宝异步返回支付结果开始"); // 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 = aliPayAppService.notify(conversionParams); if (status.equals("fail")){ return JsonData.buildError("订单修改失败"); }else { return JsonData.buildSuccess("订单修改失败"); } } /** * 向支付宝发起订单查询请求 * @Title: checkAlipay * @description * @param orderNo 商户订单号 */ @RequestMapping("/checkAlipay") @ResponseBody public JsonData checkAlipay(String orderNo) { int result = aliPayAppService.checkAlipay(orderNo); return JsonData.buildSuccess(result); } /** * 向支付宝发起退款请求 * @Title: alipayTradeRefund * @description * @param orderNo 商户订单号 * @param refundFee 退款金额 */ @RequestMapping("/alipayTradeRefund") @ResponseBody public JsonData alipayTradeRefund(String orderNo, Double refundFee) { String tradeRefund = aliPayAppService.alipayTradeRefund(orderNo, refundFee); return JsonData.buildSuccess(tradeRefund); } }
5、service层
/** * 支付宝APP支付业务层接口 */ public interface AliPayAppService { /** * 获取支付宝加签后台的订单信息字符串 */ public String getAliPayOrderStr(Integer userId, Integer videoId); /** * 支付宝异步请求逻辑处理 */ public String notify(Map<String, String> conversionParams); /** * 向支付宝发起订单查询请求 */ public int checkAlipay(String order_no); /** * 向支付宝发起退款请求 */ public String alipayTradeRefund(String order_no, Double refund_fee); }
6、serviceImpl层
/** * 阿里支付实现类 */ @Service @Slf4j public class AliPayAppServiceImpl implements AliPayAppService { @Autowired private AliPayAppService aliPayAppService; @Autowired private VideoOrderMapper videoOrderMapper; @Autowired private VideoMapper videoMapper; /** * 获取支付宝加签后台的订单信息字符串 */ @Override @Transactional(propagation = Propagation.REQUIRED) public String getAliPayOrderStr(Integer userId, Integer videoId) { String orderString = ""; try { Video video = videoMapper.selectById(videoId); //AppUser appUser = appUserMapper.selectById(userId); //生成订单 VideoOrder videoOrder = new VideoOrder(); videoOrder.setVideoId(video.getId()); videoOrder.setOutTradeNo(CommonUtils.generateUUID()); videoOrder.setState(0); videoOrder.setCreateTime(new Date()); videoOrder.setTotalFee(video.getPrice()); videoOrder.setVideoId(video.getId()); videoOrder.setVideoTitle(video.getTitle()); videoOrder.setVideoImg(video.getCoverImg()); videoOrder.setUserId(userId); //生成未支付订单 videoOrderMapper.insert(videoOrder); //实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型),为了取得预付订单信息 AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID, AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8", AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2"); //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay AlipayTradeAppPayRequest ali_request = new AlipayTradeAppPayRequest(); //SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式 AlipayTradeAppPayModel model = new AlipayTradeAppPayModel(); //业务参数传入,可以传很多,参考API //model.setPassbackParams(URLEncoder.encode(request.getBody().toString())); //公用参数(附加数据) //对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。 model.setBody("云讯网购买视频课程"); //商品名称 model.setSubject(videoOrder.getVideoTitle()); //商户订单号 model.setOutTradeNo(videoOrder.getOutTradeNo()); //交易超时时间 这里的30m就是30分钟 model.setTimeoutExpress("30m"); //支付金额 后面保留2位小数点..不能超过2位 // model.setTotalAmount(String.valueOf(BigDecimal.valueOf(videoOrder.getTotalFee()).divide(BigDecimal.valueOf(100),2,BigDecimal.ROUND_DOWN))); model.setTotalAmount("0.01"); //销售产品码(固定值) //这个不做多解释..看文档api接口参数解释 model.setProductCode("FACE_TO_FACE_PAYMENT"); //model.setPassbackParams(JSON.toJSONString(alipayBean)); ali_request.setBizModel(model); //异步回调地址 ali_request.setNotifyUrl(AppPayConfig.notify_url); //log.info("====================异步通知的地址为:" + ali_request.getNotifyUrl()); //同步回调地址(APP)同上 ali_request.setReturnUrl(AppPayConfig.return_url); //log.info("====================同步通知的地址为:" + ali_request.getReturnUrl()); // 这里和普通的接口调用不同,使用的是sdkExecute //返回支付宝订单信息(预处理) AlipayTradeAppPayResponse alipayTradeAppPayResponse = alipayClient.sdkExecute(ali_request); //就是orderString 可以直接给APP请求,无需再做处理。 orderString = alipayTradeAppPayResponse.getBody(); System.out.println(orderString); } catch (Exception e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); log.info("与支付宝交互出错,未能生成订单,请检查代码!"); } return orderString; } /** * 向支付宝发起订单查询请求 */ @Override public int checkAlipay(String orderNo) { log.info("向支付宝发起查询,查询商户订单号为:" + orderNo); try { // 实例化客户端(参数:网关地址、商户appid、商户私钥、格式、编码、支付宝公钥、加密类型) AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID, AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8", AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2"); AlipayTradeQueryRequest alipayTradeQueryRequest = new AlipayTradeQueryRequest(); alipayTradeQueryRequest.setBizContent("{" + "\"out_trade_no\" : \"" + orderNo + "\"}"); AlipayTradeQueryResponse alipayTradeQueryResponse = alipayClient.execute(alipayTradeQueryRequest); if (alipayTradeQueryResponse.isSuccess()) { VideoOrder videoOrder = videoOrderMapper.selectById(orderNo); switch (alipayTradeQueryResponse.getTradeStatus()) // 判断交易结果 { case "TRADE_FINISHED": // 交易结束并不可退款 videoOrder.setState(3); break; case "TRADE_SUCCESS": // 交易支付成功 videoOrder.setState(1); break; case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款 videoOrder.setState(2); break; case "WAIT_BUYER_PAY": // 交易创建并等待买家付款 videoOrder.setState(0); break; default: break; } videoOrderMapper.updateById(videoOrder);// 更新表记录 return videoOrder.getState(); } else { log.info("调用支付宝查询接口失败!"); } } catch (AlipayApiException e) { e.printStackTrace(); } return 0; } /** * 支付宝异步请求逻辑处理 */ @Override public String notify(Map<String, String> conversionParams) { log.info("支付宝异步请求逻辑处理"); // 签名验证(对支付宝返回的数据验证,确定是支付宝返回的) boolean signVerified = false; try { // 调用SDK验证签名 signVerified = AlipaySignature.rsaCheckV1(conversionParams, AppPayConfig.ALIPAY_PUBLIC_KEY, "utf-8", "RSA2"); } catch (AlipayApiException e) { log.info("验签失败 !"); e.printStackTrace(); } // 对验签进行处理 if (signVerified) { System.out.println("验签通过"); // 验签通过 // 获取需要保存的数据 String appId = conversionParams.get("app_id");// 支付宝分配给开发者的应用Id String notifyTime = conversionParams.get("notify_time");// 通知时间:yyyy-MM-dd HH:mm:ss String gmtCreate = conversionParams.get("gmt_create");// 交易创建时间:yyyy-MM-dd HH:mm:ss String 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 buyerId = conversionParams.get("buyer_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");// 获取交易状态 // 支付宝官方建议校验的值(out_trade_no、total_amount、sellerId、app_id) VideoOrder videoOrder = videoOrderMapper.selectOne(new QueryWrapper<VideoOrder>().eq("out_trade_no", outTradeNo)); if (videoOrder != null && totalAmount.equals(videoOrder.getTotalFee().toString())) { // 修改数据库支付宝订单表(因为要保存每次支付宝返回的信息到数据库里,以便以后查证) // alipaymentOrder.setNotify_time(DateUtils.parse(notifyTime)); // 通知时间 // alipaymentOrder.setGmt_create(DateUtils.parse(gmtCreate)); // 交易创建时间 // alipaymentOrder.setGmt_payment(DateUtils.parse(gmtPayment)); // 交易付款时间 // //alipaymentOrder.setGmt_refund(DateUtils.parse(gmtRefund)); // 交易退款时间 // //alipaymentOrder.setGmt_close(DateUtils.parse(gmtClose)); // 交易结束时间 // alipaymentOrder.setTrade_no(tradeNo); // 支付宝交易号 // //alipaymentOrder.setOut_biz_no(outBizNo); // 商户业务号(商户业务ID,主要是退款通知中返回退款申请的流水号) // alipaymentOrder.setBuyer_logon_id(buyerLogonId); // 买家支付宝账号 // alipaymentOrder.setBuyer_id(buyerId); // 买家支付宝用户号(唯一) // alipaymentOrder.setSeller_id(sellerId); // 卖家支付宝用户号 // alipaymentOrder.setSeller_email(sellerEmail); // 卖家支付宝账号 // alipaymentOrder.setTotal_amount(Double.parseDouble(totalAmount)); //订单金额:本次交易支付的订单金额,单位为人民币(元) // alipaymentOrder.setReceipt_amount(Double.parseDouble(receiptAmount)); // 实收金额:商家在交易中实际收到的款项,单位为元 // //alipaymentOrder.setInvoiceAmount(Double.parseDouble(invoiceAmount)); // 开票金额:用户在交易中支付的可开发票的金额 // alipaymentOrder.setBuyer_pay_amount(Double.parseDouble(buyerPayAmount)); // 付款金额:用户在交易中支付的金额 switch (tradeStatus) // 判断交易结果 { case "TRADE_FINISHED": // 交易结束并不可退款 videoOrder.setState(3); break; case "TRADE_CLOSED": // 未付款交易超时关闭或支付完成后全额退款 videoOrder.setState(2); break; case "TRADE_SUCCESS": // 交易支付成功 videoOrder.setState(1); break; case "WAIT_BUYER_PAY": // 交易创建并等待买家付款 videoOrder.setState(0); break; default: break; } int returnResult = videoOrderMapper.updateById(videoOrder); // 更新交易表中状态 if (tradeStatus.equals("TRADE_SUCCESS")) { // 只处理支付成功的订单: // 修改交易表状态,支付成功 if (returnResult > 0) { log.info("======更新商户订单表成功======"); 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"; } } /** * 向支付宝发起退款请求 */ @Transactional(propagation = Propagation.REQUIRED) @Override public String alipayTradeRefund(String order_no, Double refund_fee) { String returnStr = null; int code; try { AlipayClient alipayClient = new DefaultAlipayClient(AppPayConfig.URL, AppPayConfig.APPID, AppPayConfig.RSA_PRIVATE_KEY, "json", "utf-8", AppPayConfig.ALIPAY_PUBLIC_KEY, "RSA2"); AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();//创建API对应的request类 request.setBizContent("{" + " \"out_trade_no\":\"" + order_no + "\"," + " \"refund_amount\":\"" + refund_fee + "\"" + " }");//设置业务参数 AlipayTradeRefundResponse response = alipayClient.execute(request);//通过alipayClient调用API,获得对应的response类 log.info("退款返回参数====" + response); if (response.isSuccess()) { log.info("====支付宝退款成功"); // 通过订单号查询到商家支付宝订单信息 VideoOrder videoOrder = videoOrderMapper.selectOne(new QueryWrapper<VideoOrder>().eq("out_trade_no", order_no)); if (videoOrder == null) { log.info("该订单不存在"); } // // 退款总金额 // videoOrder.setRefund_fee(Double.valueOf(response.getRefundFee())); // // 退款时间 // alipaymentOrder.setGmt_refund(response.getGmtRefundPay()); // // 退款状态 // alipaymentOrder.setTrade_status(AlipayReturnEnum.TRADE_CLOSED.getIndex()); // // 本次退款是否发生了资金变化 // alipaymentOrder.setFund_change(response.getFundChange()); // // 交易在支付时候的门店名称 // alipaymentOrder.setStore_name(response.getStoreName()); videoOrder.setState(2); // 修改商家支付宝订单状态以及退款金额 videoOrderMapper.updateById(videoOrder); returnStr = response.getMsg(); } else { // 返回退款失败消息 log.info("===退款失败===原因:" + response.getSubMsg()); returnStr = response.getSubMsg(); } code = Integer.parseInt(response.getCode()); } catch (Exception e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return returnStr; } }
浙公网安备 33010602011771号