开始迁移搜索服务

This commit is contained in:
YunaiV
2020-07-30 22:38:14 +08:00
parent d88da8229f
commit 981b3d87e2
59 changed files with 745 additions and 989 deletions

View File

@@ -1,37 +0,0 @@
package cn.iocoder.mall.product.biz.bo.attr;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* 商品规格值 VO
*/
@Data
@Accessors(chain = true)
public class ProductAttrValueBO implements Serializable {
/**
* 规格值编号
*/
private Integer id;
/**
* 规格编号
*/
private Integer attrId;
/**
* 规格值名
*/
private String name;
/**
* 状态
*/
private Integer status;
/**
* 创建时间
*/
private Date createTime;
}

View File

@@ -1,21 +0,0 @@
package cn.iocoder.mall.product.biz.dto.attr;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
/**
* Product 规格添加 DTO
*/
@Data
@Accessors(chain = true)
public class ProductAttrAddDTO {
/**
* 名称
*/
@NotEmpty(message = "规格名不能为空")
private String name;
}

View File

@@ -1,19 +0,0 @@
package cn.iocoder.mall.product.biz.dto.attr;
import cn.iocoder.common.framework.vo.PageParam;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
/**
* 商品规格模块 - 商品规格分页 DTO
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class ProductAttrPageDTO extends PageParam {
/**
* 商品规格名字
*/
private String name;
}

View File

@@ -1,28 +0,0 @@
package cn.iocoder.mall.product.biz.dto.attr;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* Product 规格修改 DTO
*/
@Data
@Accessors(chain = true)
public class ProductAttrUpdateDTO {
/**
* 规格编号
*/
@NotNull(message = "规格编号不能为空")
private Integer id;
/**
* 名称
*/
@NotEmpty(message = "规格名不能为空")
private String name;
}

View File

@@ -1,27 +0,0 @@
package cn.iocoder.mall.product.biz.dto.attr;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* Product 规格值添加 DTO
*/
@Data
@Accessors(chain = true)
public class ProductAttrValueAddDTO {
/**
* 规格编号
*/
@NotNull(message = "规格编号不能为空")
private Integer attrId;
/**
* 名称
*/
@NotEmpty(message = "规格值名不能为空")
private String name;
}

View File

@@ -1,29 +0,0 @@
package cn.iocoder.mall.product.biz.dto.attr;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
/**
* Product 规格值修改 DTO
*
* 注意,不允许修改所属规格
*/
@Data
@Accessors(chain = true)
public class ProductAttrValueUpdateDTO {
/**
* 规格值编号
*/
@NotNull(message = "规格编号不能为空")
private Integer id;
/**
* 名称
*/
@NotEmpty(message = "规格名不能为空")
private String name;
}

View File

@@ -1,27 +0,0 @@
package cn.iocoder.mall.product.biz.message;
import org.springframework.cloud.stream.annotation.Output;
import org.springframework.messaging.MessageChannel;
/**
* Spring Cloud Stream Source 接口
*/
public interface MQStreamProducer {
/**
* 商品更新 Output
*/
String PRODUCT_UPDATE_OUTPUT = "product-update-output";
@Output(PRODUCT_UPDATE_OUTPUT)
MessageChannel productUpdateOutput();
// default boolean sendProductUpdateMessage(ProductUpdateMessage message) {
// // 创建 Spring Message 对象
// Message<ProductUpdateMessage> springMessage = MessageBuilder.withPayload(message)
// .build();
// // 发送消息
// return productUpdateOutput().send(springMessage);
// }
}

View File

