提交 8a0e33b8 编写于 作者: 郝先瑞

refactor: 订单重构优化

上级 054697e1
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 {
......
......@@ -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);
}
......
......@@ -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;
......
......@@ -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;
}
......@@ -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;
/**
* 商品sku价格(分)
*/
private Long skuPrice;
/**
* 商品购买的数量
*/
private Integer skuQuantity;
/**
* 商品sku总价格(分)
*/
private Long skuTotalPrice;
/**
* spu_id
*/
private Long spuId;
/**
* spu_name
*/
private String spuName;
/**
* spu_pic
*/
private String spuPic;
/**
* 品牌id
*/
private Long brandId;
private String picUrl;
/**
* 品牌名称
* 商品单价(单位:分)
*/
private String brandName;
private Long price;
/**
* 商品分类id
* 商品数量
*/
private Long categoryId;
private Integer count;
/**
* 商品分类名称
* 商品总金额(单位:分)
*/
private String categoryName;
private Long totalAmount;
/**
* 逻辑删除【0->正常;1->已删除】
* 逻辑删除(0:正常;1:已删除)
*/
private Integer deleted;
......
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 List<OrderItemDTO> orderItems;
/**
* 订单总金额-用于验价(单位:分)
*/
private Long totalAmount;
// 验价前台传值
private Long totalPrice;
/**
* 支付金额(单位:分)
*/
private Long payAmount;
/**
* 订单的商品明细
*/
private List<OrderItemDTO> orderItems;
// 收货地址
private UmsAddress deliveryAddress;
@Size(max = 500, message = "订单备注长度不能超过500")
private String remark;
/**
* 优惠券ID
*/
private String couponId;
private Long payAmount;
/**
* 收获地址
*/
private UmsAddress deliveryAddress;
}
......@@ -9,7 +9,7 @@ import java.util.List;
@Data
public class OrderConfirmVO extends BaseVO {
public class OrderConfirmVO {
private String orderToken;
......
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
*/
......
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) ;
/**
* 订单支付
......
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;
}
......
......@@ -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);
// 创建订单商品
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);
rabbitTemplate.convertAndSend("order.exchange", "order.create", orderToken);
OrderSubmitVO submitVO = new OrderSubmitVO();
submitVO.setOrderId(order.getId());
submitVO.setOrderSn(order.getOrderSn());
log.info("订单提交响应:{}", submitVO);
return submitVO;
}
boolean result = this.save(order);
@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();
// 添加订单明细
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);
}
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);
Assert.isTrue(result, "订单提交失败");
// 成功响应返回值构建
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;
}
}
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);
}
}
\ No newline at end of file
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);
}
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;
}
}
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 {
/**
......@@ -33,7 +35,15 @@ public interface SkuFeignClient {
* 扣减库存
*/
@PutMapping("/app-api/v1/sku/_deduct")
Result deductStock(@RequestParam String orderToken);
Result deductStock(@RequestParam String orderToken);
/**
* 商品验价
*
* @param checkPriceDTO
* @return
*/
@PutMapping("/app-api/v1/sku/price/_check")
Result<Boolean> checkPrice(@RequestBody CheckPriceDTO checkPriceDTO);
}
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;
}
}
......@@ -13,6 +13,7 @@ import lombok.Data;
*/
@Data
public class PmsSku extends BaseEntity {
@TableId(type = IdType.AUTO)
private Long id;
......
......@@ -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);
}
}
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,27 +24,19 @@ 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(
@ApiParam("商品库存单元ID") @PathVariable Long skuId
@ApiParam("商品库存单元ID") @PathVariable Long skuId
) {
SkuInfoDTO skuInfo = skuService.getSkuInfo(skuId);
return Result.success(skuInfo);
}
@ApiOperation("获取商品库存数量")
@GetMapping("/{skuId}/stock_num")
public Result<Integer> getStockNum(
@ApiParam("商品库存单元ID") @PathVariable Long skuId
@ApiParam("商品库存单元ID") @PathVariable Long skuId
) {
Integer stockNum = skuService.getStockNum(skuId);
return Result.success(stockNum);
......@@ -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);
}
}
......@@ -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);
}
}
......@@ -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);
......
......@@ -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;
......
......@@ -12,7 +12,7 @@ import lombok.Data;
*/
@ApiModel("商品分页对象")
@Data
public class AppSpuPageVO {
public class GoodsPageVO {
@ApiModelProperty("商品ID")
private Long id;
......
......@@ -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);
}
......@@ -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);
......
......@@ -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;
}*/
}
......@@ -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, "商品不存在");
......
......@@ -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;
......
......@@ -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,
......
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;
}
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;
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册