订单支付成功后,需要更改订单状态
支付宝有两种回调方式
- 同步回调:可以直接用request获取订单传回的数据,利用签名验证是否正确再去修改订单状态,但这种方式不推荐也不好,如果浏览器不小心关闭或者用户关闭,导致页面跳转不了也就无法修改订单数据
- 异步通知:只要支付成功以后就会给我们指定的地址发送一个请求还会带上之前成功的数据,收到以后再去修改订单,比较可靠
对于PC交易用户支付完成,支付宝会根据API传入的notify_url,通过post请求的形式将支付结果作为参数通知到商户系统,例如一些支付参数签名,业务参数支付时间流水号等等
只要我们订单支付成功,支付宝就会发送通知告诉我们订单支付成功了,我们要回复通知不然支付宝会一直尝试给我们发送通知,这也是相当于分布式事务中的最大努力通知机制
环境搭建
要让支付宝访问到我们,就要让我们的服务能够让外网访问到,因此要指定一个地址用来处理成功后支付的请求
#支付成功的异步通知页面 gulimall.alipay.notify_url=http://yjcpds.natappfree.cc/payed/notify
异步回调方法,验证成功就修改订单状态
@RequestMapping("/payed/notify") public String handleAlipayed(PayAsyncVo vo, HttpServletRequest request) throws AlipayApiException, UnsupportedEncodingException { Map<String, String[]> map = request.getParameterMap(); // for(String key : map.keySet()){ // String value = request.getParameter(key); // System.out.println("参数名:"+key+"-->参数值:"+value); // } //阿里验签方法 Map<String, String> params = new HashMap<String, String>(); Map<String, String[]> requestParams = request.getParameterMap(); for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) { String name = (String) iter.next(); String[] values = requestParams.get(name); String valueStr = ""; for (int i = 0; i < values.length; i++) { valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ","; } //乱码解决,这段代码在出现乱码时使用 //valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8"); params.put(name, valueStr); } boolean signVerified = AlipaySignature.rsaCheckV1(params, alipayTemplate.getAlipay_public_key(), alipayTemplate.getCharset(), alipayTemplate.getSign_type()); if (signVerified) { System.out.println("签名验证成功..."); String result = orderService.handlePayResult(vo); return result; } else { System.out.println("签名验证失败..."); return "error"; } }
内网穿透联调
需要把外网地址 http://yjcpds.natappfree.cc映射到我们内网主机的order.gulimall.com中
先去设置内网穿透映射的内网地址
进入到内网,内网配置了host地址,进入了虚拟机80端口
nginx监听到80端口,然后根据请求路径需要转给订单服务,但是由于请求头的原因找不到订单服务,因此进行精准匹配,把这个payed请求,直接转给订单服务,nginx还需要识别请求进来的主机名,需要配置内网穿透映射的主机名
最后编写响应成功修改订单的逻辑
@Override public String handlePayResult(PayAsyncVo vo) { //1.保存交易流水 PaymentInfoEntity infoEntity = new PaymentInfoEntity(); infoEntity.setAlipayTradeNo(vo.getTrade_no()); infoEntity.setOrderSn(vo.getOut_trade_no()); infoEntity.setPaymentStatus(vo.getTrade_status()); infoEntity.setCallbackTime(vo.getNotify_time()); paymentInfoService.save(infoEntity); //2.修改订单状态 if(vo.getTrade_status().equals("TRADE_SUCCESS")||vo.getTrade_status().equals("TRADE_FINISHED")){ //支付成功 String outTradeNo = vo.getOut_trade_no(); this.baseMapper.updateOrderStatus(outTradeNo,OrderStatusEnum.PAYED.getCode()); } return "success"; }
到此整个流程就完毕了,支付成功利用异步回调方法修改订单状态,完成整个支付流程
收单
1、订单在支付页,不支付,一直刷新,订单过期了才支付,订单状态改为已支付了,但是库存解锁了
- 使用支付宝自动收单功能解决。只要一段时间不支付,就不能支付了
在下单接口中增加一个参数,超时关闭订单支付
2、由于时延等问题。订单解锁完成,正在解锁库存的时候,异步通知才到
订单快要过期的时候,我们正好支付了,但是订单正好过期了,库存也解锁了
- 订单解锁,手动调用收单
3、网络阻塞问题,订单支付成功的异步通知一直不到达
- 查询订单列表时,ajax获取当前未支付的订单状态,查询订单状态时,再获取一下支付宝此订单的状态
4、其他各种问题
- 每天晚上闲时下载支付宝对账单,一一进行对账