@@ -1,109 +0,0 @@
package cn.iocoder.mall.product.biz.message;
import org.springframework.stereotype.Service;
/**
* 商品收藏 消费者
* @author xiaofeng
* @date 2019/07/02 19:57
* @version 1.0
*/
@Service
//@RocketMQMessageListener(topic = ProductSpuCollectionMessage.TOPIC, consumerGroup = "product-spu-consumer-group-"
// + ProductSpuCollectionMessage.TOPIC)
public class UserProductSpuCollectionsConsumer
// implements RocketMQListener<ProductSpuCollectionMessage>
{
// @Autowired
// private UserProductSpuCollectionsService userProductSpuCollectionsService;
//
// @Reference(validation = "true", version = "${dubbo.consumer.UserService.version}")
// private UserService userService;
//
// @Override
// public void onMessage(ProductSpuCollectionMessage productSpuCollectionMessage) {
// UserBO userBO = userService.getUser(productSpuCollectionMessage.getUserId());
// if (userBO == null) {
// throw ServiceExceptionUtil.exception(UserErrorCodeEnum.USER_NOT_EXISTS.getCode());
// }
// // 收藏
// if (productSpuCollectionMessage.getHasCollectionType().equals(1)) {
// this.saveUserProductSpuCollections(productSpuCollectionMessage, userBO.getNickname());
// } else if (productSpuCollectionMessage.getHasCollectionType().equals(2)) {
// // 取消收藏
// this.deleteUserProductSpuCollections(productSpuCollectionMessage.getUserId(),
// productSpuCollectionMessage.getSpuId());
// }
//
// }
//
// /**
// * 保存商品收藏
// * @param productSpuCollectionMessage
// * @param nickname
// * @return
// */
// private int saveUserProductSpuCollections(final ProductSpuCollectionMessage productSpuCollectionMessage,
// final String nickname) {
// int result = 0;
// UserProductSpuCollectionsBO userProductSpuCollectionsBO = this.userProductSpuCollectionsService
// .getUserSpuCollectionsByUserIdAndSpuId(productSpuCollectionMessage.getUserId(),
// productSpuCollectionMessage.getSpuId());
// if (userProductSpuCollectionsBO == null) {
// UserProductSpuCollectionsAddDTO userProductSpuCollectionsAddDTO = UserProductSpuCollectionsConvert.INSTANCE
// .convert(productSpuCollectionMessage);
// userProductSpuCollectionsAddDTO.setNickname(StringUtils.isEmpty(nickname) ? "" : nickname);
// userProductSpuCollectionsAddDTO.setCreateTime(new Date());
// userProductSpuCollectionsAddDTO.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
// result = userProductSpuCollectionsService.addUserSkuCollections(userProductSpuCollectionsAddDTO);
// } else {
// // 存在重新收藏
// if (userProductSpuCollectionsBO.getDeleted().equals(DeletedStatusEnum.DELETED_YES.getValue())) {
// UserProductSpuCollectionsUpdateDTO userProductSpuCollectionsUpdateDTO = this
// .setUserProductSpuCollectionsUpdateDTO(userProductSpuCollectionsBO.getId(),
// DeletedStatusEnum.DELETED_NO);
// result = this.userProductSpuCollectionsService
// .updateUserProductSpuCollections(userProductSpuCollectionsUpdateDTO);
// }
// }
// return result;
// }
//
// /**
// * 取消收藏
// * @param userId
// * @param spuId
// * @return
// */
// private int deleteUserProductSpuCollections(final Integer userId, final Integer spuId) {
// UserProductSpuCollectionsBO userProductSpuCollectionsBO = this.userProductSpuCollectionsService
// .getUserSpuCollectionsByUserIdAndSpuId(userId, spuId);
// int result = 0;
// if (userProductSpuCollectionsBO != null) {
// // 未取消收藏的数据
// if (userProductSpuCollectionsBO.getDeleted().equals(DeletedStatusEnum.DELETED_NO.getValue())) {
// UserProductSpuCollectionsUpdateDTO userProductSpuCollectionsUpdateDTO = this
// .setUserProductSpuCollectionsUpdateDTO(userProductSpuCollectionsBO.getId(),
// DeletedStatusEnum.DELETED_YES);
// result = this.userProductSpuCollectionsService
// .updateUserProductSpuCollections(userProductSpuCollectionsUpdateDTO);
// }
// }
// return result;
// }
//
// /**
// * 设置更新值
// * @param id
// * @param deletedStatusEnum
// * @return
// */
// private UserProductSpuCollectionsUpdateDTO setUserProductSpuCollectionsUpdateDTO(final Integer id,
// final DeletedStatusEnum deletedStatusEnum) {
// return new UserProductSpuCollectionsUpdateDTO().setId(id).setUpdateTime(new Date())
// .setDeleted(deletedStatusEnum.getValue());
// }
}

View File

@@ -1,26 +1,10 @@
package cn.iocoder.mall.product.biz.service.attr;
import cn.iocoder.common.framework.enums.CommonStatusEnum;
import cn.iocoder.common.framework.validator.InEnum;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.product.biz.bo.attr.ProductAttrBO;
import cn.iocoder.mall.product.biz.bo.attr.ProductAttrSimpleWithValueBO;
import cn.iocoder.mall.product.biz.bo.attr.ProductAttrValueBO;
import cn.iocoder.mall.product.biz.bo.attr.ProductAttrWithValueBO;
import cn.iocoder.mall.product.biz.bo.product.ProductAttrAndValuePairBO;
import cn.iocoder.mall.product.biz.dto.attr.*;
import java.util.List;
import java.util.Set;
public interface ProductAttrService {
/**
* 获取规格分页数据
*
* @param productAttrPageDTO 查询参数
* @return 规格分页信息
*/
PageResult<ProductAttrWithValueBO> getProductAttrPage(ProductAttrPageDTO productAttrPageDTO);
/**
* 获得规格属性数组
@@ -31,40 +15,4 @@ public interface ProductAttrService {
*/
List<ProductAttrSimpleWithValueBO> getProductAttrList();
/**
* 添加商品规格
*
* @param adminId 操作人ID
* @param productAttrAddDTO 添加参数
* @return 添加的规格
*/
ProductAttrBO addProductAttr(Integer adminId, ProductAttrAddDTO productAttrAddDTO);
/**
* 更新规格
*
* @param adminId 操作人
* @param productAttrUpdateDTO 更新规格
* @return 成功标识
*/
Boolean updateProductAttr(Integer adminId, ProductAttrUpdateDTO productAttrUpdateDTO);
/**
* 更新规格状态
*
* @param adminId 操作人
* @param productAttrId 规格ID
* @param status 状态
* @return 成功标识
*/
Boolean updateProductAttrStatus(Integer adminId, Integer productAttrId, Integer status);
ProductAttrValueBO addProductAttrValue(Integer adminId, ProductAttrValueAddDTO productAttrValueAddDTO);
Boolean updateProductAttrValue(Integer adminId, ProductAttrValueUpdateDTO productAttrValueUpdateDTO);
Boolean updateProductAttrValueStatus(Integer adminId, Integer productAttrValueId,
@InEnum(value = CommonStatusEnum.class, message = "修改状态必须是 {value}") Integer status);
List<ProductAttrAndValuePairBO> validProductAttrAndValue(Set<Integer> productAttrValueIds, boolean validStatus);
}

