支付宝支付具体流程
支付宝即时到账api https://docs.open.alipay.com/62/103738/
App 支付 https://docs.open.alipay.com/204/105297
app支付宝支付流程
1支付宝APP支付
1,首先创建应用并获取APPID,创建完成后添加app支付流程
2, 应用创建完成后,需要给应用添加App支付功能,这样就可以在你的应用里使用App支付能力。(此时为开发状态,申请上 线后才可以在生成环境中使用)
3,开始签约,配置秘钥
应用公钥:由商户自己生成的RSA公钥(与应用私钥必须匹配),商户需上传应用公钥到支付宝开放平台,以便支付宝使用 该 公钥验证该交易是否是商户发起的。
应用私钥:由商户自己生成的RSA私钥(与应用公钥必须匹配),商户开发者使用应用私钥对请求字符串进行加签。
支付宝公钥:支付宝的RSA公钥,商户使用该公钥验证该结果是否是支付宝返回的。
生成密钥后在开放平台开发者中心进行密钥配置,配置完成后可以获取支付宝公钥。具体方法流程请参见上传应用公钥并获 取 支付宝公钥。。
注:签名验签常见问题排查
支付宝开放平台SDK封装了签名和验签过程,只需配置账号及密钥参数,强烈建议使用。更多签名问题的自助排查流程,可 以 参考支付宝验签专区的未使用开放平台SDK的自助排查流程。关于同步通知和异步通知的验签规则,可参考验签教程。
更多关于签名教程和签名工具下载等问题,请参见签名专区。
4,如何集成服务端SDK下载对应语言的SDK集成到项目中
SDK在使用前需要先初始化
AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
关键参数说明:
配置参数 | 示例值解释 | 获取方式/示例值 |
---|---|---|
URL | 支付宝网关(固定) | https://openapi.alipay.com/gateway.do |
APP_ID | APPID即创建应用后生成 | 获取见上面创建应用并获取APPID |
APP_PRIVATE_KEY | 开发者应用私钥,由开发者自己生成 | 获取见上面配置密钥 |
FORMAT | 参数返回格式,只支持json | json(固定) |
CHARSET | 请求和签名使用的字符编码格式,支持GBK和UTF-8 | 开发者根据实际工程编码配置 |
ALIPAY_PUBLIC_KEY | 支付宝公钥,由支付宝生成 | 获取详见上面配置密钥 |
SIGN_TYPE | 商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用RSA2 | RSA2 |
调用接口
@Override
public String aliAppPay(Product product) {
//查询支付宝配置
PaymentMethod method = paymentMethodService.findByPcode("alipay");
AlipayConfig alipayConfig= JsonUtils.jsonToPojo(method.getParams(), AlipayConfig.class);
String orderString = Constants.FAIL;
//实例化客户端
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", alipayConfig.getAppId(), alipayConfig.getPrivateKey() , "json", "UTF-8", alipayConfig.getAlipayPublicKey(), "RSA2");
//原实例化客户端代码
// AlipayClient alipayClient = AliPayConfig.getAlipayClient();
// 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.app.pay
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
// SDK已经封装掉了公共参数,这里只需要传入业务参数。以下方法为sdk的model入参方式(model和biz_content同时存在的情况下取biz_content)。
AlipayTradeAppPayModel model = new AlipayTradeAppPayModel();
model.setBody(product.getBody());
model.setSubject(product.getSubject());
model.setOutTradeNo(product.getOutTradeNo());
model.setTimeoutExpress("30m");
model.setTotalAmount(product.getTotalFee());
model.setProductCode("QUICK_MSECURITY_PAY");
request.setBizModel(model);
request.setNotifyUrl(alipayConfig.getUrl());
try {
// 这里和普通的接口调用不同,使用的是sdkExecute
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
orderString = response.getBody();//就是orderString 可以直接给客户端请求,无需再做处理。
//System.out.println(response.getBody());
} catch (AlipayApiException e) {
e.printStackTrace();
}
return orderString ;
}
参数名称 | 参数说明 |
---|---|
out_trade_no | 支付时传入的商户订单号,与trade_no必填一个 |
trade_no | 支付时返回的支付宝交易号,与out_trade_no必填一个 |
2,配置完成后分析自己的业务逻辑首先将自己的订单信息和商品信息写入数据库中
3,调用支付接口
支付宝回调是获取所有的地址验证签名
E:AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
System.out.println(response.getBody());//就是orderString 可以直接给客户端请求,无需再做处理
配置回调地址接口
/**
* 支付宝回调
* @param request
* @param response
* @throws Exception
*/
@ApiOperation("支付宝回调")
@PostMapping("/aliPayNotify")
@Transactional
public void aliPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
//查询支付宝配置
PaymentMethod method = paymentMethodService.findByPcode("alipay");
AlipayConfig alipayConfig= JsonUtils.jsonToPojo(method.getParams(), AlipayConfig.class);
String message = "success";
Map<String, String> params = new HashMap<String, String>();
// 取出所有参数是为了验证签名
Enumeration<String> parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String parameterName = parameterNames.nextElement();
params.put(parameterName, request.getParameter(parameterName));
}
logger.info("支付宝回调参数:"+params);
//验证签名 校验签名
boolean signVerified = false;
try {
signVerified = AlipaySignature.rsaCheckV1(params, alipayConfig.getAlipayPublicKey(),"UTF-8","RSA2");
} catch (AlipayApiException e) {
e.printStackTrace();
message = "failed";
logger.error("校验签名异常");
}
if (signVerified) {
logger.info("支付宝验证签名成功!");
// 若参数中的appid和填入的appid不相同,则为异常通知
if (!alipayConfig.getAppId().equals(params.get("app_id"))) {
message = "failed";
logger.info("与付款时的appId不同,支付失败");
}else{
String outtradeno = params.get("out_trade_no");
String status = params.get("trade_status");
if (status.equals("WAIT_BUYER_PAY")) {
logger.info(outtradeno + "正在等待用户付款");
} else if (status.equals("TRADE_CLOSED")) {
logger.info(outtradeno + "订单的状态已经关闭");
} else if (status.equals("TRADE_SUCCESS") || status.equals("TRADE_FINISHED")) {
logger.info("订单号:"+outtradeno+"付款成功");
//查询订单
Recharge info = rechargeService.selectByOrderSn(outtradeno);
if(info != null){
int flag = rechargeService.updateRecharge(info.getRechargeId(),info.getUserId(),info.getCoin(),1,params.get("trade_no"));
if(flag>0){
logger.info("订单号:"+outtradeno+"状态修改成功");
}else{
logger.info("订单号:"+outtradeno+"状态修改失败");
}
}else{
logger.info("订单号:"+outtradeno+"不存在");
}
}
}
} else { // 如果验证签名没有通过
message = "failed";
logger.info("验证签名失败!");
}
BufferedOutputStream out = new BufferedOutputStream(response.getOutputStream());
out.write(message.getBytes());
out.flush();
out.close();
}
2支付宝电脑网站支付
创建应用,配置秘钥,搭建环境都一样只是调用的接口不一样
在接口提供的公共参数中设置回调地址 接受request请求对象后,为开发者生成前台页面请求需要的完整form表单的html
这个表单的String输出到http response中即可
支付宝回调接口
获取到返回的所有参数 先判断是否交易成功trade_status 再做签名校验
1、商户需要验证该通知数据中的out_trade_no是否为商户系统中创建的订单号,
2、判断total_amount是否确实为该订单的实际金额(即商户订单创建时的金额),
3、校验通知中的seller_id(或者seller_email) 是否为out_trade_no这笔单据的对应的操作方(有的时候,一个商户可能有多个seller_id/seller_email),
4、验证app_id是否为该商户本身。上述1、2、3、4有任何一个验证不通过,则表明本次通知是异常通知,务必忽略。在上述验证通过后商户必须根据支付宝不同类型的业务通知,正确的进行不同的业务处理,并且过滤重复的通知结果数据。在支付宝的业务通知中,只有交易通知状态为TRADE_SUCCESS或TRADE_FINISHED时,支付宝才会认定为买家付款成功
取出所有参数是为了验证签名
Enumeration<String> parameterNames = request.getParameterNames();
判断全部通过后 放回状态 success只要有一个失败就返回 failed
1·需要导入所需支付包:alipay-sdk-java.jar 和 commons-logging.jar,具体参考:<服务端SDK>
2·app支付 APP支付不能在沙箱测试、只能申请上线测试
3·关于签名和验签:支付宝开放平台SDK封装了签名和验签过程,只需配置账号及密钥参数,lipaySignature.rsaCheckV1。
4·构造交易数据并签名必须在商户服务端完成,商户的应用私钥绝对不能保存在商户APP客户端中,也不能从服务端下发。
A: 申请即时到账接口所需参数 (appId privateKey alipayPublicKey)
B: 通过参数生产sign(编码和seller_type 不参与签名)
C: 将请求参数发送给前端页面 提交支付宝网关(get 提交)
D: 同步通知和异步通知区别
同步通知是跳转到同步通知的页面是get 提交
异步通知是post 提交
异步通知当状态发生改变就回通知, 而同步通知只有提交页面的时候才通知
F: 异步通知的触发条件
交易成功, 交易失败,创建交易,完成交易
异步通知是在 参数状态改变的是时候发送的异步数据
异步通知只能在服务器中执行
异步通知如果返回的不是 success 会一直发送请求指导 24 小时
G: 支付宝回调是 取出前端的所有参数验证签名是否正确
业务代码
PC端网站支付
app接口支付
@AppLogin
@PostMapping("/payOrder")
@ApiOperation("订单支付")
public R payOrder(HttpServletRequest request,
@ApiParam(required = true, name = "orderId", value = "订单ID") @RequestParam(value = "orderId", required = false) String orderId,
@ApiParam(required = true, name = "totalPrice", value = "订单总价") @RequestParam(value = "totalPrice", required = false) String totalPrice,
@ApiParam(required = true, name = "paymentType", value = "支付类型(1微信,2支付宝)") @RequestParam(value = "paymentType", required = false) String paymentType
) {
try {
//获取头部请求信息中的token 根据token获取userID
String headValue = request.getHeader("APPToken");
Claims claims = jwtUtils.getClaimByToken(headValue);
String userId = claims.getSubject().toString();
//微信支付
if(paymentType.equals(PayType.WECHAT.getCode())){
//构造微信支付订单参数
WxPayConfig wxConfig = new WxPayConfig();
WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
orderRequest.setNonceStr(PublicUtil.getRandomString(32));
orderRequest.setBody("微信支付");
orderRequest.setOutTradeNo(orderId);
orderRequest.setTotalFee(WxPayUnifiedOrderRequest.yuanToFen(totalPrice));
orderRequest.setTradeType("APP");
orderRequest.setSpbillCreateIp(IPUtils.getIpAddr(request));
orderRequest.setNotifyUrl(wxConfig.getNotifyUrl());
//调用统一下单接口,获取"预支付交易会话标识"
WxPayUnifiedOrderResult result = wxPayService.unifiedOrder(orderRequest);
if("SUCCESS".equals(result.getReturnCode())){
WxPayAppOrderResult orderResult = wxPayService.createOrder(orderRequest);
logger.info("调用微信预下单接口返回信息:{}", orderResult);
return R.ok().put("result",orderResult);
} else {
return R.error("获取预支付订单失败");
}
}
//支付宝支付
if(paymentType.equals(PayType.ALI.getCode())){
//构造支付宝订单参数
Product product = new Product();
product.setBody("支付宝支付");
product.setSubject("支付宝支付");
product.setTotalFee(totalPrice);//支付金额(元)
product.setOutTradeNo(orderId);
product.setPayType(PayType.ALI.getCode());
String orderString = aliPayService.aliAppPay(product);
logger.info("调用支付宝预下单接口返回信息:{}", orderString);
return R.ok().put("orderString",orderString);
}
} catch (Exception e) {
logger.error(">>>>>>>>订单支付异常,信息:{}",e);
return R.error("网络异常,请稍后重试");
}
return R.error("支付失败");
}
支付宝回调