开发企业后台管理应用时,经常会遇到一种场景:在树结构上做模糊查询。
比如:公司组织架构树、分类树等,通常是在页面上的文本框中输入一个关键字,例如"数据",然后在公司组织架构树中过滤出名字包含数据的部门,且保持树结构不变。
公司的一级部门、二级部门、三级部门等等,名字都有可能包含"数据",比如一级部门叫大数据部门,二级部门叫数据分析部门或数据开发部门等等,这些都是符合要求的。
下面我将造出一个简单的分类树,并实现在树结构上模糊查询的功能(这里为了简单,将树的层级固定为三级,但实际上树的层级是未知的且远远不止三级,那就需要用到递归了)。
分类实体:
class Category{
private String name;
private List<Category> children;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<Category> getChildren() {
return children;
}
public void setChildren(List<Category> children) {
this.children = children;
}
}
分类树json格式的数据[tree.json]:
[
{
"name": "JAVA",
"children": [
{
"name": "JAVA程序员",
"children": [
{
"name": "开发工程师"
},
{
"name": "技术总监"
}
]
},
{
"name": "JAVA大数据",
"children": [
{
"name": "离线处理"
},
{
"name": "实时处理"
}
]
},
{
"name": "JAVA架构",
"children": [
{
"name": "高可用架构"
},
{
"name": "高并发架构"
}
]
}
]
},
{
"name": "大数据工程师",
"children": [
{
"name": "大数据开发",
"children": [
{
"name": "离线计算"
},
{
"name": "实时计算"
}
]
},
{
"name": "大数据运维",
"children": [
{
"name": "平台搭建"
},
{
"name": "数据指标监控"
}
]
},
{
"name": "大数据分析",
"children": [
{
"name": "用户画像分析"
},
{
"name": "数据指标分析"
}
]
}
]
}
]
main方法:
// 读取json文件,将其反序列化为Java的List对象
StringBuilder sb = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(Test.class.getResourceAsStream("/tree.json")));
String line;
while (null != (line = reader.readLine())){
sb.append(line).append("\n");
}
reader.close();
List<Category> oneCategoryList = JSONArray.parseArray(sb.toString(), Category.class);
// 定义模糊查询关键词
String keyword = "开发";
// 树结构模糊查询核心逻辑
treeMatch(oneCategoryList,keyword);
// 输出模糊查询后的树的样子
System.out.println(JSONArray.toJSONString(oneCategoryList));
三级树结构模糊查询核心逻辑:
public static void treeMatch(List<Category> oneCategoryList,String keyword){
Iterator<Category> oneIter = oneCategoryList.iterator();
while (oneIter.hasNext()){
Category oneCategory = oneIter.next();
// 如果包含则什么也不做(不移除),否则就看二级目录
if(!oneCategory.getName().contains(keyword)){
List<Category> twoCategoryList = oneCategory.getChildren();
Iterator<Category> twoIter = twoCategoryList.iterator();
while (twoIter.hasNext()){
Category twoCategory = twoIter.next();
// 如果包含则什么也不做(不移除),否则就看三级目录
if(!twoCategory.getName().contains(keyword)){
List<Category> threeCategoryList = twoCategory.getChildren();
Iterator<Category> threeIter = threeCategoryList.iterator();
while (threeIter.hasNext()){
Category threeCategory = threeIter.next();
if(!threeCategory.getName().contains(keyword)){
threeIter.remove();
}
}
// 三级目录看完了,如果三级目录全部被移除,则移除二级目录
if(CollectionUtils.isEmpty(twoCategory.getChildren())){
twoIter.remove();
}
}
}
// 二级目录看完了,如果二级目录全部被移除,则移除一级目录
if(CollectionUtils.isEmpty(oneCategory.getChildren())){
oneIter.remove();
}
}
}
}
当关键字为"开发时",运行程序,得到的结果如下。
[
{
"children": [
{
"children": [
{
"name": "开发工程师"
}
],
"name": "JAVA程序员"
}
],
"name": "JAVA"
},
{
"children": [
{
"children": [
{
"name": "离线计算"
},
{
"name": "实时计算"
}
],
"name": "大数据开发"
}
],
"name": "大数据工程师"
}
]
本人已经验证过是没有问题的,如果疑问欢迎指正。
下面给出递归方式模糊查询的代码。
/**
* 递归方法
* @param anyLevelCategoryList 任意层级的目录集合
* @param keyword 关键字
*/
public static void treeMatch(List<Category> anyLevelCategoryList, String keyword){
Iterator<Category> iter = anyLevelCategoryList.iterator();
while (iter.hasNext()){
// 获取当前遍历到的目录
Category category = iter.next();
// 如果当前目录名称包含关键字,则什么也不做(不移除),否则就看下一级
if(!category.getName().contains(keyword)){
// 取出下一级目录集合
List<Category> childrenCategoryList = category.getChildren();
// 递归
if(!CollectionUtils.isEmpty(childrenCategoryList)){
treeMatch(childrenCategoryList,keyword);
}
// 下一级目录看完了,如果下一级目录全部被移除,则移除当前目录
if(CollectionUtils.isEmpty(category.getChildren())){
iter.remove();
}
}
}
}
输入数据格式如下:
假如查询的关键字是“曹”,运行,输出结果如下。
验证通过。