商品库存锁定接口开发
This commit is contained in:
parent
4339d4de03
commit
90a8f1d1fc
@ -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;
|
||||||
|
@ -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("");
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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>
|
||||||
|
Loading…
Reference in New Issue
Block a user