#java版支付宝app支付流程及原理分析
本实例是基于springmvc框架编写springboot架构
一. 流程步骤
官方文档链接:https://docs.open.alipay.com.
1.执行流程
- 当手机端app(就是你公司开发的app)在支付页面时,调起服务端(后台第1个创建订单接口)接口,后台把需要调起支付宝支付的参数返回给手机端,手机端拿到
-
这些参数后,拉起支付宝支付环境完成支付,完成支付后会调异步通知(第2个接口),此时需要给支付宝返回成功或者失败信息,成功后会调用同步通知(第3个接口)
-
返回支付成功页面,完成整个支付流程。
如图 这里我们要做的即是第 2 . 3两步 讲支付宝统一下单API中所需求的参数按照既定的加密方式传入---->获得签名后的订单信息返回给前端 ,然后前端根据签名后的订单信息去调用支付宝支付请求的sdk发起支付(注意:这个时候如果你的手机上安装了支付宝则会弹出支付宝支付界面输入支付宝支付密码完成支付,如果手机未安装支付宝app则跳转至网页登录支付宝后完成后续支付操作)
public static String payOrder("调用支付时需要传入的参数 比如订单号,订单金额等") {
AlipayClient alipayClient = new DefaultAlipayClient(AliPayConfig.URL, AliPayConfig.APPID,
AliPayConfig.RSA_PRIVATE_KEY, AliPayConfig.FORMAT, AliPayConfig.CHARSET, AliPayConfig.ALIPAY_PUBLIC_KEY,
AliPayConfig.SIGNTYPE);
AlipayTradeAppPayRequest aliRequest = new AlipayTradeAppPayRequest();
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
String out_trade_no = order.getId() + "";
model.setBody("你的支付信息");
model.setSubject("支付标题" + order.getId());
model.setOutTradeNo(out_trade_no);
model.setTimeoutExpress("30m");//订单的实效m以分为单位 这里我填的是30分钟
Double amount = DoubleArith.div(order.getFreight().doubleValue(), 100.00, 2);//支付宝的订单金额以元为单位换算 这里需要转换成元0.01==>1分
// model.setTotalAmount(amount + "");// 订单价格
System.out.println(amount);
if (SwitchPayCommon.IS_REAL) {
model.setTotalAmount(amount.toString());
}else {
model.setTotalAmount(0.01 + "");
}
model.setProductCode("QUICK_MSECURITY_PAY");
model.setSellerId(AliPayConfig.SELLER_ID);// 商户id
aliRequest.setBizModel(model);
aliRequest.setNotifyUrl(AliPayConfig.notify_url);
String orderStr = "";
try {
AlipayTradeAppPayResponse aliResponse = alipayClient.sdkExecute(aliRequest);
orderStr = aliResponse.getBody();//
} catch (AlipayApiException e) {
e.printStackTrace();
logger.error("发起预支付失败的原因是:", e);
}
return orderStr;
}
在前端调用SDK完成支付之后,我们还需要定义一个接口来接收支付宝的异步请求访问---->回调接口(这个接口地址在你调用支付获取签名后订单信息的时候作为签名的必须参数传入,支付宝会根据你的订单支付结果向你的回调接口返回订单的支付结果—>具体信息详见参数列表)
支付宝配置config
public class AliPayConfig {
/**
* 1.商户appid
*/
public static final String APPID = "支付宝官方分配给你的appid2019开头的一串数字";
/**
* 2.私钥 pkcs8格式的
*/
public static final String RSA_PRIVATE_KEY ="你在官网根据支付宝提供的RSAwhith...算法得到的一串字符串";
/**
* 3.支付宝公钥
*/
public static final String ALIPAY_PUBLIC_KEY = "同上";
/**
* 4.服务器异步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
*/
//public static final String notify_url = "你的回调地址"; 当然测试环境下你可以 使用一些穿透工具来模拟外网地址填在这里 只要后面的接口能访问到就没问题
/**
* 5.页面跳转同步通知页面路径 需http://或者https://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问 商户可以自定义同步跳转地址
*/
public static final String return_url = "http://www.xxx.com/alipay/return_url.do";
/**
* 6.请求支付宝的网关地址
*/
public static final String URL = "https://openapi.alipay.com/gateway.do";
/**
* 7.编码
*/
public static final String CHARSET = "UTF-8";
/**
* 8.返回格式
*/
public static final String FORMAT = "json";
/**
* 9.加密类型
*/
public static final String SIGNTYPE = "RSA2";
/**
* 10.商家支付宝账号
*/
public static final String SELLER_ID="你的商家支付宝账号";
}
支付宝回调:
//支付宝回调处理
@PostMapping("aliPayInquiryNotify")
@ApiOperation(value = "支付宝回调接口",notes = "支付宝回调接口")
public String aliPayNotify(HttpServletRequest request) throws UnsupportedEncodingException, AlipayApiException, ParseException {
Map<String, String> params = new HashMap<String, String>();
Map<?, ?> requestParams = request.getParameterMap();
for (Iterator<?> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
String[] values = (String[]) requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
if (name.equals("trade_status")) {
logger.info("交易状态为:" + valueStr);
System.out.println("交易状态为:" + valueStr);
}
params.put(name, valueStr);
}
//根据官网信息 支付宝回调的参数必须进行验证 一下是初步验证方法, 后续你还可以验证订单id和你提交支付的订单id是否一致等,根据个人
boolean flag = AlipaySignature.rsaCheckV1(params, AliPayConfig.ALIPAY_PUBLIC_KEY, AliPayConfig.CHARSET, AliPayConfig.SIGNTYPE);
//以下是在写你自己的逻辑时可能用到的一些参数,如果你想使用更多可以去官网查看返回参数列表
//获取订单状态
String tradeStatus =params.get("trade_status");
//订单号
String out_trade_no = params.get("out_trade_no");
//支付宝交易号
String trade_no = params.get("trade_no");
//交易时间
String gmt_payment = params.get("gmt_payment");
//交易金额 单位为元
String total_amount =params.get("total_amount");
//商家在交易中实际收到的款项,单位为元
String receipt_amount =params.get("receipt_amount");
//订单描述
String body = params.get("body");
if (flag) {//验证成功
//订单状态为支付成功时,你可以在下面写你的业务逻辑.如:产生账单、订单状态变更为已支付订单、等逻辑
if (tradeStatus.equals("TRADE_FINISHED") || tradeStatus.equals("TRADE_SUCCESS")) {
//这里可以写你自己的操作逻辑
return "success";
System.out.println("fail");
return "fail";
}
//返回码
return "fail";
} else {
//验证失败
System.out.println(">>>>>验签失败" );
System.out.println(">>>>>交易被关闭了");
//这里写验证失败的业务处理
return "fail";
}
}
不论你自己的逻辑成功或者失败都要给支付宝返回相应 的success 或者fail
总体来说你只需要注意两个接口:1,统一下单接口(根据官方的api来填写请求数据) 2,回调接口(这里强调一下,支付宝回调如果你的返回值为fail时 他会根据不同的时间间隔重复发起7次回调所以–>>>>幂等机制你必须要在写你自己的逻辑时注意–>避免订单的重复支付造成的金额损失,比如充值时多次给用户平台账户添加金额等操作)
记自己的开发学习总结吧,提升自己的捷径是总结~