View File

@@ -37,34 +37,6 @@ import java.util.stream.Collectors;
@Service
public class ProductAttrServiceImpl implements ProductAttrService {
@Autowired
private ProductAttrMapper productAttrMapper;
@Autowired
private ProductAttrValueMapper productAttrValueMapper;
@Override
public PageResult<ProductAttrWithValueBO> getProductAttrPage(ProductAttrPageDTO productAttrPageDTO) {
//查询分页
Page<ProductAttrDO> page = new Page<>(productAttrPageDTO.getPageNo(), productAttrPageDTO.getPageSize());
LambdaQueryWrapper<ProductAttrDO> queryWrapper = Wrappers.<ProductAttrDO>query().lambda()
.like(StringUtils.isNotBlank(productAttrPageDTO.getName()), ProductAttrDO::getName, productAttrPageDTO.getName())
.eq(ProductAttrDO::getDeleted, false);
IPage<ProductAttrDO> attrPage = productAttrMapper.selectPage(page, queryWrapper);
PageResult<ProductAttrWithValueBO> productAttrPage = ProductAttrConvert.INSTANCE.convertPage(attrPage);
// 将规格值拼接上去
if (!CollectionUtil.isEmpty(productAttrPage.getList())) {
Set<Integer> attrIds = productAttrPage.getList().stream().map(ProductAttrBO::getId).collect(Collectors.toSet());
List<ProductAttrValueDO> attrValues = productAttrValueMapper.selectList(Wrappers.<ProductAttrValueDO>query().lambda()
.in(ProductAttrValueDO::getAttrId, attrIds)
.eq(ProductAttrValueDO::getDeleted, false));
Map<Integer, List<ProductAttrValueDO>> attrValueMap = attrValues.stream().collect(Collectors.groupingBy(ProductAttrValueDO::getAttrId));
for (ProductAttrWithValueBO item : productAttrPage.getList()) {
item.setValues(ProductAttrConvert.INSTANCE.convertAttrValues(attrValueMap.get(item.getId())));
}
}
return productAttrPage;
}
@Override
public List<ProductAttrSimpleWithValueBO> getProductAttrList() {
// 查询所有开启的规格数组
@@ -87,157 +59,4 @@ public class ProductAttrServiceImpl implements ProductAttrService {
return attrs;
}
@Override
public ProductAttrBO addProductAttr(Integer adminId, ProductAttrAddDTO productAttrAddDTO) {
// 校验规格名不重复
int count = productAttrMapper.selectCount(Wrappers.<ProductAttrDO>query().lambda()
.eq(ProductAttrDO::getName, productAttrAddDTO.getName())
.eq(ProductAttrDO::getDeleted, false));
if (count > 0) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_EXISTS.getCode());
}
// 插入到数据库
ProductAttrDO productAttrDO = new ProductAttrDO().setName(productAttrAddDTO.getName())
.setStatus(ProductAttrConstants.ATTR_STATUS_ENABLE);
productAttrDO.setCreateTime(new Date());
productAttrDO.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
productAttrMapper.insert(productAttrDO);
// 返回成功
return ProductAttrConvert.INSTANCE.convertAttr(productAttrDO);
}
@Override
public Boolean updateProductAttr(Integer adminId, ProductAttrUpdateDTO productAttrUpdateDTO) {
// 校验存在
if (productAttrMapper.selectById(productAttrUpdateDTO.getId()) == null) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode());
}
// 校验规格名不重复
ProductAttrDO existsAttrDO = productAttrMapper.selectOne(Wrappers.<ProductAttrDO>query().lambda()
.eq(ProductAttrDO::getName, productAttrUpdateDTO.getName())
.eq(ProductAttrDO::getDeleted, false));
if (existsAttrDO != null && !existsAttrDO.getId().equals(productAttrUpdateDTO.getId())) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_EXISTS.getCode());
}
// 更新到数据库
ProductAttrDO updateProductAttr = ProductAttrConvert.INSTANCE.convertUpdate(productAttrUpdateDTO);
updateProductAttr.setUpdateTime(new Date());
int i = productAttrMapper.updateById(updateProductAttr);
// 返回成功
return i > 0;
}
@Override
public Boolean updateProductAttrStatus(Integer adminId, Integer productAttrId, Integer status) {
// 校验存在
ProductAttrDO productAttrDO = productAttrMapper.selectById(productAttrId);
if (productAttrDO == null) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode());
}
// 校验状态
if (productAttrDO.getStatus().equals(status)) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_STATUS_EQUALS.getCode());
}
// 更新到数据库
ProductAttrDO updateProductAttr = new ProductAttrDO().setId(productAttrId).setStatus(status);
int i = productAttrMapper.updateById(updateProductAttr);
return i > 0;
}
@Override
public ProductAttrValueBO addProductAttrValue(Integer adminId, ProductAttrValueAddDTO productAttrValueAddDTO) {
// 校验规格名不重复
int count = productAttrValueMapper.selectCount(Wrappers.<ProductAttrValueDO>query().lambda()
.eq(ProductAttrValueDO::getName, productAttrValueAddDTO.getName())
.eq(ProductAttrValueDO::getAttrId, productAttrValueAddDTO.getAttrId())
.eq(ProductAttrValueDO::getDeleted, false));
if (count > 0) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_EXISTS.getCode());
}
// 插入到数据库
ProductAttrValueDO productAttrValueDO = ProductAttrConvert.INSTANCE.convertValueAdd(productAttrValueAddDTO)
.setStatus(ProductAttrConstants.ATTR_VALUE_STATUS_ENABLE);
productAttrValueDO.setCreateTime(new Date());
productAttrValueDO.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
productAttrValueMapper.insert(productAttrValueDO);
return ProductAttrConvert.INSTANCE.convertAttrValue(productAttrValueDO);
}
@Override
public Boolean updateProductAttrValue(Integer adminId, ProductAttrValueUpdateDTO productAttrValueUpdateDTO) {
// 校验存在
ProductAttrValueDO productAttrValueDO = productAttrValueMapper.selectById(productAttrValueUpdateDTO.getId());
if (productAttrValueDO == null) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode());
}
// 校验规格名不重复
ProductAttrValueDO existsAttrDO = productAttrValueMapper.selectOne(Wrappers.<ProductAttrValueDO>query().lambda()
.eq(ProductAttrValueDO::getName, productAttrValueDO.getName())
.eq(ProductAttrValueDO::getAttrId, productAttrValueDO.getAttrId())
.eq(ProductAttrValueDO::getDeleted, false));
if (existsAttrDO != null && !existsAttrDO.getId().equals(productAttrValueUpdateDTO.getId())) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_EXISTS.getCode());
}
// 更新到数据库
ProductAttrValueDO updateProductValue = ProductAttrConvert.INSTANCE.convertValueUpdate(productAttrValueUpdateDTO);
updateProductValue.setUpdateTime(new Date());
int i = productAttrValueMapper.updateById(updateProductValue);
return i > 0;
}
@Override
public Boolean updateProductAttrValueStatus(Integer adminId, Integer productAttrValueId, Integer status) {
// 校验存在
ProductAttrValueDO productAttrValueDO = productAttrValueMapper.selectById(productAttrValueId);
if (productAttrValueDO == null) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode());
}
// 校验状态
if (productAttrValueDO.getStatus().equals(status)) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_STATUS_EQUALS.getCode());
}
// 更新到数据库
ProductAttrValueDO updateProductAttrValue = new ProductAttrValueDO().setId(productAttrValueId).setStatus(status);
int i = productAttrValueMapper.updateById(updateProductAttrValue);
return i > 0;
}
@Override
public List<ProductAttrAndValuePairBO> validProductAttrAndValue(Set<Integer> productAttrValueIds, boolean validStatus) {
// 首先,校验规格值
List<ProductAttrValueDO> attrValues = productAttrValueMapper.selectBatchIds(productAttrValueIds);
if (attrValues.size() != productAttrValueIds.size()) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode());
}
if (validStatus) {
// 同时,校验下状态
for (ProductAttrValueDO attrValue : attrValues) {
if (ProductAttrConstants.ATTR_STATUS_DISABLE.equals(attrValue.getStatus())) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode());
}
}
}
// 然后,校验规格
Set<Integer> attrIds = attrValues.stream().map(ProductAttrValueDO::getAttrId).collect(Collectors.toSet());
List<ProductAttrDO> attrs = productAttrMapper.selectBatchIds(attrIds);
if (attrs.size() != attrIds.size()) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode());
}
if (validStatus) {
// 同时,校验下状态
for (ProductAttrDO attr : attrs) {
if (ProductAttrConstants.ATTR_VALUE_STATUS_DISABLE.equals(attr.getStatus())) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode());
}
}
}
// 返回成功
// ProductAttrDO 的映射,方便查找。
Map<Integer, ProductAttrDO> attrMap = attrs.stream().collect(Collectors.toMap(ProductAttrDO::getId, productAttrDO -> productAttrDO));
return attrValues.stream().map(productAttrValueDO -> new ProductAttrAndValuePairBO()
.setAttrId(productAttrValueDO.getAttrId()).setAttrName(attrMap.get(productAttrValueDO.getAttrId()).getName())
.setAttrValueId(productAttrValueDO.getId()).setAttrValueName(productAttrValueDO.getName())).collect(Collectors.toList());
}
}

