refactor: 订单重构优化

This commit is contained in:
郝先瑞 2022-02-08 23:43:37 +08:00
parent 054697e11a
commit 8a0e33b8cc
31 changed files with 348 additions and 468 deletions

View File

@ -1,7 +1,7 @@
package com.youlai.mall.oms;
import com.youlai.mall.pms.api.SkuFeignClient;
import com.youlai.mall.ums.api.MemberFeignClient;
import org.springframework.amqp.rabbit.annotation.EnableRabbit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
@ -11,8 +11,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
@EnableDiscoveryClient
@EnableFeignClients(basePackageClasses = { MemberFeignClient.class, GoodsFeignClient.class})
@EnableRabbit
@EnableFeignClients(basePackageClasses = { MemberFeignClient.class, SkuFeignClient.class})
@EnableTransactionManagement
public class OmsApplication {

View File

@ -7,7 +7,7 @@ import com.youlai.common.result.Result;
import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.oms.enums.PayTypeEnum;
import com.youlai.mall.oms.pojo.dto.OrderConfirmDTO;
import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO;
import com.youlai.mall.oms.pojo.form.OrderSubmitForm;
import com.youlai.mall.oms.pojo.entity.OmsOrder;
import com.youlai.mall.oms.pojo.query.OrderPageQuery;
import com.youlai.mall.oms.pojo.vo.OrderConfirmVO;
@ -59,8 +59,8 @@ public class OrderController {
@ApiOperation("订单提交")
@PostMapping("/_submit")
public Result submit(@Valid @RequestBody OrderSubmitDTO orderSubmitDTO) {
OrderSubmitVO result = orderService.submit(orderSubmitDTO);
public Result submit(@Valid @RequestBody OrderSubmitForm orderSubmitForm) {
OrderSubmitVO result = orderService.submit(orderSubmitForm);
return Result.success(result);
}

View File

@ -12,13 +12,15 @@ import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @author hxr
* @date 2021-03-16
* 订单超时取消
*
* @author haoxr
* @date 2021/3/16
*/
@Component
@Slf4j
@RequiredArgsConstructor
@Slf4j
public class OrderListener {
private final IOrderService orderService;

View File

@ -7,40 +7,47 @@ import java.io.Serializable;
/**
* 购物车商品传输层实体
*/
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Builder
@Data
public class CartItemDTO implements Serializable {
/**
* 商品库存ID
*/
private Long skuId;
/**
* 商品库存单元名称
* 商品库存名称
*/
private String skuName;
/**
* 商品库存单元编码
* 商品编码
*/
private String skuSn;
/**
* 商品库存单元图片
* 商品图片
*/
private String picUrl;
private Integer count; // 商品数量
/**
* 商品数量
*/
private Integer count;
/**
* 加入购物车价格因会变动不能作为订单计算因子订单验价时需重新获取商品价格即可
* 加入购物车价格因会变动不能作为订单计算因子订单提交时需验价
*/
private Long price;
/**
* 优惠券金额
*/
private Long coupon;
/**
* 是否选中
*/
private Boolean checked;
/**
@ -51,6 +58,6 @@ public class CartItemDTO implements Serializable {
/**
* 商品名称
*/
private String goodsName;
private String spuName;
}

View File

@ -3,10 +3,7 @@ package com.youlai.mall.oms.pojo.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.youlai.common.base.BaseEntity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
@ -18,17 +15,13 @@ import lombok.experimental.Accessors;
*/
@Data
@Accessors(chain = true)
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class OmsOrderItem extends BaseEntity {
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* order_id
* 订单ID
*/
private Long orderId;
/**
@ -38,57 +31,36 @@ public class OmsOrderItem extends BaseEntity {
/**
* 商品sku编号
*/
private String skuCode;
private String skuSn;
/**
* 商品名称
*/
private String skuName;
/**
* 商品sku图片
*/
private String skuPic;
private String picUrl;
/**
* 商品sku价格()
* 商品单价(单位)
*/
private Long skuPrice;
private Long price;
/**
* 商品购买的数量
* 商品数量
*/
private Integer skuQuantity;
private Integer count;
/**
* 商品sku总价格()
* 商品总金额(单位)
*/
private Long skuTotalPrice;
private Long totalAmount;
/**
* spu_id
*/
private Long spuId;
/**
* spu_name
*/
private String spuName;
/**
* spu_pic
*/
private String spuPic;
/**
* 品牌id
*/
private Long brandId;
/**
* 品牌名称
*/
private String brandName;
/**
* 商品分类id
*/
private Long categoryId;
/**
* 商品分类名称
*/
private String categoryName;
/**
* 逻辑删除0->正常1->已删除
* 逻辑删除(0:正常1:已删除)
*/
private Integer deleted;

View File

@ -1,5 +1,6 @@
package com.youlai.mall.oms.pojo.dto;
package com.youlai.mall.oms.pojo.form;
import com.youlai.mall.oms.pojo.dto.OrderItemDTO;
import com.youlai.mall.ums.pojo.entity.UmsAddress;
import lombok.Data;
@ -7,30 +8,51 @@ import javax.validation.constraints.Size;
import java.util.List;
/**
* 订单提交表单对象
*
* @author huawei
* @desc 订单提交
* @email huawei_code@163.com
* @date 2021/1/16
*/
@Data
public class OrderSubmitDTO {
public class OrderSubmitForm {
// 提交订单确认页面签发的令牌
/**
* 提交订单确认页面签发的令牌
*/
private String orderToken;
/**
* 订单总金额-用于验价(单位)
*/
private Long totalAmount;
/**
* 支付金额(单位)
*/
private Long payAmount;
/**
* 订单的商品明细
*/
private List<OrderItemDTO> orderItems;
// 验价前台传值
private Long totalPrice;
// 收货地址
private UmsAddress deliveryAddress;
@Size(max = 500, message = "订单备注长度不能超过500")
private String remark;
/**
* 优惠券ID
*/
private String couponId;
private Long payAmount;
/**
* 收获地址
*/
private UmsAddress deliveryAddress;
}

View File

@ -9,7 +9,7 @@ import java.util.List;
@Data
public class OrderConfirmVO extends BaseVO {
public class OrderConfirmVO {
private String orderToken;

View File

@ -1,16 +1,17 @@
package com.youlai.mall.oms.pojo.vo;
import com.youlai.common.base.BaseVO;
import lombok.Data;
/**
* 订单创建响应视图对象
*
* @author huawei
* @desc 订单创建响应结果VO
* @email huawei_code@163.com
* @date 2021/1/21
*/
@Data
public class OrderSubmitVO extends BaseVO {
public class OrderSubmitVO {
/**
* 订单ID
*/

View File

@ -1,7 +1,6 @@
package com.youlai.mall.oms.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
@ -12,7 +11,7 @@ import com.youlai.mall.oms.pojo.dto.OrderConfirmDTO;
import com.youlai.mall.oms.pojo.query.OrderPageQuery;
import com.youlai.mall.oms.pojo.vo.OrderConfirmVO;
import com.youlai.mall.oms.pojo.vo.OrderSubmitVO;
import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO;
import com.youlai.mall.oms.pojo.form.OrderSubmitForm;
/**
* 订单业务接口
@ -31,12 +30,7 @@ public interface IOrderService extends IService<OmsOrder> {
/**
* 订单提交
*/
OrderSubmitVO submit(OrderSubmitDTO orderSubmitDTO) ;
/**
* 订单提交
*/
OrderSubmitVO submitTcc(OrderSubmitDTO orderSubmitDTO) ;
OrderSubmitVO submit(OrderSubmitForm orderSubmitForm) ;
/**
* 订单支付

View File

@ -1,5 +1,6 @@
package com.youlai.mall.oms.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Assert;
import com.youlai.common.result.ResultCode;
import com.youlai.common.web.exception.BizException;
@ -7,8 +8,12 @@ import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.oms.constant.OmsConstants;
import com.youlai.mall.oms.pojo.dto.CartItemDTO;
import com.youlai.mall.oms.service.ICartService;
import com.youlai.mall.pms.api.SkuFeignClient;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtilsBean;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@ -33,7 +38,7 @@ import java.util.concurrent.CompletableFuture;
public class CartServiceImpl implements ICartService {
private RedisTemplate redisTemplate;
private GoodsFeignClient skuFeignService;
private SkuFeignClient skuFeignService;
@Override
public List<CartItemDTO> listCartItemByMemberId(Long memberId) {
@ -78,22 +83,16 @@ public class CartServiceImpl implements ICartService {
// 购物车不存在该商品添加商品至购物车
cartItem = new CartItemDTO();
CompletableFuture<Void> cartItemCompletableFuture = CompletableFuture.runAsync(() -> {
AppSkuDetailVO sku = skuFeignService.getSkuById(skuId).getData();
if (sku != null) {
cartItem.setSkuId(sku.getId());
SkuInfoDTO skuInfo = skuFeignService.getSkuInfo(skuId).getData();
if (skuInfo != null) {
BeanUtil.copyProperties(skuInfo,cartItem);
cartItem.setCount(1);
cartItem.setPrice(sku.getPrice());
cartItem.setPicUrl(sku.getPicUrl());
cartItem.setSkuName(sku.getName());
cartItem.setStock(sku.getStock());
cartItem.setSkuSn(sku.getSn());
cartItem.setGoodsName(sku.getSpuName());
cartItem.setChecked(true);
}
});
CompletableFuture.allOf(cartItemCompletableFuture).join();
Assert.isTrue(cartItem.getSkuId() != null && cartItem.getSkuId() > 0,"商品不存在");
Assert.isTrue(cartItem.getSkuId() != null,"商品不存在");
cartHashOperations.put(hKey, cartItem);
return true;
}

View File

@ -5,6 +5,7 @@ import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@ -29,20 +30,20 @@ import com.youlai.mall.oms.enums.OrderStatusEnum;
import com.youlai.mall.oms.enums.OrderTypeEnum;
import com.youlai.mall.oms.enums.PayTypeEnum;
import com.youlai.mall.oms.mapper.OrderMapper;
import com.youlai.mall.oms.pojo.dto.CartItemDTO;
import com.youlai.mall.oms.pojo.dto.OrderConfirmDTO;
import com.youlai.mall.oms.pojo.dto.OrderItemDTO;
import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO;
import com.youlai.mall.oms.pojo.dto.CartItemDTO;
import com.youlai.mall.oms.pojo.entity.OmsOrder;
import com.youlai.mall.oms.pojo.entity.OmsOrderItem;
import com.youlai.mall.oms.pojo.form.OrderSubmitForm;
import com.youlai.mall.oms.pojo.query.OrderPageQuery;
import com.youlai.mall.oms.pojo.vo.OrderConfirmVO;
import com.youlai.mall.oms.pojo.vo.OrderSubmitVO;
import com.youlai.mall.oms.service.ICartService;
import com.youlai.mall.oms.service.IOrderItemService;
import com.youlai.mall.oms.service.IOrderService;
import com.youlai.mall.oms.tcc.service.SeataTccOrderService;
import com.youlai.mall.pms.api.SkuFeignClient;
import com.youlai.mall.pms.pojo.dto.CheckPriceDTO;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import com.youlai.mall.pms.pojo.dto.app.LockStockDTO;
import com.youlai.mall.ums.api.MemberAddressFeignClient;
@ -52,7 +53,6 @@ import com.youlai.mall.ums.pojo.entity.UmsMember;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.api.Assertions;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
@ -87,16 +87,29 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
private final MemberFeignClient memberFeignClient;
private final BusinessNoGenerator businessNoGenerator;
private final SkuFeignClient skuFeignClient;
private final SeataTccOrderService seataTccOrderService;
private final RedissonClient redissonClient;
private final WxPayService wxPayService;
/**
* 订单分页列表
*
* @param queryParams
* @return
*/
@Override
public IPage<OmsOrder> listOrdersWithPage(OrderPageQuery queryParams) {
Page<OmsOrder> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
List<OmsOrder> list = this.baseMapper.listUsersWithPage(page, queryParams);
page.setRecords(list);
return page;
}
/**
* 订单确认
*/
@Override
public OrderConfirmVO confirm(OrderConfirmDTO orderConfirmDTO) {
log.info("=======================订单确认=======================\n订单确认信息{}", orderConfirmDTO);
log.info("订单确认:{}", orderConfirmDTO);
OrderConfirmVO orderConfirmVO = new OrderConfirmVO();
Long memberId = JwtUtils.getUserId();
@ -104,14 +117,14 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
CompletableFuture<Void> orderItemsCompletableFuture = CompletableFuture.runAsync(() -> {
List<OrderItemDTO> orderItems = new ArrayList<>();
Long skuId = orderConfirmDTO.getSkuId();
if (skuId != null) { // 直接购买商品
if (skuId != null) { // 直接购买
Result<SkuInfoDTO> getSkuInfoResult = skuFeignClient.getSkuInfo(orderConfirmDTO.getSkuId());
Assert.isTrue(Result.isSuccess(getSkuInfoResult), "获取商品信息失败");
SkuInfoDTO skuInfoDTO = getSkuInfoResult.getData();
OrderItemDTO orderItemDTO = new OrderItemDTO();
BeanUtil.copyProperties(skuInfoDTO, orderItemDTO);
orderItems.add(orderItemDTO);
} else { // 购物车中商品结算
} else { // 购物车结算
List<CartItemDTO> cartItems = cartService.listCartItemByMemberId(memberId);
List<OrderItemDTO> items = cartItems.stream()
.filter(CartItemDTO::getChecked)
@ -149,142 +162,74 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
*/
@Override
@GlobalTransactional
public OrderSubmitVO submit(OrderSubmitDTO submitDTO) {
log.info("=======================订单提交=======================\n订单提交信息{}", submitDTO);
public OrderSubmitVO submit(OrderSubmitForm orderSubmitForm) {
log.info("订单提交数据:{}", JSONUtil.toJsonStr(orderSubmitForm));
// 订单校验
List<OrderItemDTO> orderItems = orderSubmitForm.getOrderItems();
Assert.isTrue(CollectionUtil.isNotEmpty(orderItems), "订单没有商品");
// 订单重复提交校验
String orderToken = submitDTO.getOrderToken();
String orderToken = orderSubmitForm.getOrderToken();
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_LUA_SCRIPT, Long.class);
Long execute = this.redisTemplate.execute(redisScript, Collections.singletonList(ORDER_TOKEN_PREFIX + orderToken), orderToken);
Assert.isTrue(execute.equals(1l), "订单不可重复提交");
List<OrderItemDTO> orderItems = submitDTO.getOrderItems();
Assert.isTrue(CollectionUtil.isNotEmpty(orderItems), "订单商品为空");
// 订单验价
Long currentTotalPrice = orderItems.stream().map(item -> {
SkuInfoDTO sku = skuFeignClient.getSkuInfo(item.getSkuId()).getData();
if (sku != null) {
return sku.getPrice() * item.getCount();
}
return 0L;
}).reduce(0L, Long::sum);
Long orderTotalAmount = orderSubmitForm.getTotalAmount();
boolean checkResult = checkOrderPrice(orderTotalAmount, orderItems);
Assert.isTrue(checkResult, "当前页面已过期,请重新刷新页面再提交");
Assert.isTrue(currentTotalPrice.compareTo(submitDTO.getTotalPrice()) == 0, "当前页面已过期,请重新刷新页面再提交");
// 校验库存是否足够和锁库存
// 锁定库存
List<LockStockDTO> skuLockList = orderItems.stream()
.map(item -> LockStockDTO.builder().skuId(item.getSkuId())
.count(item.getCount())
.orderToken(orderToken)
.build())
.collect(Collectors.toList());
// 锁定库存
Result lockResult = skuFeignClient.lockStock(skuLockList);
Assert.isTrue(Result.isSuccess(lockResult), "锁定商品库存失败:{}", lockResult.getMsg());
// 创建订单(状态待支付)
OmsOrder order = new OmsOrder();
order.setOrderSn(orderToken) // 把orderToken赋值给订单编号!
// 创建订单
OmsOrder order = new OmsOrder().setOrderSn(orderToken) // 把orderToken赋值给订单编号
.setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode())
.setSourceType(OrderTypeEnum.APP.getCode())
.setMemberId(JwtUtils.getUserId())
.setRemark(submitDTO.getRemark())
.setPayAmount(submitDTO.getPayAmount())
.setRemark(orderSubmitForm.getRemark())
.setPayAmount(orderSubmitForm.getPayAmount())
.setTotalQuantity(orderItems.stream().map(OrderItemDTO::getCount).reduce(0, Integer::sum))
.setTotalAmount(orderItems.stream().map(item -> item.getPrice() * item.getCount()).reduce(0L, Long::sum));
this.save(order);
boolean result = this.save(order);
// 创建订单商品
List<OmsOrderItem> orderItemList = orderItems.stream().map(item -> OmsOrderItem.builder()
.orderId(order.getId())
.skuId(item.getSkuId())
.skuName(item.getSkuName())
.skuPrice(item.getPrice())
.skuPic(item.getPic())
.skuQuantity(item.getCount())
.skuTotalPrice(item.getCount() * item.getPrice())
.skuCode(item.getSkuCode())
.build()).collect(Collectors.toList());
orderItemService.saveBatch(orderItemList);
// 将订单放入延时队列超时未支付由交换机order.exchange切换到死信队列完成系统自动关单
log.info("订单超时取消RabbitMQ消息发送订单SN{}", orderToken);
// 添加订单明细
if (result) {
List<OmsOrderItem> orderItemList = orderItems.stream().map(orderFormItem -> {
OmsOrderItem omsOrderItem = new OmsOrderItem();
BeanUtil.copyProperties(orderFormItem, omsOrderItem);
omsOrderItem.setOrderId(order.getId());
omsOrderItem.setTotalAmount(orderFormItem.getPrice() * orderFormItem.getCount());
return omsOrderItem;
}).collect(Collectors.toList());
result = orderItemService.saveBatch(orderItemList);
if (result) {
// 订单超时取消
rabbitTemplate.convertAndSend("order.exchange", "order.create", orderToken);
}
}
Assert.isTrue(result, "订单提交失败");
// 成功响应返回值构建
OrderSubmitVO submitVO = new OrderSubmitVO();
submitVO.setOrderId(order.getId());
submitVO.setOrderSn(order.getOrderSn());
log.info("订单提交响应:{}", submitVO);
return submitVO;
}
@Override
@GlobalTransactional(rollbackFor = Exception.class)
public OrderSubmitVO submitTcc(OrderSubmitDTO submitDTO) {
log.info("=======================订单提交=======================\n订单提交信息{}", submitDTO);
// 订单重复提交校验
String orderToken = submitDTO.getOrderToken();
// DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(RELEASE_LOCK_LUA_SCRIPT, Long.class);
// Long result = this.redisTemplate.execute(redisScript, Collections.singletonList(ORDER_TOKEN_PREFIX + orderToken), orderToken);
//
// if (!ObjectUtil.equals(result, RELEASE_LOCK_SUCCESS_RESULT)) {
// throw new BizException("订单不可重复提交");
// }
List<OrderItemDTO> orderItems = submitDTO.getOrderItems();
if (CollectionUtil.isEmpty(orderItems)) {
throw new BizException("订单没有商品,请选择商品后提交");
}
// 订单验价
Long currentTotalPrice = orderItems.stream().map(item -> {
AppSkuDetailVO sku = goodsFeignClient.getSkuById(item.getSkuId()).getData();
if (sku != null) {
return sku.getPrice() * item.getCount();
}
return 0L;
}).reduce(0L, Long::sum);
if (currentTotalPrice.compareTo(submitDTO.getTotalPrice()) != 0) {
throw new BizException("页面已过期,请重新刷新页面再提交");
}
// 校验库存是否足够和锁库存
List<LockStockDTO> skuLockList = orderItems.stream()
.map(item -> LockStockDTO.builder().skuId(item.getSkuId())
.count(item.getCount())
.orderToken(orderToken)
.build())
.collect(Collectors.toList());
Result<?> lockResult = skuFeignClient.lockStock(skuLockList);
if (!Result.success().getCode().equals(lockResult.getCode())) {
throw new BizException(Result.failed().getMsg());
}
// TCC模式创建订单(状态待支付)
OmsOrder order = seataTccOrderService.prepareSubmitOrder(null, submitDTO);
// 将订单放入延时队列超时未支付由交换机order.exchange切换到死信队列完成系统自动关单
log.info("订单超时取消RabbitMQ消息发送订单SN{}", orderToken);
rabbitTemplate.convertAndSend("order.exchange", "order.create", orderToken);
OrderSubmitVO submitVO = new OrderSubmitVO();
submitVO.setOrderId(order.getId());
submitVO.setOrderSn(order.getOrderSn());
log.info("订单提交响应:{}", submitVO);
return submitVO;
}
/**
* 订单支付
*
* @param orderId
* @param appId
* @return
*/
@Override
@SuppressWarnings("unchecked")
@GlobalTransactional(rollbackFor = Exception.class)
public <T> T pay(Long orderId, String appId, PayTypeEnum payTypeEnum) {
OmsOrder order = this.getById(orderId);
@ -315,11 +260,9 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
// 扣减库存
Result<?> deductStockResult = skuFeignClient.deductStock(order.getOrderSn());
if (!Result.isSuccess(deductStockResult)) {
throw new BizException("扣减商品库存失败");
}
return result;
} catch (InterruptedException e) {
log.error(e.getMessage(), e);
@ -336,6 +279,12 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
}
private Boolean balancePay(OmsOrder order) {
// 扣减余额
Long payAmount = order.getPayAmount();
@ -403,7 +352,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
@Override
public boolean closeOrder(String orderToken) {
log.info("=======================订单关闭订单SN{}=======================", orderToken);
log.info("订单超时取消orderToken:{}", orderToken);
OmsOrder order = this.getOne(new LambdaQueryWrapper<OmsOrder>()
.eq(OmsOrder::getOrderSn, orderToken));
if (order == null || !OrderStatusEnum.PENDING_PAYMENT.getCode().equals(order.getStatus())) {
@ -425,7 +374,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
@Override
public boolean cancelOrder(Long id) {
log.info("=======================订单取消订单ID{}=======================", id);
log.info("订单超时取消订单ID{}", id);
OmsOrder order = this.getById(id);
if (order == null) {
throw new BizException("订单不存在");
@ -516,18 +465,29 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, OmsOrder> impleme
}
/**
* 订单分页列表
* 订单验价
*
* @param queryParams
* @param orderTotalAmount 订单总金额
* @param orderItems 订单商品明细
* @return
*/
@Override
public IPage<OmsOrder> listOrdersWithPage(OrderPageQuery queryParams) {
Page<OmsOrder> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
List<OmsOrder> list = this.baseMapper.listUsersWithPage(page, queryParams);
page.setRecords(list);
return page;
private boolean checkOrderPrice(Long orderTotalAmount, List<OrderItemDTO> orderItems) {
CheckPriceDTO checkPriceDTO = new CheckPriceDTO();
List<CheckPriceDTO.CheckSku> checkSkus = orderItems.stream().map(orderFormItem -> {
CheckPriceDTO.CheckSku checkSku = new CheckPriceDTO.CheckSku();
checkSku.setSkuId(orderFormItem.getSkuId());
checkSku.setCount(orderFormItem.getCount());
return checkSku;
}).collect(Collectors.toList());
checkPriceDTO.setOrderTotalAmount(orderTotalAmount); // 订单总金额
checkPriceDTO.setCheckSkus(checkSkus); // 订单的商品明细
// 调用验价接口比较订单总金额和商品明细总金额不一致则说明商品价格变动
Result<Boolean> checkPriceResult = skuFeignClient.checkPrice(checkPriceDTO);
boolean result = Result.isSuccess(checkPriceResult) && Boolean.TRUE.equals(checkPriceResult.getData());
return result;
}
}

View File

@ -1,26 +0,0 @@
package com.youlai.mall.oms.tcc.idempotent;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
/**
* @Author DaniR
* @Description TCC幂等工具类
* @Date 2021/7/15 20:38
**/
public class IdempotentUtil {
private static Table<Class<?>,String,Long> map= HashBasedTable.create();
public static void addMarker(Class<?> clazz,String xid,Long marker){
map.put(clazz,xid,marker);
}
public static Long getMarker(Class<?> clazz,String xid){
return map.get(clazz,xid);
}
public static void removeMarker(Class<?> clazz,String xid){
map.remove(clazz,xid);
}
}

View File

@ -1,20 +0,0 @@
package com.youlai.mall.oms.tcc.service;
import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO;
import com.youlai.mall.oms.pojo.entity.OmsOrder;
import io.seata.rm.tcc.api.BusinessActionContext;
import io.seata.rm.tcc.api.BusinessActionContextParameter;
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.api.TwoPhaseBusinessAction;
@LocalTCC
public interface SeataTccOrderService {
@TwoPhaseBusinessAction(name = "prepareSubmitOrder", commitMethod = "commitSubmitOrder", rollbackMethod = "rollbackSubmitOrder")
OmsOrder prepareSubmitOrder(BusinessActionContext businessActionContext,
@BusinessActionContextParameter(paramName = "orderSubmitDTO") OrderSubmitDTO orderSubmitDTO);
boolean commitSubmitOrder(BusinessActionContext businessActionContext);
boolean rollbackSubmitOrder(BusinessActionContext businessActionContext);
}

View File

@ -1,101 +0,0 @@
package com.youlai.mall.oms.tcc.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.youlai.common.web.util.JwtUtils;
import com.youlai.mall.oms.enums.OrderStatusEnum;
import com.youlai.mall.oms.enums.OrderTypeEnum;
import com.youlai.mall.oms.mapper.OrderMapper;
import com.youlai.mall.oms.pojo.dto.OrderItemDTO;
import com.youlai.mall.oms.pojo.dto.OrderSubmitDTO;
import com.youlai.mall.oms.pojo.entity.OmsOrder;
import com.youlai.mall.oms.pojo.entity.OmsOrderItem;
import com.youlai.mall.oms.service.IOrderItemService;
import com.youlai.mall.oms.tcc.idempotent.IdempotentUtil;
import com.youlai.mall.oms.tcc.service.SeataTccOrderService;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
@Slf4j
@Component
public class SeataTccOrderServiceImpl implements SeataTccOrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private IOrderItemService orderItemService;
@Transactional
@Override
public OmsOrder prepareSubmitOrder(BusinessActionContext businessActionContext, OrderSubmitDTO orderSubmitDTO) {
log.info("==========创建 订单 第一阶段事务组Xid:{} ==========", businessActionContext.getXid());
List<OrderItemDTO> orderItems = orderSubmitDTO.getOrderItems();
String orderToken = orderSubmitDTO.getOrderToken();
// 创建订单(状态待支付)
OmsOrder order = new OmsOrder();
order.setOrderSn(orderToken)
.setStatus(OrderStatusEnum.PENDING_PAYMENT.getCode())
.setSourceType(OrderTypeEnum.APP.getCode())
.setMemberId(JwtUtils.getUserId())
.setRemark(orderSubmitDTO.getRemark())
.setPayAmount(orderSubmitDTO.getPayAmount())
.setTotalQuantity(orderItems.stream().map(item -> item.getCount()).reduce(0, (x, y) -> x + y))
.setTotalAmount(orderItems.stream().map(item -> item.getPrice() * item.getCount()).reduce(0l, (x, y) -> x + y));
orderMapper.insert(order);
int i = 1 / 0;
// 创建订单商品
List<OmsOrderItem> orderItemList = orderItems.stream().map(item -> OmsOrderItem.builder()
.orderId(order.getId())
.skuId(item.getSkuId())
.skuName(item.getSkuName())
.skuPrice(item.getPrice())
.skuPic(item.getPic())
.skuQuantity(item.getCount())
.skuTotalPrice(item.getCount() * item.getPrice())
.skuCode(item.getSkuCode())
.build()).collect(Collectors.toList());
orderItemService.saveBatch(orderItemList);
log.info("保存订单:{} 成功", order.getOrderSn());
IdempotentUtil.addMarker(getClass(), businessActionContext.getXid(), System.currentTimeMillis());
return order;
}
@Override
@Transactional
public boolean commitSubmitOrder(BusinessActionContext businessActionContext) {
if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
return true;
}
IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid());
return true;
}
@Override
@Transactional
public boolean rollbackSubmitOrder(BusinessActionContext businessActionContext) {
if (Objects.isNull(IdempotentUtil.getMarker(getClass(), businessActionContext.getXid()))) {
return true;
}
JSONObject jsonObject = (JSONObject) businessActionContext.getActionContext("orderSubmitDTO");
OrderSubmitDTO orderSubmitDTO = new OrderSubmitDTO();
BeanUtil.copyProperties(jsonObject, orderSubmitDTO);
OmsOrder omsOrder = orderMapper.selectOne(new LambdaQueryWrapper<OmsOrder>().eq(OmsOrder::getOrderSn, orderSubmitDTO.getOrderToken()));
if (Objects.nonNull(omsOrder)) {
orderItemService.remove(new LambdaQueryWrapper<OmsOrderItem>().eq(OmsOrderItem::getOrderId, omsOrder.getId()));
orderMapper.deleteById(omsOrder.getId());
}
IdempotentUtil.removeMarker(getClass(), businessActionContext.getXid());
return true;
}
}

View File

@ -1,13 +1,15 @@
package com.youlai.mall.pms.api;
import com.youlai.common.result.Result;
import com.youlai.mall.pms.pojo.dto.CheckPriceDTO;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import com.youlai.mall.pms.pojo.dto.app.LockStockDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@FeignClient(value = "mall-pms",contextId = "sku")
@FeignClient(value = "mall-pms", contextId = "sku")
public interface SkuFeignClient {
/**
@ -36,4 +38,12 @@ public interface SkuFeignClient {
Result deductStock(@RequestParam String orderToken);
/**
* 商品验价
*
* @param checkPriceDTO
* @return
*/
@PutMapping("/app-api/v1/sku/price/_check")
Result<Boolean> checkPrice(@RequestBody CheckPriceDTO checkPriceDTO);
}

View File

@ -0,0 +1,44 @@
package com.youlai.mall.pms.pojo.dto;
import lombok.Data;
import java.util.List;
/**
* 商品验价传输层实体
*
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
* @date 2022/2/7 22:52
*/
@Data
public class CheckPriceDTO {
/**
* 订单商品总金额
*/
private Long orderTotalAmount;
/**
* 订单商品明细
*/
private List<CheckSku> checkSkus;
/**
* 订单商品明细
*/
@Data
public static class CheckSku {
/**
* 商品ID
*/
private Long skuId;
/**
* 商品数量
*/
private Integer count;
}
}

View File

@ -13,6 +13,7 @@ import lombok.Data;
*/
@Data
public class PmsSku extends BaseEntity {
@TableId(type = IdType.AUTO)
private Long id;

View File

@ -3,54 +3,40 @@ package com.youlai.mall.pms.controller.admin;
import com.youlai.common.result.Result;
import com.youlai.mall.pms.pojo.entity.PmsSku;
import com.youlai.mall.pms.service.IPmsSkuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.*;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
* @author <a href="mailto:xianrui0365@163.com">haoxr</a>
* @date 2022/2/8
*/
@Api(tags = "「系统端」库存信息")
@RestController
@RequestMapping("/api/v1/inventories")
@RequestMapping("/api/v1/sku")
@RequiredArgsConstructor
public class StockController {
private final IPmsSkuService iPmsSkuService;
private final IPmsSkuService skuService;
@ApiOperation(value = "商品库存详情")
@ApiImplicitParam(name = "id", value = "商品ID", required = true, paramType = "path", dataType = "Long")
@GetMapping("/{id}")
public Result detail(@PathVariable Long id) {
PmsSku sku = iPmsSkuService.getById(id);
@GetMapping("/{skuId}")
public Result detail(
@PathVariable Long skuId
) {
PmsSku sku = skuService.getById(skuId);
return Result.success(sku);
}
@ApiOperation(value = "修改库存")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "商品ID", required = true, paramType = "path", dataType = "Long"),
@ApiImplicitParam(name = "sku", value = "实体JSON对象", required = true, paramType = "body", dataType = "PmsSku")
})
@PutMapping(value = "/{id}")
public Result update(@PathVariable Long id, @RequestBody PmsSku sku) {
boolean status = iPmsSkuService.updateById(sku);
@PutMapping(value = "/{skuId}")
public Result update(
@ApiParam("商品库存单元ID") @PathVariable Long skuId,
@RequestBody PmsSku sku
) {
boolean status = skuService.updateById(sku);
return Result.judge(status);
}
@ApiOperation(value = "修改商品库存")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "商品ID", required = true, paramType = "path", dataType = "Long"),
@ApiImplicitParam(name = "num", value = "库存数量", required = true, paramType = "query", dataType = "Long")
})
@PatchMapping("/{id}/stock")
public Result updateStock(@PathVariable Long id, @RequestParam Integer num) {
PmsSku sku = iPmsSkuService.getById(id);
sku.setStock(sku.getStock() + num);
boolean result = iPmsSkuService.updateById(sku);
return Result.judge(result);
}
}

View File

@ -1,6 +1,7 @@
package com.youlai.mall.pms.controller.app;
import com.youlai.common.result.Result;
import com.youlai.mall.pms.pojo.dto.CheckPriceDTO;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import com.youlai.mall.pms.pojo.dto.app.LockStockDTO;
import com.youlai.mall.pms.service.IPmsSkuService;
@ -23,13 +24,6 @@ public class SkuController {
private final IPmsSkuService skuService;
@ApiOperation(value = "获取商品库存详情")
@GetMapping("/{skuId}")
public Result<AppSkuDetailVO> getSkuDetail(@PathVariable Long skuId) {
AppSkuDetailVO sku = skuService.getSkuById(skuId);
return Result.success(sku);
}
@ApiOperation(value = "获取商品库存信息")
@GetMapping("/{skuId}")
public Result<SkuInfoDTO> getSkuInfo(
@ -39,7 +33,6 @@ public class SkuController {
return Result.success(skuInfo);
}
@ApiOperation("获取商品库存数量")
@GetMapping("/{skuId}/stock_num")
public Result<Integer> getStockNum(
@ -68,4 +61,11 @@ public class SkuController {
boolean result = skuService.deductStock(orderToken);
return Result.judge(result);
}
@ApiOperation(value = "商品验价")
@PostMapping("/price/_check")
public Result<Boolean> checkPrice(@RequestBody CheckPriceDTO checkPriceDTO) {
boolean result = skuService.checkPrice(checkPriceDTO);
return Result.judge(result);
}
}

View File

@ -3,8 +3,8 @@ package com.youlai.mall.pms.controller.app;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.youlai.common.result.Result;
import com.youlai.mall.pms.pojo.query.SpuPageQuery;
import com.youlai.mall.pms.pojo.vo.AppSpuPageVO;
import com.youlai.mall.pms.pojo.vo.AppSpuDetailVO;
import com.youlai.mall.pms.pojo.vo.GoodsPageVO;
import com.youlai.mall.pms.pojo.vo.GoodsDetailVO;
import com.youlai.mall.pms.service.IPmsSpuService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -27,18 +27,18 @@ public class SpuController {
@ApiOperation(value = "商品分页列表")
@GetMapping("/page")
public Result<List<AppSpuPageVO>> listSpuWithPage(SpuPageQuery queryParams) {
IPage<AppSpuPageVO> result = iPmsSpuService.listAppSpuWithPage(queryParams);
public Result<List<GoodsPageVO>> listGoodsWithPage(SpuPageQuery queryParams) {
IPage<GoodsPageVO> result = iPmsSpuService.listAppSpuWithPage(queryParams);
return Result.success(result.getRecords(), result.getTotal());
}
@ApiOperation(value = "获取商品详情")
@GetMapping("/{spuId}")
public Result<AppSpuDetailVO> getSpuDetail(
public Result<GoodsDetailVO> getGoodsDetail(
@ApiParam("商品ID") @PathVariable Long spuId
) {
AppSpuDetailVO appSpuDetailVO = iPmsSpuService.getAppSpuDetail(spuId);
return Result.success(appSpuDetailVO);
GoodsDetailVO goodsDetailVO = iPmsSpuService.getAppSpuDetail(spuId);
return Result.success(goodsDetailVO);
}
}

View File

@ -4,7 +4,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.youlai.mall.pms.pojo.entity.PmsSpu;
import com.youlai.mall.pms.pojo.query.SpuPageQuery;
import com.youlai.mall.pms.pojo.vo.AppSpuPageVO;
import com.youlai.mall.pms.pojo.vo.GoodsPageVO;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@ -25,7 +25,7 @@ public interface PmsSpuMapper extends BaseMapper<PmsSpu> {
* @param queryParams
* @return
*/
List<AppSpuPageVO> listAppSpuWithPage(Page<AppSpuPageVO> page, SpuPageQuery queryParams);
List<GoodsPageVO> listAppSpuWithPage(Page<GoodsPageVO> page, SpuPageQuery queryParams);
List<PmsSpu> list(Page<PmsSpu> page, String name, Long categoryId);

View File

@ -14,7 +14,7 @@ import java.util.List;
*/
@Data
@ApiModel("商品详情")
public class AppSpuDetailVO {
public class GoodsDetailVO {
@ApiModelProperty("商品基本信息")
private GoodsInfo goodsInfo;
@ -103,7 +103,7 @@ public class AppSpuDetailVO {
private Long price;
@ApiModelProperty("库存")
private Integer stock;
private Integer stockNum;
@ApiModelProperty("商品图片URL")
private String picUrl;

View File

@ -12,7 +12,7 @@ import lombok.Data;
*/
@ApiModel("商品分页对象")
@Data
public class AppSpuPageVO {
public class GoodsPageVO {
@ApiModelProperty("商品ID")
private Long id;

View File

@ -2,6 +2,7 @@ package com.youlai.mall.pms.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.common.result.Result;
import com.youlai.mall.pms.pojo.dto.CheckPriceDTO;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import com.youlai.mall.pms.pojo.entity.PmsSku;
import com.youlai.mall.pms.pojo.dto.app.LockStockDTO;
@ -54,5 +55,11 @@ public interface IPmsSkuService extends IService<PmsSku> {
boolean deductStock(String orderToken);
/**
* 商品验价
*
* @param checkPriceDTO
* @return
*/
boolean checkPrice(CheckPriceDTO checkPriceDTO);
}

View File

@ -6,9 +6,8 @@ import com.baomidou.mybatisplus.extension.service.IService;
import com.youlai.mall.pms.pojo.dto.admin.GoodsFormDTO;
import com.youlai.mall.pms.pojo.entity.PmsSpu;
import com.youlai.mall.pms.pojo.query.SpuPageQuery;
import com.youlai.mall.pms.pojo.vo.AppSpuDetailVO;
import com.youlai.mall.pms.pojo.vo.AppSpuPageVO;
import com.youlai.mall.pms.pojo.vo.admin.GoodsDetailVO;
import com.youlai.mall.pms.pojo.vo.GoodsDetailVO;
import com.youlai.mall.pms.pojo.vo.GoodsPageVO;
import java.util.List;
@ -26,7 +25,7 @@ public interface IPmsSpuService extends IService<PmsSpu> {
* @param queryParams
* @return
*/
IPage<AppSpuPageVO> listAppSpuWithPage(SpuPageQuery queryParams);
IPage<GoodsPageVO> listAppSpuWithPage(SpuPageQuery queryParams);
/**
@ -35,7 +34,7 @@ public interface IPmsSpuService extends IService<PmsSpu> {
* @param spuId
* @return
*/
AppSpuDetailVO getAppSpuDetail(Long spuId);
GoodsDetailVO getAppSpuDetail(Long spuId);
/**
@ -43,7 +42,7 @@ public interface IPmsSpuService extends IService<PmsSpu> {
* @param id
* @return
*/
GoodsDetailVO getGoodsById(Long id);
com.youlai.mall.pms.pojo.vo.admin.GoodsDetailVO getGoodsById(Long id);
IPage<PmsSpu> list(Page<PmsSpu> page, String name,Long categoryId);

View File

@ -10,6 +10,7 @@ import com.youlai.common.result.Result;
import com.youlai.common.web.exception.BizException;
import com.youlai.mall.pms.common.constant.PmsConstants;
import com.youlai.mall.pms.mapper.PmsSkuMapper;
import com.youlai.mall.pms.pojo.dto.CheckPriceDTO;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import com.youlai.mall.pms.pojo.dto.app.LockStockDTO;
import com.youlai.mall.pms.pojo.entity.PmsSku;
@ -159,6 +160,37 @@ public class PmsSkuServiceImpl extends ServiceImpl<PmsSkuMapper, PmsSku> impleme
return true;
}
/**
* 商品验价
*
* @param checkPriceDTO
* @return
*/
@Override
public boolean checkPrice(CheckPriceDTO checkPriceDTO) {
Long orderTotalAmount = checkPriceDTO.getOrderTotalAmount(); // 订单总金额
// 计算商品总金额
List<CheckPriceDTO.CheckSku> checkOrderItems = checkPriceDTO.getCheckSkus();
if (CollectionUtil.isNotEmpty(checkOrderItems)) {
List<Long> skuIds = checkOrderItems.stream()
.map(orderItem -> orderItem.getSkuId()).collect(Collectors.toList());
List<PmsSku> skuList = this.list(new LambdaQueryWrapper<PmsSku>().in(PmsSku::getId, skuIds)
.select(PmsSku::getId, PmsSku::getPrice));
// 商品总金额
Long skuTotalAmount = checkOrderItems.stream().map(checkOrderItem -> {
Long skuId = checkOrderItem.getSkuId();
PmsSku pmsSku = skuList.stream().filter(sku -> sku.getId().equals(skuId)).findFirst().orElse(null);
if (pmsSku != null) {
return pmsSku.getPrice() * checkOrderItem.getCount();
}
return 0L;
}).reduce(0L, Long::sum);
return orderTotalAmount.compareTo(skuTotalAmount) == 0;
}
return false;
}
/**
* 获取商品库存信息
@ -168,20 +200,9 @@ public class PmsSkuServiceImpl extends ServiceImpl<PmsSkuMapper, PmsSku> impleme
*/
@Override
public SkuInfoDTO getSkuInfo(Long skuId) {
SkuInfoDTO skuInfo= this.baseMapper.getSkuInfo(skuId);
SkuInfoDTO skuInfo = this.baseMapper.getSkuInfo(skuId);
return skuInfo;
}
/* private final SeataTccSkuService seataTccSkuService;
@Override
@GlobalTransactional
public Boolean lockStockTcc(List<LockStockDTO> skuLockList) {
seataTccSkuService.prepareSkuLockList(null, skuLockList);
String orderToken = skuLockList.get(0).getOrderToken();
redisTemplate.opsForValue().set(PmsConstants.LOCKED_STOCK_PREFIX + orderToken, JSONUtil.toJsonStr(skuLockList));
return true;
}*/
}

View File

@ -18,10 +18,9 @@ import com.youlai.mall.pms.pojo.entity.PmsSku;
import com.youlai.mall.pms.pojo.entity.PmsSpu;
import com.youlai.mall.pms.pojo.entity.PmsSpuAttributeValue;
import com.youlai.mall.pms.pojo.query.SpuPageQuery;
import com.youlai.mall.pms.pojo.vo.AppSpuDetailVO;
import com.youlai.mall.pms.pojo.vo.AppSpuPageVO;
import com.youlai.mall.pms.pojo.vo.GoodsDetailVO;
import com.youlai.mall.pms.pojo.vo.GoodsPageVO;
import com.youlai.mall.pms.pojo.vo.ProductHistoryVO;
import com.youlai.mall.pms.pojo.vo.admin.GoodsDetailVO;
import com.youlai.mall.pms.service.IPmsSkuService;
import com.youlai.mall.pms.service.IPmsSpuAttributeValueService;
import com.youlai.mall.pms.service.IPmsSpuService;
@ -55,9 +54,9 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
* @return
*/
@Override
public IPage<AppSpuPageVO> listAppSpuWithPage(SpuPageQuery queryParams) {
Page<AppSpuPageVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
List<AppSpuPageVO> list = this.baseMapper.listAppSpuWithPage(page, queryParams);
public IPage<GoodsPageVO> listAppSpuWithPage(SpuPageQuery queryParams) {
Page<GoodsPageVO> page = new Page<>(queryParams.getPageNum(), queryParams.getPageSize());
List<GoodsPageVO> list = this.baseMapper.listAppSpuWithPage(page, queryParams);
page.setRecords(list);
return page;
}
@ -69,14 +68,14 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
* @return
*/
@Override
public AppSpuDetailVO getAppSpuDetail(Long spuId) {
public GoodsDetailVO getAppSpuDetail(Long spuId) {
PmsSpu pmsSpu = this.getById(spuId);
Assert.isTrue(pmsSpu != null, "商品不存在");
AppSpuDetailVO appSpuDetailVO = new AppSpuDetailVO();
GoodsDetailVO goodsDetailVO = new GoodsDetailVO();
// 商品基本信息
AppSpuDetailVO.GoodsInfo goodsInfo = new AppSpuDetailVO.GoodsInfo();
GoodsDetailVO.GoodsInfo goodsInfo = new GoodsDetailVO.GoodsInfo();
BeanUtil.copyProperties(pmsSpu, goodsInfo, "album");
List<String> album = new ArrayList<>();
@ -88,19 +87,19 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
album.addAll(Arrays.asList(pmsSpu.getAlbum()));
goodsInfo.setAlbum(album);
}
appSpuDetailVO.setGoodsInfo(goodsInfo);
goodsDetailVO.setGoodsInfo(goodsInfo);
// 商品属性列表
List<AppSpuDetailVO.Attribute> attributeList = spuAttributeValueService.list(new LambdaQueryWrapper<PmsSpuAttributeValue>()
List<GoodsDetailVO.Attribute> attributeList = spuAttributeValueService.list(new LambdaQueryWrapper<PmsSpuAttributeValue>()
.eq(PmsSpuAttributeValue::getType, AttributeTypeEnum.ATTRIBUTE.getValue())
.eq(PmsSpuAttributeValue::getSpuId, spuId)
.select(PmsSpuAttributeValue::getId, PmsSpuAttributeValue::getName, PmsSpuAttributeValue::getValue)
).stream().map(item -> {
AppSpuDetailVO.Attribute attribute = new AppSpuDetailVO.Attribute();
GoodsDetailVO.Attribute attribute = new GoodsDetailVO.Attribute();
BeanUtil.copyProperties(item, attribute);
return attribute;
}).collect(Collectors.toList());
appSpuDetailVO.setAttributeList(attributeList);
goodsDetailVO.setAttributeList(attributeList);
// 商品规格列表
@ -110,7 +109,7 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
.select(PmsSpuAttributeValue::getId, PmsSpuAttributeValue::getName, PmsSpuAttributeValue::getValue)
);
List<AppSpuDetailVO.Specification> specList = new ArrayList<>();
List<GoodsDetailVO.Specification> specList = new ArrayList<>();
// 规格Map [key:"颜色",value:[{id:1,value:""},{id:2,value:""}]]
Map<String, List<PmsSpuAttributeValue>> specValueMap = specSourceList.stream()
.collect(Collectors.groupingBy(PmsSpuAttributeValue::getName));
@ -120,11 +119,11 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
List<PmsSpuAttributeValue> specValueSourceList = entry.getValue();
// 规格映射处理
AppSpuDetailVO.Specification spec = new AppSpuDetailVO.Specification();
GoodsDetailVO.Specification spec = new GoodsDetailVO.Specification();
spec.setName(specName);
if (CollectionUtil.isNotEmpty(specValueSourceList)) {
List<AppSpuDetailVO.Specification.Value> specValueList = specValueSourceList.stream().map(item -> {
AppSpuDetailVO.Specification.Value specValue = new AppSpuDetailVO.Specification.Value();
List<GoodsDetailVO.Specification.Value> specValueList = specValueSourceList.stream().map(item -> {
GoodsDetailVO.Specification.Value specValue = new GoodsDetailVO.Specification.Value();
specValue.setId(item.getId());
specValue.setValue(item.getValue());
return specValue;
@ -133,16 +132,17 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
specList.add(spec);
}
}
appSpuDetailVO.setSpecList(specList);
goodsDetailVO.setSpecList(specList);
// 商品SKU列表
List<PmsSku> skuSourceList = skuService.list(new LambdaQueryWrapper<PmsSku>().eq(PmsSku::getSpuId, spuId));
if (CollectionUtil.isNotEmpty(skuSourceList)) {
List<AppSpuDetailVO.Sku> skuList = skuSourceList.stream().map(item -> {
AppSpuDetailVO.Sku sku = new AppSpuDetailVO.Sku();
List<GoodsDetailVO.Sku> skuList = skuSourceList.stream().map(item -> {
GoodsDetailVO.Sku sku = new GoodsDetailVO.Sku();
BeanUtil.copyProperties(item, sku);
return sku;
}).collect(Collectors.toList());
appSpuDetailVO.setSkuList(skuList);
goodsDetailVO.setSkuList(skuList);
}
// 添加用户浏览历史记录
@ -154,7 +154,7 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
vo.setPicUrl(goodsInfo.getAlbum() != null ? goodsInfo.getAlbum().get(0) : null);
memberFeignClient.addProductViewHistory(vo);
}
return appSpuDetailVO;
return goodsDetailVO;
}
@ -165,8 +165,8 @@ public class PmsSpuServiceImpl extends ServiceImpl<PmsSpuMapper, PmsSpu> impleme
* @return
*/
@Override
public GoodsDetailVO getGoodsById(Long id) {
GoodsDetailVO goodsDetailVO = new GoodsDetailVO();
public com.youlai.mall.pms.pojo.vo.admin.GoodsDetailVO getGoodsById(Long id) {
com.youlai.mall.pms.pojo.vo.admin.GoodsDetailVO goodsDetailVO = new com.youlai.mall.pms.pojo.vo.admin.GoodsDetailVO();
PmsSpu spu = this.getById(id);
Assert.isTrue(spu != null, "商品不存在");

View File

@ -68,7 +68,7 @@ public class SeataTccSkuServiceImpl implements SeataTccSkuService {
);
// 提示订单哪些商品库存不足
List<Long> ids = unlockSkuList.stream().map(LockStockDTO::getSkuId).collect(Collectors.toList());
throw new BizException("商品" + ids.toString() + "库存不足");
throw new BizException("商品" + ids + "库存不足");
}
IdempotentUtil.addMarker(getClass(), businessActionContext.getXid(), System.currentTimeMillis());
return true;

View File

@ -72,7 +72,7 @@
<!--「移动端」商品分页列表-->
<select id="listAppSpuWithPage" resultType="com.youlai.mall.pms.pojo.vo.AppSpuPageVO">
<select id="listAppSpuWithPage" resultType="com.youlai.mall.pms.pojo.vo.GoodsPageVO">
SELECT
id,
NAME,

View File

@ -1,11 +1,13 @@
package com.youlai.mall.sms.pojo.to;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import lombok.Data;
import lombok.ToString;
/**
* 秒杀商品Redis存储
*
* @author huawei
* @desc 秒杀商品Redis存储 TO
* @email huawei_code@163.com
* @date 2021/3/7
*/
@ -65,6 +67,6 @@ public class SeckillSkuRedisTO {
/**
* 秒杀商品详情
*/
private AppSkuDetailVO skuInfo;
private SkuInfoDTO skuInfo;
}

View File

@ -1,5 +1,6 @@
package com.youlai.mall.sms.pojo.vo;
import com.youlai.mall.pms.pojo.dto.SkuInfoDTO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ -68,5 +69,5 @@ public class SmsSeckillSkuVO {
/**
* 秒杀商品详情
*/
private AppSkuDetailVO skuInfo;
private SkuInfoDTO skuInfo;
}