> 我们的支付时不允许在订单的支付接口传订单金额的,所以我们采用了订单号进行支付的形式 ## 支付 我们来到`PayController` ,这里就是统一支付的接口,当然这里的统一支付采用的是微信支付。 我们直接看一下核心代码: ```java PayInfoDto payInfo = payService.pay(userId, payParam); ``` 再看看里面的代码: ```java // 修改订单信息 for (String orderNumber : orderNumbers) { OrderSettlement orderSettlement = new OrderSettlement(); orderSettlement.setPayNo(payNo); orderSettlement.setPayType(payParam.getPayType()); orderSettlement.setUserId(userId); orderSettlement.setOrderNumber(orderNumber); orderSettlementMapper.updateByOrderNumberAndUserId(orderSettlement); Order order = orderMapper.getOrderByOrderNumber(orderNumber); prodName.append(order.getProdName()).append(StrUtil.COMMA); } ``` 这里对传过来的支付参数`orderNumbers`进行了拆分,为每个订单的结算信息都进行了更新,所以这里便支持了分单支付和并单支付的流程。 订单金额: ```java // 除了ordernumber不一样,其他都一样 List<OrderSettlement> settlements = orderSettlementMapper.getSettlementsByPayNo(payNo); // 应支付的总金额 double payAmount = 0.0; for (OrderSettlement orderSettlement : settlements) { payAmount = Arith.add(payAmount, orderSettlement.getPayAmount()); } ``` 这里面应支付的金额是通过数据库中获取的订单金额,是不接受任何前端传入的订单金额的。 ## 支付回调 我们回到`controller` ```java orderRequest.setNotifyUrl(apiConfig.getDomainName() + "/notice/pay/order"); ``` 这里面规定的,订单回调的地址,这也就是为什么需要`api.properties` 传入`api.domainName`的原因 根据订单配置`/notice/pay/order`,我们去到订单回调的`controller`既`PayNoticeController` - 验签 因为订单的已经决定的订单已经支付成功,所以订单的回调是需要做一些验证的。不然谁都可以调用订单回调的地址,实在是十分危险。 其实`wxjava`这个工具包已经对返回的参数进行了校验 ```java WxPayOrderNotifyResult parseOrderNotifyResult = wxMiniPayService.parseOrderNotifyResult(xmlData); ``` 在上面这个方法之下,就有那么一句话 ```java result.checkResult(this, this.getConfig().getSignType(), false); ``` - 更新支付状态 我们看看这里的业务核心方法: ```java // 根据内部订单号更新order settlement payService.paySuccess(payNo, bizPayNo); ``` ```java @Override @Transactional(rollbackFor = Exception.class) public List<String> paySuccess(String payNo, String bizPayNo) { List<OrderSettlement> orderSettlements = orderSettlementMapper.selectList(new LambdaQueryWrapper<OrderSettlement>().eq(OrderSettlement::getPayNo, payNo)); OrderSettlement settlement = orderSettlements.get(0); // 订单已支付 if (settlement.getPayStatus() == 1) { log.info("订单已支付,settlement.id:{}",settlement.getSettlementId()); return null; } // 修改订单结算信息 if (orderSettlementMapper.updateToPay(payNo, settlement.getVersion()) < 1) { throw new YamiShopBindException("结算信息已更改"); } List<String> orderNumbers = orderSettlements.stream().map(OrderSettlement::getOrderNumber).collect(Collectors.toList()); // 将订单改为已支付状态 orderMapper.updateByToPaySuccess(orderNumbers, PayType.WECHATPAY.value()); List<Order> orders = orderNumbers.stream().map(orderNumber -> { Order order = orderMapper.getOrderByOrderNumber(orderNumber); order.setOrderItems(orderItemMapper.listByOrderNumber(orderNumber)); return order; }).collect(Collectors.toList()); eventPublisher.publishEvent(new PaySuccessOrderEvent(orders)); return orderNumbers; } ``` 这里无非就是找到原来的订单,将订单变成已支付的状态。 而这里同样有事件支付成功的事件 ```java eventPublisher.publishEvent(new PaySuccessOrderEvent(orders)); ``` 这里的事件也是和营销活动有关的,比如分销,这些代码也是商业版才有的。