支付宝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