View File

@@ -62,109 +62,4 @@ public class ProductSpuServiceImpl implements ProductSpuService {
return ProductSpuConvert.INSTANCE.convert2(spu, skus, attrAndValuePairList, category);
}
public ProductSpuDetailBO addProductSpu(Integer adminId, ProductSpuAddDTO productSpuAddDTO) {
ProductSpuDetailBO productSpuDetailBO = addProductSpu0(adminId, productSpuAddDTO);
// 如果新增生成,发送创建商品 Topic 消息
// TODO 芋艿,先不考虑事务的问题。等后面的 fescar 一起搞
// sendProductUpdateMessage(productSpuDetailBO.getId());
// 返回成功
return productSpuDetailBO;
}
@SuppressWarnings("Duplicates")
@Transactional
public ProductSpuDetailBO addProductSpu0(Integer adminId, ProductSpuAddDTO productSpuAddDTO) {
// 校验商品分类分类存在
ProductCategoryDO category = productCategoryService.validProductCategory(productSpuAddDTO.getCid());
if (ProductCategoryNodeEnum.ROOT.getId().equals(category.getPid())) {
// 商品只能添加到二级分类下
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SPU_CATEGORY_MUST_BE_LEVEL2.getCode());
}
// 校验规格是否存在
Set<Integer> productAttrValueIds = new HashSet<>();
productSpuAddDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs()));
// 读取规格时,需要考虑规格是否被禁用
List<ProductAttrAndValuePairBO> attrAndValuePairList = productAttrService.validProductAttrAndValue(productAttrValueIds, true);
// 保存 Spu
ProductSpuDO spu = ProductSpuConvert.INSTANCE.convertToSpuDO(productSpuAddDTO)
.setPicUrls(StringUtil.join(productSpuAddDTO.getPicUrls(), ","))
.setSort(0); // 排序为 0
spu.setCreateTime(new Date());
spu.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
// 初始化 sku 相关信息到 spu 中
initSpuFromSkus(spu, productSpuAddDTO.getSkus());
productSpuMapper.insert(spu);
// 保存 Sku
List<ProductSkuDO> skus = productSpuAddDTO.getSkus().stream().map(productSkuAddDTO -> {
ProductSkuDO sku = ProductSpuConvert.INSTANCE.convertToSkuDO(productSkuAddDTO)
.setSpuId(spu.getId())
.setStatus(ProductSpuConstants.SKU_STATUS_ENABLE)
.setAttrs(StringUtil.join(productSkuAddDTO.getAttrs(), ","));
sku.setCreateTime(new Date());
sku.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
return sku;
}).collect(Collectors.toList());
// 校验 Sku 规格
validProductSku(productSpuAddDTO.getSkus(), attrAndValuePairList);
// 插入 SKU 到数据库
productSkuMapper.insertList(skus);
// 返回成功
return ProductSpuConvert.INSTANCE.convert2(spu, skus, attrAndValuePairList, category);
}
/**
* 根据 sku 数组,计算相关的字段到 spu 中。
*
* @param spu spu
* @param skus sku 数组
*/
private void initSpuFromSkus(ProductSpuDO spu, List<ProductSkuAddOrUpdateDTO> skus) {
assert skus.size() > 0; // 写个断言,避免下面警告
spu.setPrice(skus.stream().min(Comparator.comparing(ProductSkuAddOrUpdateDTO::getPrice)).get().getPrice()); // 求最小价格
spu.setQuantity(skus.stream().mapToInt(ProductSkuAddOrUpdateDTO::getQuantity).sum()); // 求库存之和
}
// private boolean sendProductUpdateMessage(Integer id) {
// // 创建 Message 对象
// ProductUpdateMessage message = new ProductUpdateMessage().setId(id);
// // 创建 Spring Message 对象
// Message<ProductUpdateMessage> springMessage = MessageBuilder.withPayload(message)
// .build();
// // 发送消息
// return mqStreamProducer.productUpdateOutput().send(springMessage);
// }
/**
* 校验 sku 是否合法
*
* @param productSkuAddDTOs sku 添加或修改信息
* @param productAttrDetailBOs 商品规格明细数组
*/
private void validProductSku(List<ProductSkuAddOrUpdateDTO> productSkuAddDTOs, List<ProductAttrAndValuePairBO> productAttrDetailBOs) {
// 创建 ProductAttrDetailBO 的映射。其中KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号
Map<Integer, ProductAttrAndValuePairBO> productAttrDetailBOMap = productAttrDetailBOs.stream().collect(
Collectors.toMap(ProductAttrAndValuePairBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
// 1. 先校验,一个 Sku 下,没有重复的规格。校验方式是,遍历每个 Sku ,看看是否有重复的规格 attrId
for (ProductSkuAddOrUpdateDTO sku : productSkuAddDTOs) {
Set<Integer> attrIds = sku.getAttrs().stream().map(attrValueId -> productAttrDetailBOMap.get(attrValueId).getAttrId())
.collect(Collectors.toSet());
if (attrIds.size() != sku.getAttrs().size()) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SKU_ATTR_CANT_NOT_DUPLICATE.getCode());
}
}
// 2. 再校验,每个 Sku 的规格值的数量,是一致的。
int attrSize = productSkuAddDTOs.get(0).getAttrs().size();
for (int i = 1; i < productSkuAddDTOs.size(); i++) {
if (attrSize != productSkuAddDTOs.get(i).getAttrs().size()) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SPU_ATTR_NUMBERS_MUST_BE_EQUALS.getCode());
}
}
// 3. 最后校验,每个 Sku 之间不是重复的
Set<Set<Integer>> skuAttrValues = new HashSet<>(); // 每个元素,都是一个 Sku 的 attrValueId 集合。这样,通过最外层的 Set ,判断是否有重复的.
for (ProductSkuAddOrUpdateDTO sku : productSkuAddDTOs) {
if (!skuAttrValues.add(new HashSet<>(sku.getAttrs()))) { // 添加失败,说明重复
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_SPU_SKU__NOT_DUPLICATE.getCode());
}
}
}
}

