【智能排班系统】门店地址设置:省市区数据树形结构构建及其前端展示(级联选择器)【java+vue】

181 阅读4分钟

🎯导读:本文介绍了一种基于Java的技术方案,用于构建中国省市区的多级树形结构数据。首先定义了一个VO类AreaItemVo以封装地区信息。服务层通过查询数据库并利用Stream API筛选和构建树形结构,实现了getAreaTree()方法。此外,还提供了一个辅助方法searchSon()用于递归地查找子节点。控制器层则负责响应前端请求并返回树形数据。前端采用Element UI的级联选择器展示数据,并进行了优化处理,确保无子节点时的显示效果更佳。 🏠️ 项目仓库:智能排班系统 📙 项目介绍:【智能排班系统】开源说明

省市区数据

数据形式为sql文件,数据表字段设计如下,请点击数据下载

在这里插入图片描述

后端

vo

由于数据需要在前端显示,为了方便使用前端组件,特意封装此vo类

import lombok.AllArgsConstructor;
import lombok.Data;

import java.util.List;

/**
 * 存储地址项 如广东省 茂名市 电白区
 */
@Data
@AllArgsConstructor
public class AreaItemVo {
    /**
     * 存储id
     */
    private Long value;
    private String label;
    private List<AreaItemVo> children;

    public AreaItemVo(Long value, String label) {
        this.value = value;
        this.label = label;
    }
}

service

这段Java代码是用于构建一个表示地区层级结构(例如省份、城市、区县)的树形结构。以下是代码的详细解析:

方法 getAreaTree()

  1. 初始化结果列表:

    • 创建一个空的 ArrayList 类型的 areaItemVoList,用于存储最终构建好的树形结构。
  2. 查询数据库:

    • 调用 baseMapper.selectList(null) 方法从数据库中获取所有的省份、城市、区县等地理区域数据,并将其存储在 provinceCityRegionEntityList 列表中。
  3. 筛选省份:

    • 使用 Java 8 的 Stream API 对 provinceCityRegionEntityList 进行过滤,找出所有父ID为0的实体(即省份),并将它们收集到一个新的列表 fatherList 中。
  4. 构建树形结构:

    • 遍历 fatherList(省份列表)中的每个省份实体 father
      • 创建一个新的 AreaItemVo 实例,其中包含省份的ID和名称。
      • 调用 searchSon() 方法递归地构建该省份下的子节点(即城市和区县)。
      • 将构建好的省份节点添加到 areaItemVoList
  5. 返回结果:

    • 返回填充完成的 areaItemVoList,即整个地区的树形结构。

方法 searchSon()

  1. 查找子节点:

    • 使用 Stream API 对 provinceCityRegionEntityList 进行过滤,找出所有父ID与传入的 AreaItemVo 的值(即省份ID/市ID)相匹配的实体。
  2. 构建子节点:

    • 对于每个找到的子实体 item1
      • 创建一个新的 AreaItemVo 实例,其中包含子实体的ID和名称。
      • 再次调用 searchSon() 方法递归地构建子节点的子节点(即更下一层的城市或区县)。
      • 收集所有子节点到 sonList
  3. 设置子节点:

    • 将收集到的所有子节点列表 sonList 设置为传入的 AreaItemVochildren 属性。

通过这种方式,代码构建了一个完整的地区树形结构,其中每个节点都包含了其子节点的信息,形成了一个多级嵌套的层次结构。

 @Override
public List<AreaItemVo> getAreaTree() {
    ////声明变量
    List<AreaItemVo> areaItemVoList = new ArrayList<>();

    //查询出所有省市区数据
    List<ProvinceCityRegionEntity> provinceCityRegionEntityList = baseMapper.selectList(null);
    //过滤出所有省
    List<ProvinceCityRegionEntity> fatherList = provinceCityRegionEntityList.stream().filter(item -> {
        if (item.getParentId() == 0) {
            return true;
        } else {
            return false;
        }
    }).collect(Collectors.toList());
    for (ProvinceCityRegionEntity father : fatherList) {
        AreaItemVo areaItemVo = new AreaItemVo(father.getId(), father.getName());
        this.searchSon(areaItemVo, provinceCityRegionEntityList);
        areaItemVoList.add(areaItemVo);
    }

    return areaItemVoList;
}

private void searchSon(AreaItemVo father, List<ProvinceCityRegionEntity> provinceCityRegionEntityList) {
    List<AreaItemVo> sonList = provinceCityRegionEntityList.stream().filter(item -> {
        if (item.getParentId() == father.getValue().intValue()) {
            return true;
        } else {
            return false;
        }
    }).map(item1 -> {
        AreaItemVo son = new AreaItemVo(item1.getId(), item1.getName());
        //继续给儿子寻找孙子
        this.searchSon(son, provinceCityRegionEntityList);
        return son;
    }).collect(Collectors.toList());
    father.setChildren(sonList);
}

controller

/**
 * 获取省市区的树形结构数据
 * @return
 */
@GetMapping("/getAreaTree")
public R getAreaTree() {
    List<AreaItemVo> areaItemVoList = provinceCityRegionService.getAreaTree();
    return R.ok().addData("areaItemVoList", areaItemVoList);
}

前端

使用Element UI的级联选择器来显示结果非常之贴切

在这里插入图片描述

<el-form-item label="地区">
  <el-cascader v-model="province_city_area" :options="areaItemVoOptions" clearable></el-cascader>
</el-form-item>

发请求向后端获取数据

//获取省市区的树形结构数据
getAreaTree() {
  provinceCityRegionApi.getAreaTree().then(
    res => {
      this.areaItemVoOptions = res.areaItemVoList
    }
  )
},

当然,直接接收后端的数据还是不行的,会出现如下问题:虽然区的children没有内容,但是还是会显示No data,不太美观 在这里插入图片描述 修正版,如果children没有元素,那就直接设置undefined即可

 //获取省市区的树形结构数据
    getAreaTree() {
      provinceCityRegionApi.getAreaTree().then(
        res => {
          this.areaItemVoOptions = res.areaItemVoList
          for (let i = 0; i < this.areaItemVoOptions.length; i++) {
            this.setNullToUndefined(this.areaItemVoOptions[i])
          }
        }
      )
    },
    //将没有子元素的父类的chidren设置为 undefined
    setNullToUndefined(areaItemVo) {
      if (areaItemVo.children.length < 1) {
        areaItemVo.children = undefined;
      } else {
        for (let i = 0; i < areaItemVo.children.length; i++) {
          this.setNullToUndefined(areaItemVo.children[i])
        }
      }
    }

效果展示

在这里插入图片描述