迁移商品分类树节点及创建商品分类

pull/2/MERGE
jiangweifan 2020-05-07 00:01:03 +08:00
parent 9da9a50b92
commit 20f2ad7416
15 changed files with 538 additions and 41 deletions

View File

@ -14,7 +14,7 @@
<artifactId>onemall</artifactId>
<version>1.0-SNAPSHOT</version>
<modules>
<!-- <module>product</module>-->
<module>product</module>
<!-- <module>order</module>-->
<!-- <module>user</module>-->
<module>common</module>

View File

@ -0,0 +1,55 @@
package cn.iocoder.mall.product.biz.bo.category;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: - BO
*/
@Data
@Accessors(chain = true)
public class ProductCategoryAddBO implements Serializable {
/**
*
*/
private Integer id;
/**
*
*
* pid = 0
*/
private Integer pid;
/**
*
*/
private String name;
/**
*
*/
private String description;
/**
*
*/
private String picUrl;
/**
*
*/
private Integer sort;
/**
*
*
* 1-
* 2-
*/
private Integer status;
/**
*
*/
private Date createTime;
}

View File

@ -0,0 +1,55 @@
package cn.iocoder.mall.product.biz.bo.category;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
import java.util.Date;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: - BO
*/
@Data
@Accessors(chain = true)
public class ProductCategoryAllListBO implements Serializable {
/**
*
*/
private Integer id;
/**
*
*
* pid = 0
*/
private Integer pid;
/**
*
*/
private String name;
/**
*
*/
private String description;
/**
*
*/
private String picUrl;
/**
*
*/
private Integer sort;
/**
*
*
* 1-
* 2-
*/
private Integer status;
/**
*
*/
private Date createTime;
}

View File

