(一)场景描述
在电子商城项目中,我们会有一个获取目录的查询,目录下面有子目录。在后台的时候,我们怎样获取数据库中已经设计好的目录呢?
首先,面对一个需求,我们想的是,要将这个需求的基本功能进行实现,然后再想优化的事,一般不会立马想到最优方案,当然久经沙场用于丰富的实战经验的将军除外,像我们这些初出茅庐的小兵,只能先填饱肚子,然后再思考怎样优化功能…哈哈,废话,不多说了。
(二)数据库表设计
pid是父目录的id,当pid为0时,表示为顶级目录。
(三)代码实现
mapper层这些,这里就不再进行赘述了…,这里只展示业务层的代码
- 递归实现
@Override
public List<ProductType> treeData() {
return treeDataRecursion(0L);
}
/**
* 获取商品的目录结构,
* 目前实现方式有两种:
* 其一:使用递归的方式
* 通过递归调用,获取所有的子目录,将所有的子目录存入在集合中,
* 递归的出口就是当前的子目录集合内为空,及当前目录没有儿子了
*
* 但是递归调用的性能很差,会每递归依次都会发送很多sql,容易给服务器造成很大的压力,用户直观的体验就是系统反应迟缓
*/
//首先获取所有的儿子
public List<ProductType> getAllChildren(Long pid){
Wrapper<ProductType> wrapper = new EntityWrapper<>();
wrapper.eq("pid",pid); //此处使用pid,是因为在mapper.xml内,进行另取别名
return productTypeMapper.selectList(wrapper);
}
public List<ProductType> treeDataRecursion(Long pid){
//首先获取所有的儿子
List<ProductType> allChildren = getAllChildren(pid);
//递归的出口,当前集合下面没有儿子
if(allChildren.size()==0 || allChildren==null){
return null;
}
//递归调用,获取当前目录下的子目录
for (ProductType current : allChildren){
//获取当前目录的儿子
List<ProductType> productTypes = treeDataRecursion(current.getId());
//将儿子设置给当前目录
current.setChildren(productTypes);
}
return allChildren;
}`
- 循环实现
@Override
public List<ProductType> treeData() {
return treeDataLoop();
}
/**
* 获取商品的目录结构,
* 其二:使用循环的方式
* 只发送一条sql,将所有的pid查询到内存,然后再内存中对目录进行组装
*/
public List<ProductType> treeDataLoop(){
//1. 只 发送一条sql语句,获取所有的目录 ,此时所有的目录已经存储在内存中
List<ProductType> allProductType = productTypeMapper.selectList(null);
//3. 使用集合存放所有的顶级目录
List<ProductType> first = new ArrayList<>();
//4. 使用Map,存放所有的对象,包括顶级目录
Map<Long, ProductType> map = new HashMap<>();
for (ProductType productType: allProductType) {
map.put(productType.getId(),productType);
}
//2. 对所有的目录进行组装,组装父子关系
for (ProductType productType: allProductType) {
//根据数据库中的设计,当目录的pid为0,说明此目录是一个顶级目录,
if(productType.getPid() == 0){
//将顶级目录存放到事先准备好的list中
first.add(productType);
}else{
//非顶级目录,需要进行父子关系的组装
//获取父级目录 ,使用之前的map,避免循环的嵌套使用
ProductType parentPt = null;
parentPt = map.get(productType.getPid());
//将当前的目录添加到父级目录内,作为儿子存在
parentPt.getChildren().add(productType);
}
}
//5. 最后直接返回顶级目录就可以,因为已经进行了父子的组装,找到父亲,就能找到儿子
return first;
}
考虑代码的重构和复用、注重性能的代码才是优质的代码
不断提升吧…共勉