20.订单服务
Posted root@su
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20.订单服务相关的知识,希望对你有一定的参考价值。
1.订单确认页返回需要用的数据
@Override
public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException
//构建OrderConfirmVo
OrderConfirmVo confirmVo = new OrderConfirmVo();
//获取当前用户登录的信息
MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
//TODO :获取当前线程请求头信息(解决Feign异步调用丢失请求头问题)
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
//开启第一个异步任务
CompletableFuture<Void> addressFuture = CompletableFuture.runAsync(() ->
//每一个线程都来共享之前的请求数据
RequestContextHolder.setRequestAttributes(requestAttributes);
//1、远程查询所有的收获地址列表
List<MemberAddressVo> address = memberFeignService.getAddress(memberResponseVo.getId());
confirmVo.setMemberAddressVos(address);
, threadPoolExecutor);
//开启第二个异步任务
CompletableFuture<Void> cartInfoFuture = CompletableFuture.runAsync(() ->
//每一个线程都来共享之前的请求数据
RequestContextHolder.setRequestAttributes(requestAttributes);
//2、远程查询购物车所有选中的购物项
List<OrderItemVo> currentCartItems = cartFeignService.getCurrentCartItems();
confirmVo.setItems(currentCartItems);
//feign在远程调用之前要构造请求,调用很多的拦截器
, threadPoolExecutor).thenRunAsync(() ->
List<OrderItemVo> items = confirmVo.getItems();
//获取全部商品的id
List<Long> skuIds = items.stream()
.map((itemVo -> itemVo.getSkuId()))
.collect(Collectors.toList());
//远程查询商品库存信息
R skuHasStock = wmsFeignService.getSkuHasStock(skuIds);
List<SkuStockVo> skuStockVos = skuHasStock.getData("data", new TypeReference<List<SkuStockVo>>() );
if (skuStockVos != null && skuStockVos.size() > 0)
//将skuStockVos集合转换为map
Map<Long, Boolean> skuHasStockMap = skuStockVos.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock));
confirmVo.setStocks(skuHasStockMap);
,threadPoolExecutor);
//3、查询用户积分
Integer integration = memberResponseVo.getIntegration();
confirmVo.setIntegration(integration);
//4、价格数据自动计算
//TODO 5、防重令牌(防止表单重复提交)
//为用户设置一个token,三十分钟过期时间(存在redis)
String token = UUID.randomUUID().toString().replace("-", "");
redisTemplate.opsForValue().set(USER_ORDER_TOKEN_PREFIX+memberResponseVo.getId(),token,30, TimeUnit.MINUTES);
confirmVo.setOrderToken(token);
CompletableFuture.allOf(addressFuture,cartInfoFuture).get();
return confirmVo;
2.提交订单
// @Transactional(isolation = Isolation.READ_COMMITTED) 设置事务的隔离级别
// @Transactional(propagation = Propagation.REQUIRED) 设置事务的传播级别
@Transactional(rollbackFor = Exception.class)
// @GlobalTransactional(rollbackFor = Exception.class)
@Override
public SubmitOrderResponseVo submitOrder(OrderSubmitVo vo)
confirmVoThreadLocal.set(vo);
SubmitOrderResponseVo responseVo = new SubmitOrderResponseVo();
//去创建、下订单、验令牌、验价格、锁定库存...
//获取当前用户登录的信息
MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
responseVo.setCode(0);
//1、验证令牌是否合法【令牌的对比和删除必须保证原子性】
String script = "if redis.call(\'get\', KEYS[1]) == ARGV[1] then return redis.call(\'del\', KEYS[1]) else return 0 end";
String orderToken = vo.getOrderToken();
//通过lure脚本原子验证令牌和删除令牌
Long result = redisTemplate.execute(new DefaultRedisScript<Long>(script, Long.class),
Arrays.asList(USER_ORDER_TOKEN_PREFIX + memberResponseVo.getId()),
orderToken);
if (result == 0L)
//令牌验证失败
responseVo.setCode(1);
return responseVo;
else
//令牌验证成功
//1、创建订单、订单项等信息
OrderCreateTo order = createOrder();
//2、验证价格
BigDecimal payAmount = order.getOrder().getPayAmount();
BigDecimal payPrice = vo.getPayPrice();
if (Math.abs(payAmount.subtract(payPrice).doubleValue()) < 0.01)
//金额对比
//TODO 3、保存订单
saveOrder(order);
//4、库存锁定,只要有异常,回滚订单数据
//订单号、所有订单项信息(skuId,skuNum,skuName)
WareSkuLockVo lockVo = new WareSkuLockVo();
lockVo.setOrderSn(order.getOrder().getOrderSn());
//获取出要锁定的商品数据信息
List<OrderItemVo> orderItemVos = order.getOrderItems().stream().map((item) ->
OrderItemVo orderItemVo = new OrderItemVo();
orderItemVo.setSkuId(item.getSkuId());
orderItemVo.setCount(item.getSkuQuantity());
orderItemVo.setTitle(item.getSkuName());
return orderItemVo;
).collect(Collectors.toList());
lockVo.setLocks(orderItemVos);
//TODO 调用远程锁定库存的方法
//出现的问题:扣减库存成功了,但是由于网络原因超时,出现异常,导致订单事务回滚,库存事务不回滚(解决方案:seata)
//为了保证高并发,不推荐使用seata,因为是加锁,并行化,提升不了效率,可以发消息给库存服务
R r = wmsFeignService.orderLockStock(lockVo);
if (r.getCode() == 0)
//锁定成功
responseVo.setOrder(order.getOrder());
// int i = 10/0;
//TODO 订单创建成功,发送消息给MQ
rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",order.getOrder());
//删除购物车里的数据
redisTemplate.delete(CART_PREFIX+memberResponseVo.getId());
return responseVo;
else
//锁定失败
String msg = (String) r.get("msg");
throw new NoStockException(msg);
// responseVo.setCode(3);
// return responseVo;
else
responseVo.setCode(2);
return responseVo;
3.关闭订单
@Override
public void closeOrder(OrderEntity orderEntity)
//关闭订单之前先查询一下数据库,判断此订单状态是否已支付
OrderEntity orderInfo = this.getOne(new QueryWrapper<OrderEntity>().
eq("order_sn",orderEntity.getOrderSn()));
if (orderInfo.getStatus().equals(OrderStatusEnum.CREATE_NEW.getCode()))
//代付款状态进行关单
OrderEntity orderUpdate = new OrderEntity();
orderUpdate.setId(orderInfo.getId());
orderUpdate.setStatus(OrderStatusEnum.CANCLED.getCode());
this.updateById(orderUpdate);
// 发送消息给MQ
OrderTo orderTo = new OrderTo();
BeanUtils.copyProperties(orderInfo, orderTo);
try
//TODO 确保每个消息发送成功,给每个消息做好日志记录,(给数据库保存每一个详细信息)保存每个消息的详细信息
rabbitTemplate.convertAndSend("order-event-exchange", "order.release.other", orderTo);
catch (Exception e)
//TODO 定期扫描数据库,重新发送失败的消息
4.获取当前订单的支付信息
@Override
public PayVo getOrderPay(String orderSn)
PayVo payVo = new PayVo();
OrderEntity orderInfo = this.getOrderByOrderSn(orderSn);
//保留两位小数点,向上取值
BigDecimal payAmount = orderInfo.getPayAmount().setScale(2, BigDecimal.ROUND_UP);
payVo.setTotal_amount(payAmount.toString());
payVo.setOut_trade_no(orderInfo.getOrderSn());
//查询订单项的数据
List<OrderItemEntity> orderItemInfo = orderItemService.list(
new QueryWrapper<OrderItemEntity>().eq("order_sn", orderSn));
OrderItemEntity orderItemEntity = orderItemInfo.get(0);
payVo.setBody(orderItemEntity.getSkuAttrsVals());
payVo.setSubject(orderItemEntity.getSkuName());
return payVo;
5.查询当前用户所有订单数据
@Override
public PageUtils queryPageWithItem(Map<String, Object> params)
MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
IPage<OrderEntity> page = this.page(
new Query<OrderEntity>().getPage(params),
new QueryWrapper<OrderEntity>()
.eq("member_id",memberResponseVo.getId()).orderByDesc("create_time")
);
//遍历所有订单集合
List<OrderEntity> orderEntityList = page.getRecords().stream().map(order ->
//根据订单号查询订单项里的数据
List<OrderItemEntity> orderItemEntities = orderItemService.list(new QueryWrapper<OrderItemEntity>()
.eq("order_sn", order.getOrderSn()));
order.setOrderItemEntityList(orderItemEntities);
return order;
).collect(Collectors.toList());
page.setRecords(orderEntityList);
return new PageUtils(page);
6.保存订单所有数据
private void saveOrder(OrderCreateTo orderCreateTo)
//获取订单信息
OrderEntity order = orderCreateTo.getOrder();
order.setModifyTime(new Date());
order.setCreateTime(new Date());
//保存订单
this.baseMapper.insert(order);
//获取订单项信息
List<OrderItemEntity> orderItems = orderCreateTo.getOrderItems();
//批量保存订单项数据
orderItemService.saveBatch(orderItems);
7.创建订单
private OrderCreateTo createOrder()
OrderCreateTo createTo = new OrderCreateTo();
//1、生成订单号
String orderSn = IdWorker.getTimeId();
OrderEntity orderEntity = builderOrder(orderSn);
//2、获取到所有的订单项
List<OrderItemEntity> orderItemEntities = builderOrderItems(orderSn);
//3、验价(计算价格、积分等信息)
computePrice(orderEntity,orderItemEntities);
createTo.setOrder(orderEntity);
createTo.setOrderItems(orderItemEntities);
return createTo;
8.计算价格的方法
private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities)
//总价
BigDecimal total = new BigDecimal("0.0");
//优惠价
BigDecimal coupon = new BigDecimal("0.0");
BigDecimal intergration = new BigDecimal("0.0");
BigDecimal promotion = new BigDecimal("0.0");
//积分、成长值
Integer integrationTotal = 0;
Integer growthTotal = 0;
//订单总额,叠加每一个订单项的总额信息
for (OrderItemEntity orderItem : orderItemEntities)
//优惠价格信息
coupon = coupon.add(orderItem.getCouponAmount());
promotion = promotion.add(orderItem.getPromotionAmount());
intergration = intergration.add(orderItem.getIntegrationAmount());
//总价
total = total.add(orderItem.getRealAmount());
//积分信息和成长值信息
integrationTotal += orderItem.getGiftIntegration();
growthTotal += orderItem.getGiftGrowth();
//1、订单价格相关的
orderEntity.setTotalAmount(total);
//设置应付总额(总额+运费)
orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));
orderEntity.setCouponAmount(coupon);
orderEntity.setPromotionAmount(promotion);
orderEntity.setIntegrationAmount(intergration);
//设置积分成长值信息
orderEntity.setIntegration(integrationTotal);
orderEntity.setGrowth(growthTotal);
//设置删除状态(0-未删除,1-已删除)
orderEntity.setDeleteStatus(0);
9.构建订单数据
private OrderEntity builderOrder(String orderSn)
//获取当前用户登录信息
MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
OrderEntity orderEntity = new OrderEntity();
orderEntity.setMemberId(memberResponseVo.getId());
orderEntity.setOrderSn(orderSn);
orderEntity.setMemberUsername(memberResponseVo.getUsername());
OrderSubmitVo orderSubmitVo = confirmVoThreadLocal.get();
//远程获取收货地址和运费信息
R fareAddressVo = wmsFeignService.getFare(orderSubmitVo.getAddrId());
FareVo fareResp = fareAddressVo.getData("data", new TypeReference<FareVo>() );
//获取到运费信息
BigDecimal fare = fareResp.getFare();
orderEntity.setFreightAmount(fare);
//获取到收货地址信息
MemberAddressVo address = fareResp.getAddress();
//设置收货人信息
orderEntity.setReceiverName(address.getName());
orderEntity.setReceiverPhone(address.getPhone());
orderEntity.setReceiverPostCode(address.getPostCode());
orderEntity.setReceiverProvince(address.getProvince());
orderEntity.setReceiverCity(address.getCity());
orderEntity.setReceiverRegion(address.getRegion());
orderEntity.setReceiverDetailAddress(address.getDetailAddress());
//设置订单相关的状态信息
orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
orderEntity.setAutoConfirmDay(7);
orderEntity.setConfirmStatus(0);
return orderEntity;
10.构建所有订单项数据
public List<OrderItemEntity> builderOrderItems(String orderSn)
List<OrderItemEntity> orderItemEntityList = new ArrayList<>();
//最后确定每个购物项的价格
List<OrderItemVo> currentCartItems = cartFeignService.getCurrentCartItems();
if (currentCartItems != null && currentCartItems.size() > 0)
orderItemEntityList = currentCartItems.stream().map((items) ->
//构建订单项数据
OrderItemEntity orderItemEntity = builderOrderItem(items);
orderItemEntity.setOrderSn(orderSn);
return orderItemEntity;
).collect(Collectors.toList());
return orderItemEntityList;
11.构建某一个订单项的数据
private OrderItemEntity builderOrderItem(OrderItemVo items)
OrderItemEntity orderItemEntity = new OrderItemEntity();
//1、商品的spu信息
Long skuId = items.getSkuId();
//获取spu的信息
R spuInfo = productFeignService.getSpuInfoBySkuId(skuId);
SpuInfoVo spuInfoData = spuInfo.getData("data", new TypeReference<SpuInfoVo>()
);
orderItemEntity.setSpuId(spuInfoData.getId());
orderItemEntity.setSpuName(spuInfoData.getSpuName());
orderItemEntity.setSpuBrand(spuInfoData.getBrandName());
orderItemEntity.setCategoryId(spuInfoData.getCatalogId());
//2、商品的sku信息
orderItemEntity.setSkuId(skuId);
orderItemEntity.setSkuName(items.getTitle());
orderItemEntity.setSkuPic(items.getImage());
orderItemEntity.setSkuPrice(items.getPrice());
orderItemEntity.setSkuQuantity(items.getCount());
//使用StringUtils.collectionToDelimitedString将list集合转换为String
String skuAttrValues = StringUtils.collectionToDelimitedString(items.getSkuAttrValues(), ";");
orderItemEntity.setSkuAttrsVals(skuAttrValues);
//3、商品的优惠信息
//4、商品的积分信息
orderItemEntity.setGiftGrowth(items.getPrice().multiply(new BigDecimal(items.getCount())).intValue());
orderItemEntity.setGiftIntegration(items.getPrice().multiply(new BigDecimal(items.getCount())).intValue());
//5、订单项的价格信息
orderItemEntity.setPromotionAmount(BigDecimal.ZERO);
orderItemEntity.setCouponAmount(BigDecimal.ZERO);
orderItemEntity.setIntegrationAmount(BigDecimal.ZERO);
//当前订单项的实际金额.总额 - 各种优惠价格
//原来的价格
BigDecimal origin = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));
//原价减去优惠价得到最终的价格
BigDecimal subtract = origin.subtract(orderItemEntity.getCouponAmount())
.subtract(orderItemEntity.getPromotionAmount())
.subtract(orderItemEntity.getIntegrationAmount());
orderItemEntity.setRealAmount(subtract);
return orderItemEntity;
12.处理支付宝的支付结果
@Transactional(rollbackFor = Exception.class)
@Override
public String handlePayResult(PayAsyncVo asyncVo)
//保存交易流水信息
PaymentInfoEntity paymentInfo = new PaymentInfoEntity();
paymentInfo.setOrderSn(asyncVo.getOut_trade_no());
paymentInfo.setAlipayTradeNo(asyncVo.getTrade_no());
paymentInfo.setTotalAmount(new BigDecimal(asyncVo.getBuyer_pay_amount()));
paymentInfo.setSubject(asyncVo.getBody());
paymentInfo.setPaymentStatus(asyncVo.getTrade_status());
paymentInfo.setCreateTime(new Date());
paymentInfo.setCallbackTime(asyncVo.getNotify_time());
//添加到数据库中
this.paymentInfoService.save(paymentInfo);
//修改订单状态
//获取当前状态
String tradeStatus = asyncVo.getTrade_status();
if (tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED"))
//支付成功状态
String orderSn = asyncVo.getOut_trade_no(); //获取订单号
this.updateOrderStatus(orderSn,OrderStatusEnum.PAYED.getCode(),PayConstant.ALIPAY);
return "success";
13.构建某一个订单项的数据
private OrderItemEntity builderOrderItem(OrderItemVo items)
OrderItemEntity orderItemEntity = new OrderItemEntity();
//1、商品的spu信息
Long skuId = items.getSkuId();
//获取spu的信息
R spuInfo = productFeignService.getSpuInfoBySkuId(skuId);
SpuInfoVo spuInfoData = spuInfo.getData("data", new TypeReference<SpuInfoVo>()
);
orderItemEntity.setSpuId(spuInfoData.getId());
orderItemEntity.setSpuName(spuInfoData.getSpuName());
orderItemEntity.setSpuBrand(spuInfoData.getBrandName());
orderItemEntity.setCategoryId(spuInfoData.getCatalogId());
//2、商品的sku信息
orderItemEntity.setSkuId(skuId);
orderItemEntity.setSkuName(items.getTitle());
orderItemEntity.setSkuPic(items.getImage());
orderItemEntity.setSkuPrice(items.getPrice());
orderItemEntity.setSkuQuantity(items.getCount());
//使用StringUtils.collectionToDelimitedString将list集合转换为String
String skuAttrValues = StringUtils.collectionToDelimitedString(items.getSkuAttrValues(), ";");
orderItemEntity.setSkuAttrsVals(skuAttrValues);
//3、商品的优惠信息
//4、商品的积分信息
orderItemEntity.setGiftGrowth(items.getPrice().multiply(new BigDecimal(items.getCount())).intValue());
orderItemEntity.setGiftIntegration(items.getPrice().multiply(new BigDecimal(items.getCount())).intValue());
//5、订单项的价格信息
orderItemEntity.setPromotionAmount(BigDecimal.ZERO);
orderItemEntity.setCouponAmount(BigDecimal.ZERO);
orderItemEntity.setIntegrationAmount(BigDecimal.ZERO);
//当前订单项的实际金额.总额 - 各种优惠价格
//原来的价格
BigDecimal origin = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));
//原价减去优惠价得到最终的价格
BigDecimal subtract = origin.subtract(orderItemEntity.getCouponAmount())
.subtract(orderItemEntity.getPromotionAmount())
.subtract(orderItemEntity.getIntegrationAmount());
orderItemEntity.setRealAmount(subtract);
return orderItemEntity;
14.处理支付宝的支付结果
@Transactional(rollbackFor = Exception.class)
@Override
public String handlePayResult(PayAsyncVo asyncVo)
//保存交易流水信息
PaymentInfoEntity paymentInfo = new PaymentInfoEntity();
paymentInfo.setOrderSn(asyncVo.getOut_trade_no());
paymentInfo.setAlipayTradeNo(asyncVo.getTrade_no());
paymentInfo.setTotalAmount(new BigDecimal(asyncVo.getBuyer_pay_amount()));
paymentInfo.setSubject(asyncVo.getBody());
paymentInfo.setPaymentStatus(asyncVo.getTrade_status());
paymentInfo.setCreateTime(new Date());
paymentInfo.setCallbackTime(asyncVo.getNotify_time());
//添加到数据库中
this.paymentInfoService.save(paymentInfo);
//修改订单状态
//获取当前状态
String tradeStatus = asyncVo.getTrade_status();
if (tradeStatus.equals("TRADE_SUCCESS") || tradeStatus.equals("TRADE_FINISHED"))
//支付成功状态
String orderSn = asyncVo.getOut_trade_no(); //获取订单号
this.updateOrderStatus(orderSn,OrderStatusEnum.PAYED.getCode(),PayConstant.ALIPAY);
return "success";
15.修改订单状态
private void updateOrderStatus(String orderSn, Integer code,Integer payType)
this.baseMapper.updateOrderStatus(orderSn,code,payType);
16.微信异步通知结果
@Override
public String asyncNotify(String notifyData)
//签名效验
PayResponse payResponse = bestPayService.asyncNotify(notifyData);
log.info("payResponse=",payResponse);
//2.金额效验(从数据库查订单)
OrderEntity orderEntity = this.getOrderByOrderSn(payResponse.getOrderId());
//如果查询出来的数据是null的话
//比较严重(正常情况下是不会发生的)发出告警:钉钉、短信
if (orderEntity == null)
//TODO 发出告警,钉钉,短信
throw new RuntimeException("通过订单编号查询出来的结果是null");
//判断订单状态状态是否为已支付或者是已取消,如果不是订单状态不是已支付状态
Integer status = orderEntity.getStatus();
if (status.equals(OrderStatusEnum.PAYED.getCode()) || status.equals(OrderStatusEnum.CANCLED.getCode()))
throw new RuntimeException("该订单已失效,orderNo=" + payResponse.getOrderId());
/*//判断金额是否一致,Double类型比较大小,精度问题不好控制
if (orderEntity.getPayAmount().compareTo(BigDecimal.valueOf(payResponse.getOrderAmount())) != 0)
//TODO 告警
throw new RuntimeException("异步通知中的金额和数据库里的不一致,orderNo=" + payResponse.getOrderId());
*/
//3.修改订单支付状态
//支付成功状态
String orderSn = orderEntity.getOrderSn();
this.updateOrderStatus(orderSn,OrderStatusEnum.PAYED.getCode(),PayConstant.WXPAY);
//4.告诉微信不要再重复通知了
return "<xml>\\n" +
" <return_code><![CDATA[SUCCESS]]></return_code>\\n" +
" <return_msg><![CDATA[OK]]></return_msg>\\n" +
"</xml>";
17.创建秒杀单
@Override
public void createSeckillOrder(SeckillOrderTo orderTo)
//TODO 保存订单信息
OrderEntity orderEntity = new OrderEntity();
orderEntity.setOrderSn(orderTo.getOrderSn());
orderEntity.setMemberId(orderTo.getMemberId());
orderEntity.setCreateTime(new Date());
BigDecimal totalPrice = orderTo.getSeckillPrice().multiply(BigDecimal.valueOf(orderTo.getNum()));
orderEntity.setPayAmount(totalPrice);
orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
//保存订单
this.save(orderEntity);
//保存订单项信息
OrderItemEntity orderItem = new OrderItemEntity();
orderItem.setOrderSn(orderTo.getOrderSn());
orderItem.setRealAmount(totalPrice);
orderItem.setSkuQuantity(orderTo.getNum());
//保存商品的spu信息
R spuInfo = productFeignService.getSpuInfoBySkuId(orderTo.getSkuId());
SpuInfoVo spuInfoData = spuInfo.getData("data", new TypeReference<SpuInfoVo>()
);
orderItem.setSpuId(spuInfoData.getId());
orderItem.setSpuName(spuInfoData.getSpuName());
orderItem.setSpuBrand(spuInfoData.getBrandName());
orderItem.setCategoryId(spuInfoData.getCatalogId());
//保存订单项数据
orderItemService.save(orderItem);
以上是关于20.订单服务的主要内容,如果未能解决你的问题,请参考以下文章