增加数据字典 tree 接口

This commit is contained in:
YunaiV
2019-03-06 21:39:25 +08:00
parent 1ebc7492fa
commit 63dd545c50
34 changed files with 1023 additions and 82 deletions

View File

@@ -0,0 +1,38 @@
package cn.iocoder.mall.product.convert;
import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO;
import cn.iocoder.mall.product.api.bo.ProductAttrSimpleBO;
import cn.iocoder.mall.product.api.bo.ProductAttrValueDetailBO;
import cn.iocoder.mall.product.api.bo.ProductAttrValueSimpleBO;
import cn.iocoder.mall.product.dataobject.ProductAttrDO;
import cn.iocoder.mall.product.dataobject.ProductAttrValueDO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface ProductAttrConvert {
ProductAttrConvert INSTANCE = Mappers.getMapper(ProductAttrConvert.class);
@Mappings({})
List<ProductAttrDetailBO> convert(List<ProductAttrDO> attrs);
@Mappings({})
ProductAttrValueDetailBO convert(ProductAttrValueDO value);
@Mappings({})
List<ProductAttrValueDetailBO> convert2(List<ProductAttrValueDO> values);
@Mappings({})
List<ProductAttrSimpleBO> convert3(List<ProductAttrDO> attrs);
// @Mappings({})
// ProductAttrValueSimpleBO convert3(ProductAttrValueDO value);
//
@Mappings({})
List<ProductAttrValueSimpleBO> convert4(List<ProductAttrValueDO> values);
}

View File