View File

@@ -1,2 +0,0 @@
##################### 业务模块 #####################

View File

@@ -1,19 +0,0 @@
spring:
# 数据源配置项
datasource:
url: jdbc:mysql://s1.iocoder.cn:3306/mall_product?useSSL=false&useUnicode=true&characterEncoding=UTF-8
driver-class-name: com.mysql.jdbc.Driver
username: root
password: 3WLiVUBEwTbvAfsh
# MyBatis Plus 配置项
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 虽然默认为 true ,但是还是显示去指定下。
global-config:
db-config:
id-type: auto
logic-delete-value: 1 # 逻辑已删除值(默认为 1)
logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: cn.iocoder.mall.product.biz.dataobject

View File

@@ -1,19 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.mall.product.biz.dao.sku.ProductSkuMapper">
<insert id="insertList" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
INSERT INTO product_sku (
spu_id, status, pic_url, attrs, price,
quantity, deleted, create_time
) VALUES
<foreach collection="productSkuDOs" item="productSkuDO" separator=",">
(#{productSkuDO.spuId}, #{productSkuDO.status}, #{productSkuDO.picUrl}, #{productSkuDO.attrs}, #{productSkuDO.price},
#{productSkuDO.quantity}, #{productSkuDO.deleted}, #{productSkuDO.createTime}
)
</foreach>
</insert>
</mapper>

