商品库存锁定接口开发

This commit is contained in:
jieyuu 2024-09-02 15:44:06 +08:00
parent 4339d4de03
commit 90a8f1d1fc
9 changed files with 184 additions and 15 deletions

View File

@ -1,7 +1,6 @@
package net.jieyuu.service.impl; package net.jieyuu.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.sun.org.apache.bcel.internal.generic.RETURN;
import net.jieyuu.model.ProductOrderDO; import net.jieyuu.model.ProductOrderDO;
import net.jieyuu.mapper.ProductOrderMapper; import net.jieyuu.mapper.ProductOrderMapper;
import net.jieyuu.service.ProductOrderService; import net.jieyuu.service.ProductOrderService;

View File

@ -16,7 +16,7 @@ public class InterceptorConfig implements WebMvcConfigurer {
registry registry
.addInterceptor(new LoginInterceptor()) .addInterceptor(new LoginInterceptor())
//拦截的路径 //拦截的路径
.addPathPatterns("/api/cart/*/**") .addPathPatterns("/api/product/*/lock_products", "/api/cart/*/**")
//放行的路径 //放行的路径
.excludePathPatterns(""); .excludePathPatterns("");

View File

@ -4,6 +4,7 @@ package net.jieyuu.controller;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiParam;
import net.jieyuu.request.LockProductRequest;
import net.jieyuu.service.ProductService; import net.jieyuu.service.ProductService;
import net.jieyuu.utils.JsonData; import net.jieyuu.utils.JsonData;
import net.jieyuu.vo.ProductVO; import net.jieyuu.vo.ProductVO;
@ -46,5 +47,18 @@ public class ProductController {
return JsonData.buildSuccess(productVO); return JsonData.buildSuccess(productVO);
} }
/**
* 商品库存锁定
*
* @return
*/
@ApiOperation("商品库存锁定")
@PutMapping("lock_products")
public JsonData lockProduct(@ApiParam("商品库存锁定") @RequestBody LockProductRequest lockProductRequest) {
JsonData jsonData = productService.lockProductStock(lockProductRequest);
return jsonData;
}
} }

View File

@ -2,6 +2,7 @@ package net.jieyuu.mapper;
import net.jieyuu.model.ProductDO; import net.jieyuu.model.ProductDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Param;
/** /**
* <p> * <p>
@ -13,4 +14,12 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
*/ */
public interface ProductMapper extends BaseMapper<ProductDO> { public interface ProductMapper extends BaseMapper<ProductDO> {
/**
* 锁定商品库存
*
* @param productId
* @param buyNum
* @return
*/
int lockProductStock(@Param("productId") long productId, @Param("buyNum") int buyNum);
} }

View File

@ -0,0 +1,24 @@
package net.jieyuu.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@ApiModel(value = "商品锁定对象", description = "商品锁定对象协议")
@Data
public class LockProductRequest {
@ApiModelProperty(value = "订单id", example = "1233332131231321")
@JsonProperty("order_out_trade_no")
private String orderOutTradeNo;
@ApiModelProperty(value = "订单项")
@JsonProperty("order_item_list")
private List<OrderItemRequest> orderItemList;
}

View File

@ -0,0 +1,20 @@
package net.jieyuu.request;
import com.fasterxml.jackson.annotation.JsonProperty;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel("商品子项")
@Data
public class OrderItemRequest {
@ApiModelProperty(value = "商品id",example = "1")
@JsonProperty("product_id")
private long productId;
@ApiModelProperty(value = "购买数量",example = "1")
@JsonProperty("buy_num")
private int buyNum;
}

View File

@ -1,7 +1,8 @@
package net.jieyuu.service; package net.jieyuu.service;
import net.jieyuu.model.ProductDO;
import com.baomidou.mybatisplus.extension.service.IService; import net.jieyuu.request.LockProductRequest;
import net.jieyuu.utils.JsonData;
import net.jieyuu.vo.ProductVO; import net.jieyuu.vo.ProductVO;
import java.util.List; import java.util.List;
@ -41,4 +42,12 @@ public interface ProductService {
* @return * @return
*/ */
List<ProductVO> findProductByIdBatch(List<Long> productIdList); List<ProductVO> findProductByIdBatch(List<Long> productIdList);
/**
* 锁定商品库存
*
* @param lockProductRequest
* @return
*/
JsonData lockProductStock(LockProductRequest lockProductRequest);
} }

View File

