0.思想
首先找到一級目錄(類別),然后從一級目錄(類別)遞歸獲取所有子目錄(類別),并組合成為一個“目錄樹”
1.普通實現(xiàn):controller層傳的是0層,就是一級目錄層,從這里開始往下遞歸。
/**
* 遞歸查詢得到,分類目錄數(shù)據(jù);(針對前臺的)
* @return
*/
@Override
public List<CategoryVO> listCategoryForCustomer() {
//定義一個List,這個List就用來存在最終的查詢結(jié)果;即,這個List中的直接元素是:所有的parent_id=0,即type=1的,第1級別的目錄;
List<CategoryVO> categoryVOList = new ArrayList<CategoryVO>();
//我們額外創(chuàng)建recursivelyFindCategories()方法,去實現(xiàn)遞歸查詢的邏輯;
//我們第一次遞歸查詢時,是先查一級目錄;(而一級目錄的parentId是0)
//該方法第一個參數(shù)是:List<CategoryVO> categoryVOList:用來存放當(dāng)前級別對應(yīng)的,所有的下一級目錄數(shù)據(jù);
// PS:對于【最終返回給前端的List<CategoryVO> categoryVOList】來說,其所謂的下一級目錄就是:所有的parent_id=0,即type=1的,第1級別的目錄;
// PS:對于【所有的parent_id=0,即type=1的,第1級別的目錄;】來說,其categoryVOList就是【List<CategoryVO> childCategory屬性】,其是用來存放該級別對應(yīng)的所有的parent_id=1,即type=2的,第2級別的目錄;
// PS:對于【所有的parent_id=1,即type=2的,第2級別的目錄;】來說,其categoryVOList就是【List<CategoryVO> childCategory屬性】,其是用來存放該級別對應(yīng)的所有的parent_id=2,即type=3的,第3級別的目錄;
//該方法的第二個參數(shù)是:當(dāng)前級別目錄的parent_id,即也就是當(dāng)前級別的上一級目錄的id;
//即,第一個參數(shù)是【上一級別的List<CategoryVO> categoryVOList】;第二參數(shù)是【下一級別的parent_id,也就是當(dāng)前級別的id】;
recursivelyFindCategories(categoryVOList, 0);
return categoryVOList;
}
/**
* 遞歸查詢分類目錄數(shù)據(jù)的,具體邏輯;;;其實就是,遞歸獲取所有目錄分類和子目錄分類,并組合稱為一個“目錄樹”;
* @param categoryVOList :存放所有下級別分類目錄的數(shù)據(jù);
* @param parentId :某級分類目錄的parentId;
*/
private void recursivelyFindCategories(List<CategoryVO> categoryVOList, Integer parentId) {
//首先,根據(jù)parent_id,查詢出所有該級別的數(shù)據(jù);(比如,第一次我們查詢的是parent_id=0,即type=1的,第1級別的目錄)
List<Category> categoryList = categoryMapper.selectCategoriesByParentId(parentId);
//然后,遍歷上面查詢的該級別的數(shù)據(jù);去嘗試查詢該級別數(shù)據(jù)的,下一級別的數(shù)據(jù);
if (!CollectionUtils.isEmpty(categoryList)) {
//遍歷所有查到的當(dāng)前級別數(shù)據(jù),把其放在對應(yīng)上級目錄的【List<CategoryVO> categoryVOList】中;
for (int i = 0; i < categoryList.size(); i++) {
//獲取到【上面查詢的,該級別數(shù)據(jù)中的,一條數(shù)據(jù)】,把其存儲到上級目錄的List<CategoryVO> childCategory屬性中;
//自然,如果該級別是【parent_id=0,即type=1的,第1級別的目錄】,就是把其存儲在最頂級的、返回給前端的那個List<CategoryVO> categoryVOS中;
Category category = categoryList.get(i);
CategoryVO categoryVo = new CategoryVO();
BeanUtils.copyProperties(category, categoryVo);
categoryVOList.add(categoryVo);
//然后,這一步是關(guān)鍵:針對【每一個當(dāng)前級別的,目錄數(shù)據(jù)】去遞歸調(diào)用recursivelyFindCategories()方法;
//自然,第一個參數(shù)是【當(dāng)前級別數(shù)據(jù)的,List<CategoryVO> childCategory屬性】:這是存放所有下級別目錄數(shù)據(jù)的;
//第二個參數(shù)是【當(dāng)前級別數(shù)據(jù)的id】:這自然是下級別目錄數(shù)據(jù)的parent_id:
recursivelyFindCategories(categoryVo.getChildCategory(), categoryVo.getId());
}
}
}
2.stream流實現(xiàn):
/**
* 利用stream 流實現(xiàn)
*
*/
@Override
public List<CategoryVO> listTree() {
//1.查出所有分類
List<Category> categories = categoryMapper.selectList();
//轉(zhuǎn)成VO實體集合類
List<CategoryVO> categoryVOS = new ArrayList<>();
//ArrayListBeanUtils.copyProperties(categories,categoryVOS);
//注意BeanUtils.copyProperties無法直接復(fù)制集合,要循環(huán);也可以單獨寫一個工具類,
//后續(xù)補充轉(zhuǎn)換集合工具類
for (Category category:categories
) {
CategoryVO categoryVO = new CategoryVO();
BeanUtils.copyProperties(category,categoryVO);
categoryVOS.add(categoryVO);
}
//2.組裝成父子的樹形結(jié)構(gòu)
//2.1 找到所有的一級分類
List<CategoryVO> collect = categoryVOS.stream().filter(categoryVO -> {
return categoryVO.getParentId() == 0;//一級分類就是父id=0是吧
}).map(menu -> {
menu.setChildCategory(getChildrens(menu,categoryVOS));
return menu;
}).sorted((menu1,menu2)->{//目錄排序
return (menu1.getOrderNum() ==null?0:menu1.getOrderNum() )- (menu2.getOrderNum() == null?0:menu2.getOrderNum());
}).collect(Collectors.toList());
return collect;
}
//遞歸查找所有菜單的子菜單
//root 當(dāng)前菜單,categoryList是菜單集合
private List<CategoryVO> getChildrens(CategoryVO root, List<CategoryVO> categoryList) {
//找出當(dāng)前菜單的子菜單
List<CategoryVO> children = categoryList.stream().filter(categoryVO -> {
//當(dāng)前菜單root的id等于(是)菜單集合中菜單的父Id,那就意味著當(dāng)前菜單就是子菜單
//當(dāng)前菜單root的id,是其他菜單的父id,意味著當(dāng)前菜單的子菜單找到了唄
return categoryVO.getParentId() == root.getId();
}).map(categoryVO -> {
//找到子菜單
categoryVO.setChildCategory(getChildrens(categoryVO, categoryList));
return categoryVO;
}).sorted((menu1,menu2)->{
//菜單的排序
return (menu1.getOrderNum() ==null?0:menu1.getOrderNum() )- (menu2.getOrderNum() == null?0:menu2.getOrderNum());
}).collect(Collectors.toList());
return children;
}
3.實體類集合專VO類集合的工具類
入?yún)槲粗愋偷膶嶓w集合與目標(biāo)集合的泛型字節(jié)碼類型(類名.class)
創(chuàng)建一個新集合用來存儲最終結(jié)果,泛型為目標(biāo)類型T
遍歷循環(huán)實體集合
通過Class獲取構(gòu)造器并創(chuàng)建新的實例
使用BeanUtils.copyProperties,將實體數(shù)據(jù)拷貝到目標(biāo)類型文章來源:http://www.zghlxwxcb.cn/news/detail-764416.html
將拷貝過數(shù)據(jù)的目標(biāo)類型添加到集合中文章來源地址http://www.zghlxwxcb.cn/news/detail-764416.html
public static <T> List<T> entityListToVOList(List<?> list, Class<T> clazz) {
List<T> result = new ArrayList<>(list.size());
for (Object source : list) {
T target;
try {
target = clazz.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException();
}
BeanUtils.copyProperties(source, target);
result.add(target);
}
return result;
}
到了這里,關(guān)于java返回前端樹形結(jié)構(gòu)數(shù)據(jù)(2種實現(xiàn)方式)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!