Java后端 || ElementUI 显示后端树形表格数据

发布于:2024-06-30 ⋅ 阅读:(146) ⋅ 点赞:(0)

1、前端源码

ElementUI Table 链接

在此链接中找到 树形数据与懒加载

在这里插入图片描述
查看其JS源码,可知,每个菜单节点的子节点存放于children字段中,

const tableData: User[] = [
  {
    id: 1,
    date: '2016-05-02',
    name: 'wangxiaohu',
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    id: 2,
    date: '2016-05-04',
    name: 'wangxiaohu',
    address: 'No. 189, Grove St, Los Angeles',
  },
  {
    id: 3,
    date: '2016-05-01',
    name: 'wangxiaohu',
    address: 'No. 189, Grove St, Los Angeles',
    children: [
      {
        id: 31,
        date: '2016-05-01',
        name: 'wangxiaohu',
        address: 'No. 189, Grove St, Los Angeles',
      },
      {
        id: 32,
        date: '2016-05-01',
        name: 'wangxiaohu',
        address: 'No. 189, Grove St, Los Angeles',
      },
    ],
  },
  {
    id: 4,
    date: '2016-05-03',
    name: 'wangxiaohu',
    address: 'No. 189, Grove St, Los Angeles',
  },
]

将示例代码复制到项目中,此处根据源码做了符合自己项目的修改,主要复制el-table中的内容

<el-table
        :data="list"
        style="width: 100%; margin-bottom: 20px"
        row-key="id"
        border
        default-expand-all
    >
    <el-table-column prop="title" label="菜单标题" />
    <el-table-column prop="component" label="路由名称" />
    <el-table-column prop="sortValue" label="排序" />
    <el-table-column prop="status" label="状态" #default="scope">
      {{ scope.row.status == 1 ? '正常' : '停用' }}
    </el-table-column>
    <el-table-column prop="createTime" label="创建时间" />

    <el-table-column label="操作" align="center" width="280" #default="scope" >
        <el-button type="success" size="small" @click="addShow(scope.row)">
            添加下级节点
        </el-button>
        <el-button type="primary" size="small" @click="editShow(scope.row)">
            修改
        </el-button>
        <el-button type="danger" size="small" @click="remove(scope.row.id)">
            删除
        </el-button>
    </el-table-column>
  </el-table>

<script setup>
import { ref , onMounted } from "vue"

// 定义表格数据模型
const list = ref([])
//页面表单数据
const defaultForm = {
    id: '',
    parentId: 0,
    title: '',
    url: '',
    component: '',
    icon: '',
    sortValue: 1,
    status: 1,
}

// 钩子函数
onMounted(() => {
    fetchData()
})

const fetchData = async () => {
    const { code, data, message } = await FindNodes()
    list.value = data
}
</script>

前端js配置文件

import request from '@/utils/request'
const api_name = '/admin/system/sysMenu'

export const FindNodes = () => {
    return request({
        url: `${api_name}/findNodes`,
        method: 'get',
    })
}

2、数据库设计

每个菜单有自己的id,还有其父节点的parent_id(用于表示父子关系,双亲表示法)
在这里插入图片描述
给出SQL DDL 注:基于MySQL 8.0.30

CREATE TABLE `sys_menu` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '编号',
  `parent_id` bigint NOT NULL DEFAULT '0' COMMENT '所属上级',
  `title` varchar(20) NOT NULL DEFAULT '' COMMENT '菜单标题',
  `component` varchar(100) DEFAULT NULL COMMENT '组件名称',
  `sort_value` int NOT NULL DEFAULT '1' COMMENT '排序',
  `status` tinyint NOT NULL DEFAULT '1' COMMENT '状态(0:禁止,1:正常)',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标记(0:不可用 1:可用)',
  PRIMARY KEY (`id`),
  KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='菜单表'

3、后端设计

3.1、实体类

这边先把公共的属性抽取出来 组成BaseEntity类,然后将菜单的属性定义在SysMenu类,并继承BaseEntity

// BaseEntity 类

@Data
public class BaseEntity implements Serializable {

    @Schema(description = "唯一标识")
    private Long id;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Schema(description = "创建时间")
    private Date createTime;

    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Schema(description = "修改时间")
    private Date updateTime;

    @Schema(description = "是否删除")
    private Integer isDeleted;

}
// SysMenu 类

@Data
public class SysMenu extends BaseEntity {

	@Schema(description = "父节点id")
	private Long parentId;

	@Schema(description = "节点标题")
	private String title;

	@Schema(description = "组件名称")
	private String component;

	@Schema(description = "排序值")
	private Integer sortValue;

	@Schema(description = "状态(0:禁止,1:正常)")
	private Integer status;

	// 下级列表
	@Schema(description = "子节点")
	private List<SysMenu> children;

}

3.2、Controller层

常规调用,注意"/findNodes"路径与前端js文件中保持一致

// 显示菜单列表方法
@GetMapping("/findNodes")
public Result findNodes(){
    List<SysMenu> sysMenuList = sysMenuService.findNodes();
    return Result.build(sysMenuList, ResultCodeEnum.SUCCESS);
}

3.3、具体树形列表后端代码实现

代码3.1为实现类中的方法,此代码中sysMenuMapper.findAll() 用于查询所有菜单,其SQL如下
select * from sys_menu where is_deleted = 0 order by sort_value

此外,其中的MenuHelper为自定义的一个类,在代码3.2中给出,该类的静态方法buildTree为具体的递归构造树形菜单的方法(该方法的参数为:菜单列表数据)。

buildTree方法调用了递归函数findChildren(该递归函数的参数为:已知的父节点,菜单列表数据),其思路是:已知的父节点为N0,再找出子节点N1,并递归地为N1节点的children属性赋值,然后将N1添加至N0的children中。

代码3.1:

// 递归查找列表
@Override
public List<SysMenu> findNodes() {
    // 1.先查询所有菜单,返回所有list集合
    List<SysMenu> sysMenuList = sysMenuMapper.findAll();
    if (CollectionUtils.isEmpty(sysMenuList)){
        return null;
    }

    // 2.调用工具类中的方法,返回树形数据结构列表
    List<SysMenu> treeList = MenuHelper.buildTree(sysMenuList);
    return treeList;
}

代码3.2:

public class MenuHelper {

    // 递归实现封装
    public static List<SysMenu> buildTree(List<SysMenu> sysMenuList){
        // TODO 完成封装过程
        List<SysMenu> trees = new ArrayList<>();

        for (SysMenu sysMenu : sysMenuList) {
            // 找到递归入口
            if (sysMenu.getParentId().longValue()==0){
                // 根据第一层,找下一层的数据
                trees.add(findChildren(sysMenu, sysMenuList));
            }
        }

        return trees;
    }


    // 返回已经封装好children字段的 菜单节点
    private static SysMenu findChildren(SysMenu sysMenu, List<SysMenu> sysMenuList) {
        // 初始化
        sysMenu.setChildren(new ArrayList<>());

        for (SysMenu menu : sysMenuList) {
            if(menu.getParentId().longValue()==sysMenu.getId().longValue()){
                sysMenu.getChildren().add(findChildren(menu, sysMenuList));
            }
        }

        return sysMenu;
    }
}

最终效果:

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到