支付宝App支付
第一步:客户端调服务端的统一下单接口,服务器端在支付宝平台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付
1 package com.kpcx.pay.alipay; 2 3 4 import java.io.IOException; 5 import java.net.URLDecoder; 6 import java.util.HashMap; 7 import java.util.Map; 8 import java.util.ResourceBundle; 9 import javax.servlet.ServletException; 10 import javax.servlet.annotation.WebServlet; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 import com.alibaba.fastjson.JSON; 15 import com.alibaba.fastjson.JSONObject; 16 import com.alipay.api.AlipayApiException; 17 import com.alipay.api.AlipayClient; 18 import com.alipay.api.DefaultAlipayClient; 19 import com.alipay.api.domain.AlipayTradeAppPayModel; 20 import com.alipay.api.request.AlipayTradeAppPayRequest; 21 import com.alipay.api.response.AlipayTradeAppPayResponse; 22 import com.kpcx.controller.NotifyController; 23 import com.kpcx.util.JSONSerializer; 24 /** 25 * 支付宝创建订单接口 26 * 27 * @see get请求 28 * @Title: 支付宝创建订单接口 29 * @author: 孟丛丛 30 * @param: param 31 * @return: Object 32 * @Time :2017-05-23 33 * 先调用该接口在微信支付服务后台生成预支付交易单,返回正确的预支付交易回话标识后再在APP里面调起支付 34 */ 35 @WebServlet(name = "ZfbOrderCreate", urlPatterns = "/create/zfbOrderCreate") 36 public class ZfbOrderCreate2 extends HttpServlet { 37 38 private static final long serialVersionUID = 1L; 39 /** 40 * @see 支付宝创建订单接口 41 */ 42 protected void doGet(HttpServletRequest request, HttpServletResponse response) 43 throws ServletException, IOException { 44 String param = URLDecoder.decode(request.getParameter("param"),"UTF-8"); 45 46 AlipayTradeAppPayModel model = JSON.parseObject(param, AlipayTradeAppPayModel.class); 47 NotifyController ncController = new NotifyController(); 48 String outTradeNo = model.getOutTradeNo();//订单号 49 String totalAmount = model.getTotalAmount();//支付金额 50 String checkOrders = ncController.checkOrders(outTradeNo, totalAmount); 51 52 //这是订单支付前校验,校验金额、支付状态(避免已经用别的支付方式已经支付)、是否已取消 53 JSONObject checkOrdersO = JSONObject.parseObject(checkOrders); 54 checkOrdersO.remove("Result"); 55 checkOrdersO.put("Result", outTradeNo); 56 String code = checkOrdersO.getString("Code"); 57 58 if(code!=null&&"0".equals(code)){ 59 //获取资源文件 60 ResourceBundle resource = ResourceBundle.getBundle("kpcxPay"); //kpcxPay是一个.properties文件 61 //实例化客户端 62 AlipayClient alipayClient = new DefaultAlipayClient(resource.getString("URL"), resource.getString("APP_ID"),resource.getString("APP_PRIVATE_KEY"), resource.getString("FORMAT"), resource.getString("CHARSET"), resource.getString("ALIPAY_PUBLIC_KEY"), resource.getString("SIGN_TYPE")); 63 64 //实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay 65 AlipayTradeAppPayRequest requestPay = new AlipayTradeAppPayRequest(); 66 requestPay.setBizModel(model); 67 requestPay.setNotifyUrl(resource.getString("notifyUrl")); 68 try { 69 //这里和普通的接口调用不同,使用的是sdkExecute 70 AlipayTradeAppPayResponse responsePay = alipayClient.sdkExecute(requestPay); 71 String orderInfo=responsePay.getBody(); 72 Map map = new HashMap(); 73 map.put("Code", 0); 74 map.put("Result",orderInfo); 75 String jsons = JSONSerializer.serialize(map); 76 response.getWriter().write(jsons); 77 //结果返回到filter,记录到日志中 78 request.setAttribute("outStr", jsons); 79 80 } catch (AlipayApiException e) { 81 e.printStackTrace(); 82 } 83 }else{ 84 response.getWriter().write(checkOrdersO.toString()); 85 //结果返回到filter,记录到日志中 86 request.setAttribute("outStr", checkOrdersO.toString()); 87 } 88 89 } 90 /** 91 * @see post请求 92 */ 93 protected void doPost(HttpServletRequest request, HttpServletResponse response) 94 throws ServletException, IOException { 95 doGet(request, response); 96 } 97 }
第二步:客户端根据服务端返回的参数,成功调起app支付,并支付成功,服务端等待支付宝的异步推送
1 package com.kpcx.pay.alipay; 2 3 import java.io.IOException; 4 import java.util.HashMap; 5 import java.util.Iterator; 6 import java.util.Map; 7 import java.util.ResourceBundle; 8 9 import javax.servlet.ServletException; 10 import javax.servlet.annotation.WebServlet; 11 import javax.servlet.http.HttpServlet; 12 import javax.servlet.http.HttpServletRequest; 13 import javax.servlet.http.HttpServletResponse; 14 15 import org.slf4j.Logger; 16 import org.slf4j.LoggerFactory; 17 18 import com.alibaba.fastjson.JSONObject; 19 import com.alipay.api.internal.util.AlipaySignature; 20 import com.kpcx.controller.NotifyController; 21 import com.kpcx.service.PaymentService; 22 import com.kpcx.service.impl.PaymentServiceImpl; 23 24 /** 25 * 支付宝创建订单回调接口 26 * 27 * @see get请求 28 * @Title: 支付宝创建订单回调接口 29 * @author: 孟丛丛 30 * @param: param 31 * @return: Object 32 * @Time :2017-05-23 调用支付宝支付接口成功后调用此接口,更新快票出行订单状态及支付方式 33 */ 34 @WebServlet(name = "ZfbOrderNotify", urlPatterns = "/zfbOrderNotify") 35 public class ZfbOrderNotifyNew2 extends HttpServlet { 36 37 /** 38 * 39 */ 40 private static final long serialVersionUID = 1L; 41 protected Logger logger = LoggerFactory.getLogger(getClass()); 42 ResourceBundle resource1 = ResourceBundle.getBundle("jkUrl"); 43 44 /** 45 * @see get请求 46 */ 47 protected void doGet(HttpServletRequest request, HttpServletResponse response) 48 throws ServletException, IOException { 49 // 获取支付宝POST过来反馈信息 50 Map<String, String> params = new HashMap<String, String>(); 51 Map<String, String[]> requestParams = request.getParameterMap(); 52 for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext();) { 53 String name = (String) iter.next(); 54 String[] values = (String[]) requestParams.get(name); 55 String valueStr = ""; 56 for (int i = 0; i < values.length; i++) { 57 valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; 58 } 59 // 乱码解决,这段代码在出现乱码时使用。 60 params.put(name, valueStr); 61 } 62 63 params.remove("sign_type");// 移除sign_type 64 ResourceBundle resource = ResourceBundle.getBundle("kpcxPay"); 65 try { 66 //验签 67 boolean flag = AlipaySignature.rsaCheckV2(params, resource.getString("ALIPAY_PUBLIC_KEY"),resource.getString("CHARSET"), resource.getString("SIGN_TYPE")); 68 //回调及验签成功 69 if (flag==true && params.get("trade_status").equals("TRADE_SUCCESS")==true) { 70 // 如果回调成功,进行服务器端订单处理 71 /** 72 * 一系列的判断处理 73 * 1、查看该订单是否是自己的单子 74 * 2、查看该订单的支付状态是否是未支付 75 * 3、查看该订单的金额和支付宝返回的金额是否一致 76 * 4、保存支付数据 77 * 5、更新支付状态 78 * 6、判断完成、插完支付数据自己想要做的操作 79 * 注意:4、5部要加同步锁,防止几个回调同时对数据的操作 80 * 81 */ 82 } 83 84 } catch (Exception e) { 85 e.printStackTrace(); 86 } 87 88 } 89 @Override 90 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { 91 doGet(req, resp); 92 } 93 94 95 }
- 必须保证服务器异步通知页面(notify_url)上无任何字符,如空格、HTML标签、开发系统自带抛出的异常提示信息等;
- 支付宝是用POST方式发送通知信息,因此该页面中获取参数的方式,如:request.Form(“out_trade_no”)、$_POST[‘out_trade_no’];
- 支付宝主动发起通知,该方式才会被启用;
- 只有在支付宝的交易管理中存在该笔交易,且发生了交易状态的改变,支付宝才会通过该方式发起服务器通知(即时到账交易状态为“等待买家付款”的状态默认是不会发送通知的);
- 服务器间的交互,不像页面跳转同步通知可以在页面上显示出来,这种交互方式是不可见的;
- 第一次交易状态改变(即时到账中此时交易状态是交易完成)时,不仅会返回同步处理结果,而且服务器异步通知页面也会收到支付宝发来的处理结果通知;
- 程序执行完后必须打印输出“success”(不包含引号)。如果商户反馈给支付宝的字符不是success这7个字符,支付宝服务器会不断重发通知,直到超过24小时22分钟。一般情况下,25小时以内完成8次通知(通知的间隔频率一般是:4m,10m,10m,1h,2h,6h,15h);
- 程序执行完成后,该页面不能执行页面跳转。如果执行页面跳转,支付宝会收不到success字符,会被支付宝服务器判定为该页面程序运行出现异常,而重发处理结果通知;
- cookies、session等在此页面会失效,即无法获取这些数据;
- 该方式的调试与运行必须在服务器上,即互联网上能访问;
- 该方式的作用主要防止订单丢失,即页面跳转同步通知没有处理订单更新,它则去处理;
- 当商户收到服务器异步通知并打印出success时,服务器异步通知参数notify_id才会失效。也就是说在支付宝发送同一条异步通知时(包含商户并未成功打印出success导致支付宝重发数次通知),服务器异步通知参数notify_id是不变的
来源:https://www.cnblogs.com/lmcc/p/7992740.html