View File

@@ -43,15 +43,6 @@ public class AdminsProductAttrController {
@Autowired
private ProductAttrService productAttrService;
@GetMapping("/attr/page")
@ApiOperation("获得规格分页")
public CommonResult<PageResult<AdminsProductAttrPageResponse>> attrPage(ProductAttrPageRequest request) {
ProductAttrPageDTO pageDTO = ProductAttrConvert.INSTANCE.convert(request);
PageResult<ProductAttrWithValueBO> productAttrPage = productAttrService.getProductAttrPage(pageDTO);
PageResult<AdminsProductAttrPageResponse> adminPageResponse = ProductAttrConvert.INSTANCE.convertPage(productAttrPage);
return CommonResult.success(adminPageResponse);
}
@GetMapping("/attr/tree")
@ApiOperation(value = "获得规格树结构", notes = "该接口返回的信息更为精简。一般用于前端缓存数据字典到本地。")
public CommonResult<List<AdminsProductAttrSimpleResponse>> tree() {
@@ -60,76 +51,4 @@ public class AdminsProductAttrController {
return CommonResult.success(ProductAttrConvert.INSTANCE.convertSimple(result));
}
@PostMapping("/attr/add")
@ApiOperation(value = "创建商品规格")
public CommonResult<AdminsProdutAttrResponse> addAttr(@Validated ProductAttrAddRequest addRequest) {
// 创建 ProductAttrAddDTO 对象
ProductAttrAddDTO productAttrAddDTO = new ProductAttrAddDTO().setName(addRequest.getName());
// 添加
ProductAttrBO result = productAttrService.addProductAttr(AdminSecurityContextHolder.getContext().getAdminId(), productAttrAddDTO);
return CommonResult.success(ProductAttrConvert.INSTANCE.convertAttr(result));
}
@PostMapping("/attr/update")
@ApiOperation(value = "修改商品规格")
public CommonResult<Boolean> updateAttr(@Validated ProductAttrUpdateRequest updateRequest) {
ProductAttrUpdateDTO productAttrUpdateDTO = ProductAttrConvert.INSTANCE.convertUpdate(updateRequest);
// 更新
return CommonResult.success(productAttrService.updateProductAttr(AdminSecurityContextHolder.getContext().getAdminId(), productAttrUpdateDTO));
}
@PostMapping("/attr/update_status")
@ApiOperation(value = "修改商品规格状态")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "规格编号", required = true, example = "100"),
@ApiImplicitParam(name = "status", value = "状态", required = true, example = "1")
})
public CommonResult<Boolean> updateAttrStatus(@RequestParam("id") Integer id,
@RequestParam("status") Integer status) {
return CommonResult.success(productAttrService.updateProductAttrStatus(AdminSecurityContextHolder.getContext().getAdminId(), id, status));
}
// TODO 芋艿 暂时不考虑 delete Attr 。因为关联逻辑比较多
@PostMapping("/attr_value/add")
@ApiOperation(value = "创建商品规格值")
@ApiImplicitParams({
@ApiImplicitParam(name = "attrId", value = "规格编号", required = true, example = "100"),
@ApiImplicitParam(name = "name", value = "规格值", required = true, example = "蓝色")
})
public CommonResult<AdminsProductAttrValueResponse> addAttrValue(@Validated ProductAttrValueAddRequest addRequest) {
// 创建 ProductAttrValueAddDTO 对象
ProductAttrValueAddDTO productAttrValueAddDTO = new ProductAttrValueAddDTO().setAttrId(addRequest.getAttrId()).setName(addRequest.getName());
// 添加
ProductAttrValueBO result = productAttrService.addProductAttrValue(AdminSecurityContextHolder.getContext().getAdminId(), productAttrValueAddDTO);
// 返回结果
return CommonResult.success(ProductAttrConvert.INSTANCE.convertAddResponse(result));
}
@PostMapping("/attr_value/update")
@ApiOperation(value = "修改商品规格值")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "规格值编号", required = true, example = "100"),
@ApiImplicitParam(name = "name", value = "规格值", required = true, example = "蓝色")
})
public CommonResult<Boolean> updateAttrValue(@RequestParam("id") Integer id,
@RequestParam("name") String name) {
// 创建 ProductAttrValueUpdateDTO 对象
ProductAttrValueUpdateDTO productAttrValueUpdateDTO = new ProductAttrValueUpdateDTO().setId(id).setName(name);
// 更新
return CommonResult.success(productAttrService.updateProductAttrValue(AdminSecurityContextHolder.getContext().getAdminId(), productAttrValueUpdateDTO));
}
@PostMapping("/attr_value/update_status")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "规格编号", required = true, example = "100"),
@ApiImplicitParam(name = "status", value = "状态", required = true, example = "1")
})
public CommonResult<Boolean> updateAttrValueStatus(@RequestParam("id") Integer id,
@RequestParam("status") Integer status) {
return CommonResult.success(productAttrService.updateProductAttrValueStatus(AdminSecurityContextHolder.getContext().getAdminId(), id, status));
}
// TODO 芋艿 暂时不考虑 delete Attr Value 。因为关联逻辑比较多
}