@@ -1,7 +1,7 @@
package cn.iocoder.mall.product.convert;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO;
import cn.iocoder.mall.product.api.bo.ProductAttrAndValuePairBO;
import cn.iocoder.mall.product.api.bo.ProductSkuDetailBO;
import cn.iocoder.mall.product.api.bo.ProductSpuBO;
import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO;
@@ -63,13 +63,13 @@ public interface ProductSpuConvert {
})
ProductSkuDetailBO convert2(ProductSkuDO sku);
@Mappings({})
default ProductSpuDetailBO convert2(ProductSpuDO spu, List<ProductSkuDO> skus, List<ProductAttrDetailBO> productAttrDetailBOs) {
@Mappings({}) // TODO 芋艿,后续细看下 mapstruct 的 API ,优化这块
default ProductSpuDetailBO convert2(ProductSpuDO spu, List<ProductSkuDO> skus, List<ProductAttrAndValuePairBO> productAttrDetailBOs) {
// 创建并转换 ProductSpuDetailBO 对象
ProductSpuDetailBO spuDetail = this.convert2(spu).setPicUrls(StringUtil.split(spu.getPicUrls(), ","));
// 创建 ProductAttrDetailBO 的映射。其中KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号
Map<Integer, ProductAttrDetailBO> productAttrDetailBOMap = productAttrDetailBOs.stream().collect(
Collectors.toMap(ProductAttrDetailBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
Map<Integer, ProductAttrAndValuePairBO> productAttrDetailBOMap = productAttrDetailBOs.stream().collect(
Collectors.toMap(ProductAttrAndValuePairBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
// 创建并转换 ProductSpuDetailBO 数组
spuDetail.setSkus(new ArrayList<>());
skus.forEach(sku -> {

View File

@@ -14,4 +14,12 @@ public interface ProductAttrMapper {
List<ProductAttrDO> selectListByIds(@Param("ids") Collection<Integer> ids);
List<ProductAttrDO> selectListByStatus(@Param("status") Integer status);
List<ProductAttrDO> selectListByNameLike(@Param("name") String name,
@Param("offset") Integer offset,
@Param("limit") Integer limit);
Integer selectCountByNameLike(@Param("name") String name);
}

View File

@@ -14,4 +14,8 @@ public interface ProductAttrValueMapper {
List<ProductAttrValueDO> selectListByIds(@Param("ids") Collection<Integer> ids);
List<ProductAttrValueDO> selectListByStatus(@Param("status") Integer status);
List<ProductAttrValueDO> selectListByAttrIds(@Param("attrIds") Collection<Integer> attrIds);
}

View File

@@ -2,16 +2,25 @@ package cn.iocoder.mall.product.service;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.product.api.ProductAttrService;
import cn.iocoder.mall.product.api.bo.ProductAttrAndValuePairBO;
import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO;
import cn.iocoder.mall.product.api.bo.ProductAttrPageBO;
import cn.iocoder.mall.product.api.bo.ProductAttrSimpleBO;
import cn.iocoder.mall.product.api.constant.ProductAttrConstants;
import cn.iocoder.mall.product.api.constant.ProductErrorCodeEnum;
import cn.iocoder.mall.product.api.dto.ProductAttrPageDTO;
import cn.iocoder.mall.product.convert.ProductAttrConvert;
import cn.iocoder.mall.product.dao.ProductAttrMapper;
import cn.iocoder.mall.product.dao.ProductAttrValueMapper;
import cn.iocoder.mall.product.dataobject.ProductAttrDO;
import cn.iocoder.mall.product.dataobject.ProductAttrValueDO;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -24,22 +33,25 @@ import java.util.stream.Collectors;
* @see cn.iocoder.mall.product.dataobject.ProductAttrValueDO
*/
@Service
public class ProductAttrServiceImpl {
@com.alibaba.dubbo.config.annotation.Service(validation = "true")
public class ProductAttrServiceImpl implements ProductAttrService {
@Autowired
private ProductAttrMapper productAttrMapper;
@Autowired
private ProductAttrValueMapper productValueMapper;
private ProductAttrValueMapper productAttrValueMapper;
public CommonResult<List<ProductAttrDetailBO>> validProductAttrAndValue(Set<Integer> productAttrValueIds) {
public CommonResult<List<ProductAttrAndValuePairBO>> validProductAttrAndValue(Set<Integer> productAttrValueIds, boolean validStatus) {
// 首先,校验规格值
List<ProductAttrValueDO> attrValues = productValueMapper.selectListByIds(productAttrValueIds);
List<ProductAttrValueDO> attrValues = productAttrValueMapper.selectListByIds(productAttrValueIds);
if (attrValues.size() != productAttrValueIds.size()) {
return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode());
}
for (ProductAttrValueDO attrValue : attrValues) { // 同时,校验下状态
if (ProductAttrConstants.ATTR_STATUS_DISABLE.equals(attrValue.getStatus())) {
return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode());
if (validStatus) {
for (ProductAttrValueDO attrValue : attrValues) { // 同时,校验下状态
if (ProductAttrConstants.ATTR_STATUS_DISABLE.equals(attrValue.getStatus())) {
return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_VALUE_NOT_EXIST.getCode());
}
}
}
// 然后,校验规格
@@ -48,17 +60,58 @@ public class ProductAttrServiceImpl {
if (attrs.size() != attrIds.size()) {
return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode());
}
for (ProductAttrDO attr : attrs) { // 同时,校验下状态
if (ProductAttrConstants.ATTR_VALUE_STATUS_DISABLE.equals(attr.getStatus())) {
return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode());
if (validStatus) {
for (ProductAttrDO attr : attrs) { // 同时,校验下状态
if (ProductAttrConstants.ATTR_VALUE_STATUS_DISABLE.equals(attr.getStatus())) {
return ServiceExceptionUtil.error(ProductErrorCodeEnum.PRODUCT_ATTR_NOT_EXIST.getCode());
}
}
}
// 返回成功
Map<Integer, ProductAttrDO> attrMap = attrs.stream().collect(Collectors.toMap(ProductAttrDO::getId, productAttrDO -> productAttrDO)); // ProductAttrDO 的映射,方便查找。
List<ProductAttrDetailBO> result = attrValues.stream().map(productAttrValueDO -> new ProductAttrDetailBO()
List<ProductAttrAndValuePairBO> result = attrValues.stream().map(productAttrValueDO -> new ProductAttrAndValuePairBO()
.setAttrId(productAttrValueDO.getAttrId()).setAttrName(attrMap.get(productAttrValueDO.getAttrId()).getName())
.setAttrValueId(productAttrValueDO.getId()).setAttrValueName(productAttrValueDO.getName())).collect(Collectors.toList());
return CommonResult.success(result);
}
@Override
public CommonResult<ProductAttrPageBO> getProductAttrPage(ProductAttrPageDTO productAttrPageDTO) {
ProductAttrPageBO productAttrPageBO = new ProductAttrPageBO();
// 查询分页数据
int offset = productAttrPageDTO.getPageNo() * productAttrPageDTO.getPageSize();
productAttrPageBO.setAttrs(ProductAttrConvert.INSTANCE.convert(productAttrMapper.selectListByNameLike(productAttrPageDTO.getName(),
offset, productAttrPageDTO.getPageSize())));
// 查询分页总数
productAttrPageBO.setCount(productAttrMapper.selectCountByNameLike(productAttrPageDTO.getName()));
// 将规格值拼接上去
if (!productAttrPageBO.getAttrs().isEmpty()) {
Set<Integer> attrIds = productAttrPageBO.getAttrs().stream().map(ProductAttrDetailBO::getId).collect(Collectors.toSet());
List<ProductAttrValueDO> attrValues = productAttrValueMapper.selectListByAttrIds(attrIds);
ImmutableListMultimap<Integer, ProductAttrValueDO> attrValueMap = Multimaps.index(attrValues, ProductAttrValueDO::getAttrId); // KEY 是 attrId VALUE 是 ProductAttrValueDO 数组
for (ProductAttrDetailBO productAttrDetailBO : productAttrPageBO.getAttrs()) {
productAttrDetailBO.setValues(ProductAttrConvert.INSTANCE.convert2(((attrValueMap).get(productAttrDetailBO.getId()))));
}
}
// 返回结果
return CommonResult.success(productAttrPageBO);
}
@Override
public CommonResult<List<ProductAttrSimpleBO>> getProductAttrList() {
// 查询所有开启的规格数组
List<ProductAttrSimpleBO> attrs = ProductAttrConvert.INSTANCE.convert3(productAttrMapper.selectListByStatus(ProductAttrConstants.ATTR_STATUS_ENABLE));
// 如果为空,则返回空
if (attrs.isEmpty()) {
return CommonResult.success(Collections.emptyList());
}
// 将规格值拼接上去
List<ProductAttrValueDO> attrValues = productAttrValueMapper.selectListByStatus(ProductAttrConstants.ATTR_VALUE_STATUS_ENABLE);
ImmutableListMultimap<Integer, ProductAttrValueDO> attrValueMap = Multimaps.index(attrValues, ProductAttrValueDO::getAttrId); // KEY 是 attrId VALUE 是 ProductAttrValueDO 数组
for (ProductAttrSimpleBO productAttrSimpleBO : attrs) {
productAttrSimpleBO.setValues(ProductAttrConvert.INSTANCE.convert4(((attrValueMap).get(productAttrSimpleBO.getId()))));
}
return CommonResult.success(attrs);
}
}

View File

@@ -6,7 +6,7 @@ import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.common.framework.util.StringUtil;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.product.api.ProductSpuService;
import cn.iocoder.mall.product.api.bo.ProductAttrDetailBO;
import cn.iocoder.mall.product.api.bo.ProductAttrAndValuePairBO;
import cn.iocoder.mall.product.api.bo.ProductSpuDetailBO;
import cn.iocoder.mall.product.api.bo.ProductSpuPageBO;
import cn.iocoder.mall.product.api.constant.ProductErrorCodeEnum;
@@ -61,7 +61,8 @@ public class ProductSpuServiceImpl implements ProductSpuService {
// 获得规格
Set<Integer> productAttrValueIds = new HashSet<>();
skus.forEach(sku -> productAttrValueIds.addAll(StringUtil.splitToInt(sku.getAttrs(), ",")));
CommonResult<List<ProductAttrDetailBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds);
CommonResult<List<ProductAttrAndValuePairBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds,
false); // 读取规格时,不考虑规格是否被禁用
if (validAttrResult.isError()) {
return CommonResult.error(validAttrResult);
}
@@ -81,7 +82,8 @@ public class ProductSpuServiceImpl implements ProductSpuService {
// 校验规格是否存在
Set<Integer> productAttrValueIds = new HashSet<>();
productSpuAddDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs()));
CommonResult<List<ProductAttrDetailBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds);
CommonResult<List<ProductAttrAndValuePairBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds
, true); // 读取规格时,需要考虑规格是否被禁用
if (validAttrResult.isError()) {
return CommonResult.error(validAttrResult);
}
@@ -126,7 +128,8 @@ public class ProductSpuServiceImpl implements ProductSpuService {
// 校验规格是否存在
Set<Integer> productAttrValueIds = new HashSet<>();
productSpuUpdateDTO.getSkus().forEach(productSkuAddDTO -> productAttrValueIds.addAll(productSkuAddDTO.getAttrs()));
CommonResult<List<ProductAttrDetailBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds);
CommonResult<List<ProductAttrAndValuePairBO>> validAttrResult = productAttrService.validProductAttrAndValue(productAttrValueIds,
true); // 读取规格时,需要考虑规格是否被禁用
if (validAttrResult.isError()) {
return CommonResult.error(validAttrResult);
}
@@ -203,10 +206,10 @@ public class ProductSpuServiceImpl implements ProductSpuService {
return CommonResult.success(productSpuPage);
}
private CommonResult<Boolean> validProductSku(List<ProductSkuAddOrUpdateDTO> productSkuAddDTOs, List<ProductAttrDetailBO> productAttrDetailBOs) {
private CommonResult<Boolean> validProductSku(List<ProductSkuAddOrUpdateDTO> productSkuAddDTOs, List<ProductAttrAndValuePairBO> productAttrDetailBOs) {
// 创建 ProductAttrDetailBO 的映射。其中KEY 为 ProductAttrDetailBO.attrValueId ,即规格值的编号
Map<Integer, ProductAttrDetailBO> productAttrDetailBOMap = productAttrDetailBOs.stream().collect(
Collectors.toMap(ProductAttrDetailBO::getAttrValueId, productAttrDetailBO -> productAttrDetailBO));
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());

View File

@@ -70,4 +70,41 @@
AND deleted = 0
</select>
<select id="selectListByNameLike" resultType="ProductAttrDO">
SELECT
<include refid="FIELDS" />
FROM product_attr
<where>
<if test="name != null">
name LIKE "%"#{name}"%"
</if>
AND deleted = 0
</where>
LIMIT #{offset}, #{limit}
</select>
<select id="selectCountByNameLike" resultType="Integer">
SELECT
COUNT(1)
FROM product_attr
<where>
<if test="name != null">
name LIKE "%"#{name}"%"
</if>
AND deleted = 0
</where>
</select>
<select id="selectListByStatus" parameterType="Integer" resultType="ProductAttrDO">
SELECT
<include refid="FIELDS" />
FROM product_attr
<where>
<if test="status != null">
status = #{status}
</if>
AND deleted = 0
</where>
</select>
</mapper>

View File

@@ -70,4 +70,27 @@
AND deleted = 0
</select>
<select id="selectListByAttrIds" resultType="ProductAttrValueDO">
SELECT
<include refid="FIELDS" />
FROM product_attr_value
WHERE attr_id IN
<foreach item="attrId" collection="attrIds" separator="," open="(" close=")" index="">
#{attrId}
</foreach>
AND deleted = 0
</select>
<select id="selectListByStatus" resultType="ProductAttrValueDO">
SELECT
<include refid="FIELDS" />
FROM product_attr_value
<where>
<if test="status != null">
status = #{status}
</if>
AND deleted = 0
</where>
</select>
</mapper>