如今生活中无时无刻的在使用者支付功能,最常见的支付平台"支付宝""微信"今天就来介绍一下java后端如何集成支付宝应用(使用沙箱环境 无需企业认证)
支付宝开发者平台地址
支付宝将与服务端交互的接口(OpenAPI)封装在开发工具包(SDK)中,开发者无需自行实现同服务端交互的复杂逻辑,直接将 SDK 导入自己的工程后,通过 OpenAPI 的示例代码实现同支付宝服务端的交互。支付宝javaSDK下载地址
如果是采用maven 可直接将sdk 导入到pom文件中
<!-- alipay sdk 支付依赖 --> <dependency> <groupId>com.alipay.sdk</groupId> <artifactId>alipay-sdk-java</artifactId> <version>4.13.0.ALL</version> </dependency> <!--依赖支付的空判断--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.10</version> </dependency> 123456789101112
下面这段话是参考其他博主描述参考文档地址
首先,我们来理一理开发的思路,按照我当前项目的需求,关于支付这一块大概操作流程是:用户在APP上选好要购买的商品,点击“立即购买”,跳转到订单详细页面。选择支付方式,点击“确定支付”跳转到支付宝APP,付款完成后,跳转回APP,完成支付。这个过程,当用户点击“确定支付”时,APP需要调用商户后台接口。
这时候就是我们所需要做的事情:先是生成商户系统一笔未支付的订单,获得商户订单ID(商户系统生成)和订单的一些其他信息,然后再调用支付宝的SDK提供的数字签名方法,将需要传给支付宝的信息进行加签,然后把加签后的字符串返回给APP。APP拉起支付宝APP,再把这个加签的字符串传给支付宝,完成支付。APP接收到同步通知后,还需要再次调用商户后台的接口(虽然同步通知也有付款情况,但需要以后台通知为准),校验订单最终的付款情况。按照支付宝API上所说,当完成支付后,支付宝会做2个操作,一个是同步返回信息给APP,一个是异步通知商户后台返回支付状态等信息,并且最终的支付结果是以异步通知为准。所以我们还需要考虑到一点,就是当用户支付成功之后,商户系统暂时没有接收到支付宝的异步通知时。我们需要拿着这个商户订单ID主动调用SDK支付宝的查询接口,去获取该订单的支付情况,并最终返回给APP。这个查询的接口应该是给APP收到同步通知后,请求商户系统后台进行校验的时候调用的。
根据我们上面思考所得,后台只需要对外提供3个接口即可
1.用户点击“立即购买”时调用商户后台接口,后台返回加签后的订单信息字符串
2.在支付完成之后,支付宝异步通知商户后台订单的付款情况
3.在支付完成之后,跳转回APP时,APP调用商户后台进行最终付款校验
下面开始编写代码
public class AlipayConfig {// 1.商户appidpublic static String APPID = "2021xxxx693113";// 2.私钥 pkcs8格式的public static String RSA_PRIVATE_KEY = "MIIE...";// 3.支付宝公钥public static String ALIPAY_PUBLIC_KEY = "MIIB...";// 4.服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参 数,必须外网可以正常访问public static String notify_url = "http://xxx:8080/Health/alipay/notify_url.do";// 5.页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义 参数,必须外网可以正常访问// 商户可以自定义同步跳转地址public static String return_url = "http://xxx:8080/Health/alipay/return_url.do";// 6.请求支付宝的网关地址public static String URL = "https://openapi.alipaydev.com/gateway.do";// 7.编码public static String CHARSET = "UTF-8";// 8.返回格式public static String FORMAT = "json";// 9.加密类型public static String SIGNTYPE = "RSA2"; }
1234567891011121314151617181920212223242526272829303132 2、实现第一个接口:用户点击“立即购买”时调用商户后台接口,后台返回加签后的订单信息字符串。写一个生成订单号的类 每次有交易让程序自动生成一个OutTradeNo
public class GenerateNum {// 全局自增数 private static int count = 0; // 每毫秒秒最多生成多少订单(最好是像9999这种准备进位的值) private static final int total = 99; // 格式化的时间字符串 private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); // 获取当前时间年月日时分秒毫秒字符串 private static String getNowDateStr() { return sdf.format(new Date()); } // 记录上一次的时间,用来判断是否需要递增全局数 private static String now = null; /* 生成一个订单号 */ public static String generateOrder() { String datastr = getNowDateStr(); if (datastr.equals(now)) { count++;// 自增 } else { count = 1; now = datastr; } int countInteger = String.valueOf(total).length() - String.valueOf(count).length();// 算补位 String bu = "";// 补字符串 for (int i = 0; i < countInteger; i++) { bu += "0"; } bu += String.valueOf(count); if (count >= total) { count = 0; } return datastr + bu; } }
123456789101112131415161718192021222324252627282930313233343536373839404142Controller层 大家可以更具自己的具体业务来编写
/** * 获取支付宝加签后台的订单信息字符串 * @param request * @param response * @return */@RequestMapping(value = "getOrderInfo.do", produces = "application/json,charset=UTF-8", method = RequestMethod.POST)@ResponseBodypublic String getOrderInfo(HttpServletRequest request, HttpServletResponse response) {int userid = Integer.valueOf(request.getParameter("userid"));String totalAmount = request.getParameter("totalAmount");int effectiveDay = Integer.valueOf(request.getParameter("effectiveDay"));PayDto payDto = new PayDto();payDto.setEffectiveDay(effectiveDay);payDto.setOutTradeNo(GenerateNum.generateOrder());payDto.setUserid(userid);payDto.setTotalAmount(totalAmount);return alipayService.alipaytest(payDto);}
12345678910111213141516171819Service层
@Overridepublic String alipaytest(PayDto payDto) {String orderInfo = "";String orderNumber = GenerateNum.generateOrder();// 创建支付宝订单AlipaymentOrder alipaymentOrder = new AlipaymentOrder();alipaymentOrder.setUserid(payDto.getUserid());// 订单用户idalipaymentOrder.setEffectiveDay(payDto.getEffectiveDay());// 获取有效天数alipaymentOrder.setOutTradeNo(payDto.getOutTradeNo());// 后台生成的订单号alipaymentOrder.setTradeStatus(0);// 交易状态alipaymentOrder.setTotalAmount(Double.parseDouble(payDto.getTotalAmount()));// 订单总金额alipaymentOrder.setReceiptAmount(0.00);// 实收金额alipaymentOrder.setInvoiceAmount(0.00);// 开票金额alipaymentOrder.setBuyerPayAmount(0.00);// 付款金额alipaymentOrder.setRefundFee(0.00); // 总退款金额try {// 实例化客户端AlipayClient alipayClient = getAlipayClient(); //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 request = new AlipayTradeAppPayRequest();// SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();model.setBody("我是测试数据");model.setSubject("App支付测试Java");// 商品名称model.setOutTradeNo(payDto.getOutTradeNo());// 交易订单号model.setTimeoutExpress("30m");// 交易超时时间model.setTotalAmount(payDto.getTotalAmount());// 支付金额model.setProductCode("QUICK_MSECURITY_PAY");// 销售产品码(固定值)request.setBizModel(model);request.setNotifyUrl(AlipayConfig.notify_url);// 异步回调地址request.setReturnUrl(AlipayConfig.return_url);// 同步回调地址// 这里和普通的接口调用不同,使用的是sdkExecuteAlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);orderInfo = response.getBody();System.out.println(response.getBody());// 就是orderString 可以直接给客户端请求,无需再做处理。// 创建新的商户支付宝订单this.alipayDao.createAlipayMentOrder(alipaymentOrder);} catch (AlipayApiException e) {e.printStackTrace();}return orderInfo;}
12345678910111213141516171819202122232425262728293031323334353637383940414243444546到此 我们的第一接口 后台返回加签后的字符串已经完成
3、实现第二个接口在支付完成之后,支付宝异步通知商户后台订单的付款情况/** * 支付宝支付成功后,异步请求该参数 * * @param request * @param response * @return */@RequestMapping(value = "notify_url.do", produces = "application/json,charset=UTF-8", method = RequestMethod.POST)@ResponseBodypublic String notify_url(HttpServletRequest request, HttpServletResponse response) {// 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);} //logger.info("==================返回参数集合:" + conversionParams);String status = alipayService.notify(conversionParams);return status;}
12345678910111213141516171819202122232425262728293031Service层
/** * 支付宝异步请求逻辑 */@Overridepublic String notify(Map<String, String> conversionParams) {// 签名验证(对支付宝返回的数据验证,确定是支付宝返回的)boolean signVerified = false;try {// 调用SDK验证签名signVerified = AlipaySignature.rsaCheckV1(conversionParams, AlipayConfig.ALIPAY_PUBLIC_KEY,AlipayConfig.CHARSET, AlipayConfig.SIGNTYPE);} catch (AlipayApiException e) {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");// 卖家支付宝账号Double totalAmount = Double.parseDouble(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)AlipaymentOrder alipaymentOrder = alipayDao.selectByOutTradeNo(outTradeNo);if (alipaymentOrder != null && totalAmount.equals(alipaymentOrder.getTotalAmount())&& AlipayConfig.APPID.equals(appId)) {// 修改数据库支付宝订单表(因为要保存每次支付宝返回的信息到数据库里,以便以后查证)try {System.out.println("yyyyyyyy" + notifyTime);alipaymentOrder.setNotifyTime(dateformat(notifyTime));alipaymentOrder.setGmtCreate(dateformat(gmtCreate));alipaymentOrder.setGmtPayment(dateformat(gmtPayment));alipaymentOrder.setGmtRefund(dateformat(gmtRefund));alipaymentOrder.setGmtClose(dateformat(gmtClose));} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}alipaymentOrder.setTradeNo(tradeNo);alipaymentOrder.setOutBizNo(outBizNo);alipaymentOrder.setBuyerLogonId(buyerLogonId);alipaymentOrder.setSellerId(sellerId);alipaymentOrder.setSellerEmail(sellerEmail);alipaymentOrder.setTotalAmount(totalAmount);alipaymentOrder.setReceiptAmount(Double.parseDouble(receiptAmount));alipaymentOrder.setInvoiceAmount(Double.parseDouble(invoiceAmount));alipaymentOrder.setBuyerPayAmount(Double.parseDouble(buyerPayAmount));switch (tradeStatus) // 判断交易结果{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;}int returnResult = this.alipayDao.updateAlipayMentOrder(alipaymentOrder);if (tradeStatus.equals("TRADE_SUCCESS")) { // 只处理支付成功的订单: 修改交易表状态,支付成功if (returnResult > 0) {return "success";} else {return "fail";}} else {return "fail";}} else {return "fail";}} else { // 验签不通过return "fail";}}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102 4、第三个接口在支付完成之后,跳转回APP时,APP调用商户后台进行最终付款校验。/** * 向支付宝发起订单查询 */@Overridepublic int checkAlipay(String outTradeno) {String responseString = "";AlipayClient alipayClient = getAlipayClient();Map<String,String> paraMap = new HashMap<String,String>();paraMap.put("out_trade_no",outTradeno);//商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复paraMap.put("trade_no",null);// trade_no 即便是空你也得写上 不能省略 !!!!!!!!!!!AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();// 创建API对应的request类request.setBizContent(JSON.toJSONString(paraMap));AlipayTradeQueryResponse alipayTradeQueryResponse;try {alipayTradeQueryResponse = alipayClient.execute(request);responseString = alipayTradeQueryResponse.getBody();System.out.println(responseString);if (alipayTradeQueryResponse.isSuccess()) {AlipaymentOrder alipaymentOrder = alipayDao.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.alipayDao.updateAlipayMentOrder(alipaymentOrder); // 更新表记录return alipaymentOrder.getTradeStatus();} else {}} catch (AlipayApiException e) {// TODO Auto-generated catch blocke.printStackTrace();} // 通过alipayClient调用API,获得对应的response类return 0;}
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657到此 我们的三个接口已近全部完成 是不是没有想象中的那么复杂呢
在通过订单号查询交易记录的时候我们穿了两个值 一个是outTradeNo(后台生成) 还有一个为TradeNo(支付宝生成)
本以为两个二选一即可 但是测试多边后 即使是trade_no传入null也是要传入 不然会报40004(业务处理失败)
Map<String,String> paraMap = new HashMap<String,String>();paraMap.put("out_trade_no",outTradeno);//商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复paraMap.put("trade_no",null);// trade_no 即便是空你也得写上 不能省略 !!!!!!!!!!! 123
好啦 今天的分享就到这里 本人小白一个 如有问题请多多指教
QQ:2289091393 (请注明来意)
相关知识
app调起支付宝-后端预支付
这是我见过最全的支付系统!一套适合互联网企业使用的开源支付系统
web支付基础教程
Java通用型支付+电商平台双系统实战
基于Java的网上花店网站的设计与开发资源
java毕业设计网上花店商城的设计与实现(Springboot+mysql+jdk1.8+maven3.39)
java毕业设计鲜花管理系统的设计与实现(springboot+mysql+jdk1.8+meven)
java计算机毕业设计网上鲜花销售平台设计与实现(开题+程序+论文)
java网上花店鲜花商城鲜花销售管理系统设计与实现项目源代码下载javawebjspsshmysql
【开题报告】基于SpringBoot的鲜花销售系统的设计与实现
网址: java后端实现集成支付宝APP支付(沙箱环境) https://m.huajiangbk.com/newsview849417.html
上一篇: 若依(springboot)集成 |
下一篇: java集成微信支付(完整流程) |