View File

@@ -1,93 +0,0 @@
package cn.iocoder.mall.product.rest.controller.brand;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.product.biz.bo.brand.ProductBrandBO;
import cn.iocoder.mall.product.biz.dto.brand.ProductBrandAddDTO;
import cn.iocoder.mall.product.biz.dto.brand.ProductBrandPageDTO;
import cn.iocoder.mall.product.biz.dto.brand.ProductBrandUpdateDTO;
import cn.iocoder.mall.product.biz.service.brand.ProductBrandService;
import cn.iocoder.mall.product.rest.convert.brand.ProductBrandConvert;
import cn.iocoder.mall.product.rest.request.brand.ProductBrandAddRequest;
import cn.iocoder.mall.product.rest.request.brand.ProductBrandPageRequest;
import cn.iocoder.mall.product.rest.request.brand.ProductBrandUpdateRequest;
import cn.iocoder.mall.product.rest.response.brand.AdminsProductBrandResponse;
import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import static cn.iocoder.common.framework.vo.CommonResult.success;
@RestController
@RequestMapping("admins/brand")
@Api("管理员 - 商品品牌 API")
@AllArgsConstructor
public class AdminsProductBrandController {
private final ProductBrandService productBrandService;
@PostMapping("/add")
@ApiOperation("创建品牌")
public CommonResult<AdminsProductBrandResponse> add(@Validated ProductBrandAddRequest addRequest) {
// 创建 ProductBrandAddDTO 对象
ProductBrandAddDTO productBrandAddDTO = ProductBrandConvert.INSTANCE.convertAdd(addRequest);
// 保存品牌
ProductBrandBO result = productBrandService.addProductBrand(AdminSecurityContextHolder.getContext().getAdminId(), productBrandAddDTO);
// 返回结果
return success(ProductBrandConvert.INSTANCE.convert(result));
}
@PostMapping("/update")
@ApiOperation("更新商品")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "品牌主键", required = true, example = "1"),
@ApiImplicitParam(name = "name", value = "品牌名称", required = true, example = "安踏"),
@ApiImplicitParam(name = "description", value = "品牌描述", required = true, example = "安踏拖鞋"),
@ApiImplicitParam(name = "picUrl", value = "品牌图片", required = true, example = "http://www.iocoder.cn"),
@ApiImplicitParam(name = "status", value = "状态 1开启 2禁用", required = true, example = "1")
})
// TODO FROM 芋艿 to q2118cs只要改成了 bean 接收,就不用在写 @ApiImplicitParam 注解啦,直接在 bean 里写就 ok 啦
public CommonResult<Boolean> update(@Validated ProductBrandUpdateRequest updateRequest) {
// 创建 productBrandUpdateDTO 对象
ProductBrandUpdateDTO productBrandUpdateDTO = ProductBrandConvert.INSTANCE.convertUpdate(updateRequest);
// 更新商品
return success(productBrandService.updateProductBrand(AdminSecurityContextHolder.getContext().getAdminId(), productBrandUpdateDTO));
}
@GetMapping("/get")
@ApiOperation("获取品牌")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "品牌主键", required = true, example = "1")
})
public CommonResult<AdminsProductBrandResponse> add(@RequestParam("id") Integer id) {
// 保存商品
ProductBrandBO result = productBrandService.getProductBrand(id);
// 返回结果
return success(ProductBrandConvert.INSTANCE.convert(result));
}
@GetMapping("/page")
@ApiOperation("获得品牌分页")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "品牌名称", required = true, example = "安踏"),
@ApiImplicitParam(name = "description", value = "品牌描述", required = true, example = "安踏拖鞋"),
@ApiImplicitParam(name = "status", value = "状态 1开启 2禁用", required = true, example = "1"),
@ApiImplicitParam(name = "pageNo", value = "页码", required = true, example = "1"),
@ApiImplicitParam(name = "pageSize", value = "页面大小", required = true, example = "10")
})
public CommonResult<PageResult<AdminsProductBrandResponse>> attrPage(ProductBrandPageRequest pageRequest) {
// 创建 ProductBrandPageDTO 对象
ProductBrandPageDTO productBrandPageDTO = ProductBrandConvert.INSTANCE.convertPageRequest(pageRequest);
// 查询分页
PageResult<ProductBrandBO> productBrandPage = productBrandService.getProductBrandPage(productBrandPageDTO);
PageResult<AdminsProductBrandResponse> adminPageResponse = ProductBrandConvert.INSTANCE.convertPage(productBrandPage);
return CommonResult.success(adminPageResponse);
}
}

View File