@ -4,10 +4,18 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import net.jieyuu.enums.BizCodeEnum;
import net.jieyuu.enums.StockTaskStateEnum;
import net.jieyuu.exception.BizException;
import net.jieyuu.mapper.ProductTaskMapper;
import net.jieyuu.model.ProductDO; import net.jieyuu.model.ProductDO;
import net.jieyuu.mapper.ProductMapper; import net.jieyuu.mapper.ProductMapper;
import net.jieyuu.model.ProductTaskDO;
import net.jieyuu.request.LockProductRequest;
import net.jieyuu.request.OrderItemRequest;
import net.jieyuu.service.ProductService; import net.jieyuu.service.ProductService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import net.jieyuu.utils.JsonData;
import net.jieyuu.vo.ProductVO; import net.jieyuu.vo.ProductVO;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@ -16,6 +24,7 @@ import org.springframework.stereotype.Service;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
/** /**
@ -33,6 +42,16 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im
@Autowired @Autowired
private ProductMapper productMapper; private ProductMapper productMapper;
@Autowired
private ProductTaskMapper productTaskMapper;
/**
* 分页查询商品列表
*
* @param page
* @param size
* @return
*/
@Override @Override
public Map<String, Object> page(int page, int size) { public Map<String, Object> page(int page, int size) {
Page<ProductDO> pageInfo = new Page<>(page, size); Page<ProductDO> pageInfo = new Page<>(page, size);
@ -47,6 +66,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im
return pageMap; return pageMap;
} }
/**
* 根据id找商品详情
*
* @param productId
* @return
*/
@Override @Override
public ProductVO findDetailById(long productId) { public ProductVO findDetailById(long productId) {
ProductDO productDO = productMapper.selectById(productId); ProductDO productDO = productMapper.selectById(productId);
@ -54,6 +79,12 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im
return beanProcess(productDO); return beanProcess(productDO);
} }
/**
* 批量查询
*
* @param productIdList
* @return
*/
@Override @Override
public List<ProductVO> findProductByIdBatch(List<Long> productIdList) { public List<ProductVO> findProductByIdBatch(List<Long> productIdList) {
List<ProductDO> productDOList = productMapper.selectList(new QueryWrapper<ProductDO>().in("id", productIdList)); List<ProductDO> productDOList = productMapper.selectList(new QueryWrapper<ProductDO>().in("id", productIdList));
@ -61,6 +92,59 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, ProductDO> im
return productVOList; return productVOList;
} }
/**
* 锁定商品库存
* 1)遍历商品锁定每个商品购买数量
* 2)每一次锁定的时候都要发送延迟消息
*
* @param lockProductRequest
* @return
*/
@Override
public JsonData lockProductStock(LockProductRequest lockProductRequest) {
String outTradeNo = lockProductRequest.getOrderOutTradeNo();
List<OrderItemRequest> orderItemList = lockProductRequest.getOrderItemList();
// 批量查询itemList的商品情况减少连接
// 提取itemList里面的所有id
List<Long> productIdList = orderItemList.stream().map(OrderItemRequest::getProductId).collect(Collectors.toList());
//一次查询结果分组
//批量查询商品最新数据
List<ProductVO> productVOList = this.findProductByIdBatch(productIdList);
//根据id进行分组
Map<Long, ProductVO> productMaps = productVOList.stream().collect(Collectors.toMap(ProductVO::getId, Function.identity()));
for (OrderItemRequest item : orderItemList) {
// 锁定商品记录
int rows = productMapper.lockProductStock(item.getProductId(), item.getBuyNum());
if (rows != 1) {
throw new BizException(BizCodeEnum.ORDER_CONFIRM_LOCK_PRODUCT_FAIL);
} else {
// 插入product_task
ProductVO productVO = productMaps.get(item.getProductId());
ProductTaskDO productTaskDO = new ProductTaskDO();
productTaskDO.setBuyNum(item.getBuyNum());
productTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
productTaskDO.setProductId(item.getProductId());
productTaskDO.setOutTradeNo(outTradeNo);
// 假若不需要插入商品名那么前文批量查询就不需要了
// 此处为冗余字段
productTaskDO.setProductName(productVO.getTitle());
// 插入product_task
productTaskMapper.insert(productTaskDO);
// 发送MQ延迟消息, 延迟解锁商品库存 todo
}
}
return null;
}
private ProductVO beanProcess(ProductDO obj) { private ProductVO beanProcess(ProductDO obj) {
ProductVO productVO = new ProductVO(); ProductVO productVO = new ProductVO();
BeanUtils.copyProperties(obj, productVO); BeanUtils.copyProperties(obj, productVO);

View File

@ -4,20 +4,30 @@
<!-- 通用查询映射结果 --> <!-- 通用查询映射结果 -->
<resultMap id="BaseResultMap" type="net.jieyuu.model.ProductDO"> <resultMap id="BaseResultMap" type="net.jieyuu.model.ProductDO">
<id column="id" property="id" /> <id column="id" property="id"/>
<result column="title" property="title" /> <result column="title" property="title"/>
<result column="cover_img" property="coverImg" /> <result column="cover_img" property="coverImg"/>
<result column="detail" property="detail" /> <result column="detail" property="detail"/>
<result column="old_amount" property="oldAmount" /> <result column="old_amount" property="oldAmount"/>
<result column="amount" property="amount" /> <result column="amount" property="amount"/>
<result column="stock" property="stock" /> <result column="stock" property="stock"/>
<result column="create_time" property="createTime" /> <result column="create_time" property="createTime"/>
<result column="lock_stock" property="lockStock" /> <result column="lock_stock" property="lockStock"/>
</resultMap> </resultMap>
<!-- 通用查询结果列 --> <!-- 通用查询结果列 -->
<sql id="Base_Column_List"> <sql id="Base_Column_List">
id, title, cover_img, detail, old_amount, amount, stock, create_time, lock_stock id
, title, cover_img, detail, old_amount, amount, stock, create_time, lock_stock
</sql> </sql>
<!--锁定商品库存-->
<update id="lockProductStock">
update product
set lock_stock = lock_stock + #{buyNum}
where id = #{productId}
and stock - lock_stock >={buyNum}
</update>
</mapper> </mapper>