实体类 由于用到递归所以请看标红
/**
* 商品三级分类
* @TableName mall_product_type_info
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class MallProductTypeInfo implements Serializable {
/**
* 分类id
*/
@NotNull(message="[分类id]不能为空")
@ApiModelProperty("分类id")
private Long catId;
/**
* 分类名称
*/
@ApiModelProperty("分类名称")
private String name;
/**
* 父分类id
*/
@ApiModelProperty("父分类id")
private Long parentCid;
/**
* 层级
*/
@ApiModelProperty("层级")
private Integer catLevel;
/**
* 是否显示[0-不显示,1显示]
*/
@ApiModelProperty("是否显示[0-不显示,1显示]")
private Integer showStatus;
/**
* 排序
*/
@ApiModelProperty("排序")
private Integer sort;
/**
* 图标地址
*/
@ApiModelProperty("图标地址")
private String icon;
/**
* 计量单位
*/
@ApiModelProperty("计量单位")
private String productUnit;
/**
* 商品数量
*/
@ApiModelProperty("商品数量")
private Integer productCount;
/**
* 乐观锁
*/
@ApiModelProperty("乐观锁")
private Integer revision;
/**
* 子分类
*/
@TableField(exist = false)
private List<MallProductTypeInfo> children;
}
package com.spider.sync;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.spider.mapper.ClassificationMapper;
import com.spider.pojo.MallProductTypeInfo;
import com.spider.util.JsonUtil;
import com.spider.util.RedisCacheUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.annotation.Configuration;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import static java.awt.SystemColor.menu;
/**
* 📝 TODO 三级分类启动同步
* 🕟 2024/2/22 8:54
* 👦 Lxj
*/
@Configuration
public class RunnerSync implements ApplicationRunner {
@Autowired
private ClassificationMapper classificationMapper;
@Autowired
private RedisCacheUtil redisCacheUtil;
private static String MALL_PRODUCT_TYPE_INFO_REDIS = "mallProductTypeInfoList";
@Override
public void run(ApplicationArguments args) throws Exception {
//获取数据
List<MallProductTypeInfo> mallProductTypeInfoList = classificationMapper.selectList(new LambdaQueryWrapper<>());
List<MallProductTypeInfo> typeInfoList = mallProductTypeInfoList.stream().filter(mallProductTypeInfo -> {
//一级分类
return mallProductTypeInfo.getParentCid().equals(0L);
}).peek(menu ->
//子分类
menu.setChildren(getChildren(menu, mallProductTypeInfoList))
).sorted(
//catId排序
Comparator.comparing(MallProductTypeInfo::getCatId)
).collect(Collectors.toList());
//json存入redis
String jsonString = JsonUtil.toJSONString(typeInfoList);
redisCacheUtil.setCacheObject(MALL_PRODUCT_TYPE_INFO_REDIS,jsonString);
}
/**
* 获取子分类
* @param root 当前对象
* @param mallProductTypeInfoList 集合
* @return
*/
public List<MallProductTypeInfo> getChildren(MallProductTypeInfo root,
List<MallProductTypeInfo> mallProductTypeInfoList) {
List<MallProductTypeInfo> children = mallProductTypeInfoList.stream().filter(mallProductTypeInfo -> {
//子分类
return mallProductTypeInfo.getParentCid().equals(root.getCatId());
}).peek(menu ->
//递归 获取子分类
menu.setChildren(getChildren(menu, mallProductTypeInfoList))
).sorted(
//catId排序
Comparator.comparing(MallProductTypeInfo::getCatId)
).collect(Collectors.toList());
//最后一级结束递归
if(children == null || children.size()==0){
return null;
}
return children;
}
}
peek()
和 sorted()
都是 Java 8 中 Stream API 提供的中间操作(intermediate operation)方法,它们可以对一个 Stream 对象进行一些处理并返回一个新的 Stream 对象。
-
peek(Consumer<? super T> action)
方法允许你在流的每个元素上执行一些操作,而不会改变流的内容。它会将流的每个元素传递给参数action
执行,并返回原始的流对象。比如在你提供的代码中,peek()
方法将每个 MallProductTypeInfo 对象设置了子元素后返回了原始的流对象。需要注意的是peek()
方法不应该用来修改流中的元素,它的主要作用是允许你在流的每个元素上执行一些额外的操作,比如打印调试信息等。 -
sorted(Comparator<? super T> comparator)
方法可以按照指定的排序规则对流进行排序,并返回一个新的排序后的流对象。排序规则由参数comparator
指定,它是一个函数接口,用于比较流中的元素。在你提供的代码中,sorted()
方法使用了Comparator.comparing()
方法创建了一个按照catId
属性排序的比较器,并将其传递给sorted()
方法进行排序。
需要注意的是,这两个方法都是中间操作(intermediate operation),它们不会对流的元素进行实际的操作,只是返回一个新的流对象。只有当你调用流的终端操作(terminal operation)方法时,整个流才会被处理并产生结果。在你提供的代码中,collect(Collectors.toList())
方法是一个终端操作,它将排序后的流转换为一个 List 对象并返回。