@ -11,6 +11,7 @@ import java.util.Date;
*/
@Data
@Accessors(chain = true)
@Deprecated // TODO jiangweifan 后面确认无使用后删除
public class ProductCategoryBO implements Serializable {
/**

View File

@ -0,0 +1,56 @@
package cn.iocoder.mall.product.biz.convert.category;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAddBO;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAllListBO;
import cn.iocoder.mall.product.biz.dataobject.product.ProductCategoryDO;
import cn.iocoder.mall.product.biz.dto.category.ProductCategoryAddDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: -
*/
@Mapper
public interface ProductCategoryConvert {
ProductCategoryConvert INSTANCE = Mappers.getMapper(ProductCategoryConvert.class);
/**
* - DOBO
* @param category
* @return
*/
@Mappings({})
ProductCategoryAllListBO convertToAllListBO(ProductCategoryDO category);
/**
* - DOBO {@link #convertToAllListBO(ProductCategoryDO)}
* @param category
* @return
*/
@Mappings({})
List<ProductCategoryAllListBO> convertToAllListBO(List<ProductCategoryDO> category);
/**
* - DTODO
* @param productCategoryAddDTO
* @return
*/
@Mappings({})
ProductCategoryDO convertToDO(ProductCategoryAddDTO productCategoryAddDTO);
/**
* - DOBO
* @param category
* @return
*/
@Mappings({})
ProductCategoryAddBO convertToAddBO(ProductCategoryDO category);
}

View File

@ -1,30 +0,0 @@
package cn.iocoder.mall.product.biz.convert.product;
import cn.iocoder.mall.product.biz.bo.product.ProductCategoryBO;
import cn.iocoder.mall.product.biz.dataobject.product.ProductCategoryDO;
import cn.iocoder.mall.product.biz.dto.product.ProductCategoryAddDTO;
import cn.iocoder.mall.product.biz.dto.product.ProductCategoryUpdateDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
import java.util.List;
@Mapper
public interface ProductCategoryConvert {
ProductCategoryConvert INSTANCE = Mappers.getMapper(ProductCategoryConvert.class);
@Mappings({})
ProductCategoryBO convertToBO(ProductCategoryDO category);
@Mappings({})
List<ProductCategoryBO> convertToBO(List<ProductCategoryDO> categoryList);
@Mappings({})
ProductCategoryDO convert(ProductCategoryAddDTO productCategoryAddDTO);
@Mappings({})
ProductCategoryDO convert(ProductCategoryUpdateDTO productCategoryUpdateDTO);
}

View File

@ -1,10 +1,16 @@
package cn.iocoder.mall.product.biz.dao.product;
import cn.iocoder.mall.product.biz.dataobject.product.ProductBrandDO;
import cn.iocoder.mall.product.biz.dataobject.product.ProductCategoryDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.springframework.stereotype.Repository;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description:
*/
@Repository
public interface ProductCategoryMapper extends BaseMapper<ProductBrandDO> {
public interface ProductCategoryMapper extends BaseMapper<ProductCategoryDO> {
}

View File

@ -1,41 +1,41 @@
package cn.iocoder.mall.product.biz.dto.product;
package cn.iocoder.mall.product.biz.dto.category;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* DTO
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: - DTO
*/
@Data
@Accessors(chain = true)
public class ProductCategoryAddDTO {
/**
* id
*/
private Integer adminId;
/**
*
*/
@NotNull(message = "父分类编号不能为空")
private Integer pid;
/**
*
*/
@NotNull(message = "名称不能为空")
private String name;
/**
*
*/
@NotNull(message = "描述不能为空")
private String description;
/**
*
*/
// @NotNull(message = "分类图片不能为空")
private String picUrl;
/**
*
*/
@NotNull(message = "排序值不能为空")
private Integer sort;
}

View File

@ -0,0 +1,28 @@
package cn.iocoder.mall.product.biz.service.product;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAddBO;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAllListBO;
import cn.iocoder.mall.product.biz.dto.category.ProductCategoryAddDTO;
import java.util.List;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: -
*/
public interface ProductCategoryService {
/**
*
* @return
*/
List<ProductCategoryAllListBO> getAllProductCategory();
/**
*
* @param productCategoryAddDTO
* @return
*/
ProductCategoryAddBO addProductCategory(ProductCategoryAddDTO productCategoryAddDTO);
}

View File

@ -0,0 +1,77 @@
package cn.iocoder.mall.product.biz.service.product.impl;
import cn.iocoder.common.framework.util.ServiceExceptionUtil;
import cn.iocoder.mall.mybatis.enums.DeletedStatusEnum;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAddBO;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAllListBO;
import cn.iocoder.mall.product.biz.convert.category.ProductCategoryConvert;
import cn.iocoder.mall.product.biz.dao.product.ProductCategoryMapper;
import cn.iocoder.mall.product.biz.dataobject.product.ProductCategoryDO;
import cn.iocoder.mall.product.biz.dto.category.ProductCategoryAddDTO;
import cn.iocoder.mall.product.biz.enums.ProductErrorCodeEnum;
import cn.iocoder.mall.product.biz.enums.product.ProductCategoryConstants;
import cn.iocoder.mall.product.biz.service.product.ProductCategoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: -
*/
@Service
public class ProductCategoryServiceImpl implements ProductCategoryService {
@Autowired
private ProductCategoryMapper productCategoryMapper;
/**
*
* @return
*/
@Override
public List<ProductCategoryAllListBO> getAllProductCategory() {
List<ProductCategoryDO> categoryList = productCategoryMapper.selectList(null);
return ProductCategoryConvert.INSTANCE.convertToAllListBO(categoryList);
}
/**
*
* @param productCategoryAddDTO
* @return
*/
@Override
public ProductCategoryAddBO addProductCategory(ProductCategoryAddDTO productCategoryAddDTO) {
// 校验父分类
validParent(productCategoryAddDTO.getPid());
// 保存到数据库
ProductCategoryDO productCategory = ProductCategoryConvert.INSTANCE.convertToDO(productCategoryAddDTO)
.setStatus(ProductCategoryConstants.STATUS_ENABLE);
productCategory.setCreateTime(new Date());
productCategory.setDeleted(DeletedStatusEnum.DELETED_NO.getValue());
productCategoryMapper.insert(productCategory);
// TODO jiangweifan 操作日志
// 返回成功
return ProductCategoryConvert.INSTANCE.convertToAddBO(productCategory);
}
/**
*
* @param pid
*/
private void validParent(Integer pid) {
if (!ProductCategoryConstants.PID_ROOT.equals(pid)) {
ProductCategoryDO parentCategory = productCategoryMapper.selectById(pid);
// 校验父分类是否存在
if (parentCategory == null) {
throw ServiceExceptionUtil.exception(ProductErrorCodeEnum.PRODUCT_CATEGORY_PARENT_NOT_EXISTS.getCode());
}
// 父分类必须是一级分类
if (!ProductCategoryConstants.PID_ROOT.equals(parentCategory.getPid())) {
throw ServiceExceptionUtil.exception((ProductErrorCodeEnum.PRODUCT_CATEGORY_PARENT_CAN_NOT_BE_LEVEL2.getCode()));
}
}
}
}

View File

@ -0,0 +1,78 @@
package cn.iocoder.mall.product.rest.controller.admins;
import cn.iocoder.common.framework.constant.MallConstants;
import cn.iocoder.common.framework.vo.CommonResult;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAddBO;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAllListBO;
import cn.iocoder.mall.product.biz.dto.category.ProductCategoryAddDTO;
import cn.iocoder.mall.product.biz.enums.product.ProductCategoryConstants;
import cn.iocoder.mall.product.biz.service.product.ProductCategoryService;
import cn.iocoder.mall.product.rest.convert.category.ProductCategoryConvert;
import cn.iocoder.mall.product.rest.request.category.AdminsProductCategoryAddRequest;
import cn.iocoder.mall.product.rest.response.category.AdminsProductCategoryAddResponse;
import cn.iocoder.mall.product.rest.response.category.AdminsProductCategoryTreeNodeResponse;
import cn.iocoder.mall.security.core.context.AdminSecurityContextHolder;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.common.framework.vo.CommonResult.success;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: - API
*/
@RestController
@RequestMapping(MallConstants.ROOT_PATH_ADMIN + "/category")
@Api(tags = "商品分类 API")
public class AdminsProductCategoryController {
@Autowired
private ProductCategoryService productCategoryService;
@GetMapping("/tree")
@ApiOperation("获取分类树结构")
public CommonResult<List<AdminsProductCategoryTreeNodeResponse>> tree() {
List<ProductCategoryAllListBO> productCategories = productCategoryService.getAllProductCategory();
// 创建 ProductCategoryTreeNodeVO Map
Map<Integer, AdminsProductCategoryTreeNodeResponse> treeNodeMap = productCategories.stream().collect(Collectors.toMap(ProductCategoryAllListBO::getId, ProductCategoryConvert.INSTANCE::convertToTreeNodeResponse));
// 处理父子关系
treeNodeMap.values().stream()
.filter(node -> !node.getPid().equals(ProductCategoryConstants.PID_ROOT))
.forEach((childNode) -> {
// 获得父节点
AdminsProductCategoryTreeNodeResponse parentNode = treeNodeMap.get(childNode.getPid());
if (parentNode.getChildren() == null) { // 初始化 children 数组
parentNode.setChildren(new ArrayList<>());
}
// 将自己添加到父节点中
parentNode.getChildren().add(childNode);
});
// 获得到所有的根节点
List<AdminsProductCategoryTreeNodeResponse> rootNodes = treeNodeMap.values().stream()
.filter(node -> node.getPid().equals(ProductCategoryConstants.PID_ROOT))
.sorted(Comparator.comparing(AdminsProductCategoryTreeNodeResponse::getSort))
.collect(Collectors.toList());
return success(rootNodes);
}
@PostMapping("/add")
@ApiOperation(value = "创建商品分类")
public CommonResult<AdminsProductCategoryAddResponse> add(@RequestBody AdminsProductCategoryAddRequest adminsProductCategoryAddRequest) {
// 转换 ProductCategoryAddDTO 对象
ProductCategoryAddDTO productCategoryAddDTO = ProductCategoryConvert.INSTANCE.convertToAddDTO(AdminSecurityContextHolder.getContext().getAdminId(), adminsProductCategoryAddRequest);
// 创建商品分类
ProductCategoryAddBO addProductCategoryBO = productCategoryService.addProductCategory(productCategoryAddDTO);
// 返回结果
return success(ProductCategoryConvert.INSTANCE.convertToAddResponse(addProductCategoryBO));
}
}

View File

@ -0,0 +1,47 @@
package cn.iocoder.mall.product.rest.convert.category;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAddBO;
import cn.iocoder.mall.product.biz.bo.category.ProductCategoryAllListBO;
import cn.iocoder.mall.product.biz.dto.category.ProductCategoryAddDTO;
import cn.iocoder.mall.product.rest.request.category.AdminsProductCategoryAddRequest;
import cn.iocoder.mall.product.rest.response.category.AdminsProductCategoryAddResponse;
import cn.iocoder.mall.product.rest.response.category.AdminsProductCategoryTreeNodeResponse;
import org.mapstruct.Mapper;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: - API
*/
@Mapper
public interface ProductCategoryConvert {
ProductCategoryConvert INSTANCE = Mappers.getMapper(ProductCategoryConvert.class);
/**
* - BOResponse
* @param productCategoryAllListBO
* @return
*/
@Mappings({})
AdminsProductCategoryTreeNodeResponse convertToTreeNodeResponse(ProductCategoryAllListBO productCategoryAllListBO);
/**
* - RequestDTO
* @param adminsProductCategoryAddRequest
* @return
*/
@Mappings({})
ProductCategoryAddDTO convertToAddDTO(Integer adminId, AdminsProductCategoryAddRequest adminsProductCategoryAddRequest);
/**
* - BOResponse
* @param productCategoryAddBO
* @return
*/
@Mappings({})
AdminsProductCategoryAddResponse convertToAddResponse(ProductCategoryAddBO productCategoryAddBO);
}

View File

@ -0,0 +1,48 @@
package cn.iocoder.mall.product.rest.request.category;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: - Request
*/
@ApiModel("创建商品分类Request")
@Data
@Accessors(chain = true)
public class AdminsProductCategoryAddRequest {
/**
*
*/
@ApiModelProperty(name = "pid", value = "父级分类编号", required = true, example = "1")
@NotNull(message = "父分类编号不能为空")
private Integer pid;
/**
*
*/
@ApiModelProperty(name = "name", value = "分类名字(标识)", required = true, example = "admin/info")
@NotNull(message = "名称不能为空")
private String name;
/**
*
*/
@ApiModelProperty(name = "description", value = "描述", required = true, example = "1")
@NotNull(message = "描述不能为空")
private String description;
/**
*
*/
@ApiModelProperty(name = "picUrl", value = "分类图片", example = "http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg/")
private String picUrl;
/**
*
*/
@ApiModelProperty(name = "sort", value = "排序", required = true, example = "1")
@NotNull(message = "排序值不能为空")
private Integer sort;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.mall.product.rest.response.category;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: - Response
*/
@ApiModel("创建商品分类Response")
@Data
@Accessors(chain = true)
public class AdminsProductCategoryAddResponse {
@ApiModelProperty(value = "分类编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "父分类编号", required = true, example = "0")
private Integer pid;
@ApiModelProperty(value = "分类名", required = true, example = "手机")
private String name;
@ApiModelProperty(value = "描述", required = true, example = "这个商品很吊")
private String description;
@ApiModelProperty(value = "分类图片", notes = "一般情况下,只有根分类才有图片", example = "http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
private String picUrl;
@ApiModelProperty(value = "排序值", required = true, example = "10")
private Integer sort;
@ApiModelProperty(value = "状态", required = true, notes = "1-开启2-关闭", example = "1")
private Integer status;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳")
private Date createTime;
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.mall.product.rest.response.category;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
import java.util.List;
/**
* @Author: jiangweifan
* @Date: 2020/5/6
* @Description: - Response
*/
@ApiModel("商品分类树节点")
@Data
@Accessors(chain = true)
public class AdminsProductCategoryTreeNodeResponse {
@ApiModelProperty(value = "分类编号", required = true, example = "1")
private Integer id;
@ApiModelProperty(value = "父分类编号", required = true, example = "0")
private Integer pid;
@ApiModelProperty(value = "分类名", required = true, example = "手机")
private String name;
@ApiModelProperty(value = "描述", required = true, example = "这个商品很吊")
private String description;
@ApiModelProperty(value = "分类图片", notes = "一般情况下,只有根分类才有图片", example = "http://www.iocoder.cn/images/common/wechat_mp_2017_07_31_bak.jpg")
private String picUrl;
@ApiModelProperty(value = "排序值", required = true, example = "10")
private Integer sort;
@ApiModelProperty(value = "状态", required = true, notes = "1-开启2-关闭", example = "1")
private Integer status;
@ApiModelProperty(value = "创建时间", required = true, example = "时间戳")
private Date createTime;
@ApiModelProperty(value = "子节点数组")
private List<AdminsProductCategoryTreeNodeResponse> children;
}