d首先是创建订单,根据

    public OrderPageResponse createOrderPage(List<OderPageRequest> oderPageRequests, String personId) {
        //生成 提交订单时 所需要的 唯一的 pageToken. 并且存储到后端的 redis 服务器中
        String pageToken = UUID.randomUUID().toString();
        redisCommonProcessor.set(personId + pageToken, pageToken, 300);

        //运费计算, 需要访一个新的 微服务: 仓库微服务
//        Integer freight = wareServiceClient.calculateFreight(oderPageRequests);
        Integer freight = 0;

        //总价计算
        BigDecimal totalPrice = new BigDecimal(0);
        for (OderPageRequest oderPageRequest : oderPageRequests) {
            totalPrice = totalPrice.add(oderPageRequest.getPrice().multiply(new BigDecimal(oderPageRequest.getCount())));
        }
        totalPrice = totalPrice.add(new BigDecimal(freight));

        return OrderPageResponse.builder()
                .pageToken(pageToken)
                .freight(freight)
                .totalPrice(totalPrice)
                .build();
    }

订单的信息主要包括 商品id 店铺id 价格 数量 以及城市编码

private Long skuId;
private Integer shopId;
private BigDecimal price;
private Integer count;
private String cityCode;

订单提交后 会消耗对应的pageToken防止网络波动造成的多次提交。另外卡住页面长时间提交也不行,会给pageToken一个过期时间,这里面涉及到了价格的计算,上游是一个购物车的实现。

创建完订单之后主要是这个token的信息,拿到这个token

用户提交订单请求信息  用户id (全局上下文获取 header通过网关得到的 订单id后面生成根据日期uuid规则,运费是在创建订单里面计算的,我的代码把这个规则省略了,pageToekn 还有商品列表 包含了购买每个商品的库存 

public class OrderSubmitRequest implements Serializable {
    //用户相关信息
    private String personId;
    private String orderId;
    private Integer freight;//运费
    private String cityCode;//收获地址管理
    private String pageToken;
    private String orderStatus;
    private Date createTime;

    //购买商品信息
    private List<OrderItemEntity> orderItemEntities;


}
public CommonResponse submitOrder(OrderSubmitRequest orderSubmitRequest) {

        String personId = orderSubmitRequest.getPersonId();
        String pageToken = orderSubmitRequest.getPageToken();
        //并发问题 synchronized不行,分布式锁 性能稍差 redis的一个命令执行 尤其是lua脚本
//        if(cachedToken == null || !cachedToken.equals(personId)) {
//            return ResponseUtils.failResponse(ResponseCode.BAD_REQUEST.getCode(), null,"expired");
//        }
//        redisCommonProcessor.remove(personId + pageToken);
        String luaScript = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long validate = redisCommonProcessor.runLuaScripts(luaScript, pageToken, personId + pageToken);
        if(validate == 0)   {
            return ResponseUtils.failResponse(ResponseCode.BAD_REQUEST.getCode(), null,"expired");
        }
        //假设是雪花算法
        UUID uuid = UUID.randomUUID();
        String orderId = uuid.toString();
        orderSubmitRequest.setOrderId(orderId);

        List<OrderWareLockResponse> orderWareLockResponses = wareServiceClient.lockWare(orderSubmitRequest);
        Map<Boolean, List<OrderWareLockResponse>> wareLockMap = orderWareLockResponses.stream().collect(Collectors.groupingBy(OrderWareLockResponse::isLocked));
        if(wareLockMap.get(false) != null) {
            return ResponseUtils.failResponse(ResponseCode.BAD_REQUEST.getCode(), orderWareLockResponses,"your page is wrong");
        }
        //存入redis,支付时的查询,减少db依赖
        createOrderInfo(orderSubmitRequest);
        redisCommonProcessor.set(orderId, JSON.toJSONString(orderSubmitRequest), 1200);

        //支付信息
        rabbitTemplate.convertAndSend(ConstantUtils.ORDER_EXCHANGE,ConstantUtils.ORDER_CONFIRM_QUEUE,orderSubmitRequest);
        //订单信息
        rabbitTemplate.convertAndSend(ConstantUtils.ORDER_EXCHANGE,ConstantUtils.ORDER_DATA_QUEUE,orderSubmitRequest);
        return ResponseUtils.okResponse(orderSubmitRequest);
    }

上面这个首先进行pageToken校验,防止网络抖动造成的窗口抖动多次提交,另外不直接从redis获取数据,防止并发问题造成同时请求到下面,使用lua脚本的方式保证原子性同时不损失性能,这里uuid生成订单号,我只是举了一个例子,然后一次遍历每个商铺以及商品id的库存,如下图,分别检查每个商品的库存够不够,这里面用了手动事务的方式,一般的事务不太行。最后把订单信息分别存reids以及支付信息队列和订单信息队列,后面根据我的学习仅需更新

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