@@ -1,18 +1,7 @@
package cn.iocoder.mall.product.rest.convert.attr;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.product.biz.bo.attr.ProductAttrBO;
import cn.iocoder.mall.product.biz.bo.attr.ProductAttrSimpleWithValueBO;
import cn.iocoder.mall.product.biz.bo.attr.ProductAttrValueBO;
import cn.iocoder.mall.product.biz.bo.attr.ProductAttrWithValueBO;
import cn.iocoder.mall.product.biz.dto.attr.ProductAttrPageDTO;
import cn.iocoder.mall.product.biz.dto.attr.ProductAttrUpdateDTO;
import cn.iocoder.mall.product.rest.request.attr.ProductAttrPageRequest;
import cn.iocoder.mall.product.rest.request.attr.ProductAttrUpdateRequest;
import cn.iocoder.mall.product.rest.response.attr.AdminsProductAttrPageResponse;
import cn.iocoder.mall.product.rest.response.attr.AdminsProductAttrSimpleResponse;
import cn.iocoder.mall.product.rest.response.attr.AdminsProdutAttrResponse;
import cn.iocoder.mall.product.rest.response.attr.AdminsProductAttrValueResponse;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@@ -24,22 +13,8 @@ public interface ProductAttrConvert {
ProductAttrConvert INSTANCE = Mappers.getMapper(ProductAttrConvert.class);
@Mappings({})
ProductAttrPageDTO convert(ProductAttrPageRequest bean);
@Mappings({})
PageResult<AdminsProductAttrPageResponse> convertPage(PageResult<ProductAttrWithValueBO> productAttrPage);
@Mappings({})
List<AdminsProductAttrSimpleResponse> convertSimple(List<ProductAttrSimpleWithValueBO> simpleList);
@Mappings({})
AdminsProdutAttrResponse convertAttr(ProductAttrBO attrBO);
@Mappings({})
ProductAttrUpdateDTO convertUpdate(ProductAttrUpdateRequest updateRequest);
@Mappings({})
AdminsProductAttrValueResponse convertAddResponse(ProductAttrValueBO result);
}

View File

@@ -1,35 +0,0 @@
package cn.iocoder.mall.product.rest.convert.brand;
import cn.iocoder.common.framework.vo.PageResult;
import cn.iocoder.mall.product.biz.bo.brand.ProductBrandBO;
import cn.iocoder.mall.product.biz.dto.brand.ProductBrandAddDTO;
import cn.iocoder.mall.product.biz.dto.brand.ProductBrandPageDTO;
import cn.iocoder.mall.product.biz.dto.brand.ProductBrandUpdateDTO;
import cn.iocoder.mall.product.rest.request.brand.ProductBrandAddRequest;
import cn.iocoder.mall.product.rest.request.brand.ProductBrandPageRequest;
import cn.iocoder.mall.product.rest.request.brand.ProductBrandUpdateRequest;
import cn.iocoder.mall.product.rest.response.brand.AdminsProductBrandResponse;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface ProductBrandConvert {
ProductBrandConvert INSTANCE = Mappers.getMapper(ProductBrandConvert.class);
@Mappings({})
AdminsProductBrandResponse convert(ProductBrandBO brand);
@Mappings({})
ProductBrandAddDTO convertAdd(ProductBrandAddRequest addRequest);
@Mappings({})
ProductBrandUpdateDTO convertUpdate(ProductBrandUpdateRequest updateRequest);
@Mappings({})
ProductBrandPageDTO convertPageRequest(ProductBrandPageRequest pageRequest);
@Mappings({})
PageResult<AdminsProductBrandResponse> convertPage(PageResult<ProductBrandBO> productBrandPage);
}

View File

@@ -1,36 +0,0 @@
package cn.iocoder.mall.product.rest.response.brand;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotEmpty;
/**
* VO
*/
@ApiModel(value = "商品品牌", description = "商品品牌")
@Data
@Accessors(chain = true)
public class AdminsProductBrandResponse {
/**
* 规格编号
*/
@ApiModelProperty(value = "品牌编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(name = "name", value = "品牌名称", required = true, example = "安踏")
@NotEmpty(message = "品牌名称不能为空")
private String name;
@ApiModelProperty(name = "description", value = "品牌描述", required = true, example = "安踏拖鞋")
private String description;
@ApiModelProperty(name = "picUrl", value = "品牌图片", required = true, example = "http://www.iocoder.cn")
private String picUrl;
@ApiModelProperty(name = "status", value = "状态 1开启 2禁用", required = true, example = "1")
private Integer status;
}

View File

@@ -1,20 +0,0 @@
package cn.iocoder.mall.product.api.message;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 商品更新(包括创建)消息
*/
@Data
@Accessors(chain = true)
public class ProductUpdateMessage {
public static final String TOPIC = "ProductUpdate";
/**
* 商品编号
*/
private Integer id;
}

View File

@@ -151,14 +151,4 @@ public class ProductSpuServiceImpl implements ProductSpuService {
return ProductSpuConvert.INSTANCE.convert3(skus, spus, attrAndValuePairList);
}
private boolean sendProductUpdateMessage(Integer id) {
// 创建 Message 对象
ProductUpdateMessage message = new ProductUpdateMessage().setId(id);
// 创建 Spring Message 对象
Message<ProductUpdateMessage> springMessage = MessageBuilder.withPayload(message)
.build();
// 发送消息
return mqStreamProducer.productUpdateOutput().send(springMessage);
}
}

View File

@@ -68,8 +68,4 @@ public class AdminsProductSpuController {
return success(ProductSpuConvert.INSTANCE.convert3(list));
}
private <T> List<T> parseSkus(String skuStr, Class<T> clazz) {
return JSON.parseArray(skuStr, clazz);
}
}