springboot+mybatisplus+layui+restful实现dtree树形结构显示,以左右两侧传值显示

简介: springboot+mybatisplus+layui+restful实现dtree树形结构显示,以左右两侧传值显示

1.首先我们看一下layui中的dtree组件的json格式,我才用简单的json封装,也就是list风格的json。格式如下:


{
"status":{"code":200,"message":"操作成功"},
"data": [
  {"id":"001","title": "湖南省","checkArr": "0","parentId": "0"},
  {"id":"002","title": "湖北省","checkArr": "0","parentId": "0"},
  {"id":"003","title": "广东省","checkArr": "0","parentId": "0"},
  {"id":"004","title": "浙江省","checkArr": "0","parentId": "0"},
  {"id":"005","title": "福建省","checkArr": "0","parentId": "0"},
  {"id":"001001","title": "长沙市","checkArr": "0","parentId": "001"},
  {"id":"001002","title": "株洲市","checkArr": "0","parentId": "001"},
  {"id":"001003","title": "湘潭市","checkArr": "0","parentId": "001"},
  {"id":"001004","title": "衡阳市","checkArr": "0","parentId": "001"},
  {"id":"001005","title": "郴州市","checkArr": "0","iconClass": "dtree-icon-caidan_xunzhang","parentId": "001"}
]
}


2.TreeNode.java 对树中结构的数据的封装


@Data
@AllArgsConstructor
@NoArgsConstructor
public class TreeNode {
    private Integer id;//自己的id
    @JsonProperty("parentId") //返回的json的名称 parentId ,为了确定层级关系
    private Integer pid;
    private String title;//名称
    private String icon;
    private String href;
    private Boolean spread;//是否展开
    private List<TreeNode> children = new ArrayList<TreeNode>();
    /**
     * 0为不选中  1为选中
     */
    private String checkArr="0";
    /**
     * 部门 dtree的构造器,我们只用到了这四个
     * @param id id
     * @param pid 父亲parentId
     * @param title 名称
     * @param spread 是否展开
     */
    public TreeNode(Integer id, Integer pid, String title, Boolean spread) {
        this.id = id;
        this.pid = pid;
        this.title = title;
        this.spread = spread;
    }
}



3.sql,我们看一下数据库文件的结构


DROP TABLE IF EXISTS `sys_dept`;
CREATE TABLE `sys_dept` (
  `id` int(11) NOT NULL AUTO_INCREMENT, #只用到了它
  `pid` int(11) DEFAULT NULL, #只用到了它
  `name` varchar(255) DEFAULT NULL, #只用到了它
  `open` int(11) DEFAULT NULL, #只用到了它
  `remark` varchar(255) DEFAULT NULL,
  `address` varchar(255) DEFAULT NULL,
  `available` int(11) DEFAULT NULL COMMENT '状态【0不可用1可用】',
  `ordernum` int(11) DEFAULT NULL COMMENT '排序码【为了调试显示顺序】',
  `createtime` datetime DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;


4.DataGridView.java用来返回前台json数据的实体


@Data
@AllArgsConstructor
@NoArgsConstructor
public class DataGridView {
    private Integer code = 0;
    private String msg = "";
    private Long count = 0L;
    private Object data; //这里是dtree中部门的数据
    public DataGridView(Long count, Object data) {
        this.count = count;
        this.data = data;
    }
    public DataGridView(Object data) {
        this.data = data;
    }
}


5.Dept.java


@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@TableName("sys_dept")
@ToString
public class Dept implements Serializable {
    private static final long serialVersionUID=1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    private Integer pid;
    private String name;
    /**
     * 是否展开,0不展开,1展开
     */
    private Integer open;
    private String remark;
    private String address;
    /**
     * 是否可用,0不可用,1可用
     */
    private Integer available;
    /**
     * 排序码
     */
    private Integer ordernum;
    private Date createtime;
}


6.DeptController.java


@RestController
@RequestMapping("/dept")
public class DeptController {
    @Autowired
    private DeptService deptService;
    /**
     * 加载部门左边的菜单树json
     * @param
     * @return
     */
    @RequestMapping("/loadDeptManagerLeftTreeJson")
    public DataGridView loadManagerLeftTreeJson(){
        //查询出所有的部门,存放进list中
        List<Dept> list = deptService.list();
        List<TreeNode> treeNodes = new ArrayList<>();
        //将部门放入treeNodes中,组装成json
        for (Dept dept : list) {
            Boolean open = dept.getOpen() == 1?true:false;
            treeNodes.add(new TreeNode(dept.getId(),dept.getPid(),dept.getName(),open));
        }
        //返回树的Json实体,装着树,树中有部门数据
        return new DataGridView(treeNodes);
    }
}


7.DeptService.java


public interface DeptService extends IService<Dept> {
}


8.DeptServiceImpl.java


@Service
@Transactional
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements DeptService {
}


9.DeptMapper.java


1. public interface DeptMapper extends BaseMapper<Dept> {
2. }


10.父页面,用来分开里面的树结构和右侧内容


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>部门管理</title>
</head>
<!--左右两侧-->
<frameset cols="220,*" border="2" frameborder="yes">
    <frame th:src="@{/sys/toDeptLeft}" name="left">
    <frame th:src="@{/sys/toDeptRight}" name="right">
</frameset>
</html>


11.Left 树页面


<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>left</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta http-equiv="Access-Control-Allow-Origin" content="*">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <link rel="icon" href="/resources/favicon.ico">
    <link rel="stylesheet" href="resources/layui/css/layui.css" th:href="@{/resources/layui/css/layui.css}" media="all"/>
    <link rel="stylesheet" th:href="@{/resources/css/public.css}" media="all"/>
    <link rel="stylesheet" th:href="@{/resources/layui_ext/dtree/dtree.css}" media="all"/>
    <link rel="stylesheet" th:href="@{/resources/layui_ext/dtree/font/dtreefont.css}" media="all"/>
</head>
<body>
<!--存放树的容器开始-->
<ul id="deptTree" class="dtree" data-id="0"></ul>
<!--存放树的容器结束-->
<script type="text/javascript" th:src="@{/resources/layui/layui.js}"></script>
<script type="text/javascript" th:src="@{/resources/layui_ext/dtree/dtree.js}"></script>
<script type="text/javascript">
    var deptTree;
    layui.extend({
        dtree: '/resources/layui_ext/dtree/dtree'   // {/}的意思即代表采用自有路径,即不跟随 base 路径
    }).use(['dtree','layer','jquery'], function(){
        var dtree = layui.dtree;
        var layer = layui.layer;
        var $ = layui.jquery;
        // 初始化树
        deptTree = dtree.render({
            elem: "#deptTree",
            dataStyle: "layuiStyle", //使用layui风格的数据格式
            dataFormat: "list",     //配置data的风格为list,这里是简单的json格式
            response:{message:"msg",statusCode:0},  //修改response中返回数据的定义
            url: "/dept/loadDeptManagerLeftTreeJson" // 使用url加载(可与data加载同时存在)
        });
        // 绑定节点点击事件
        dtree.on("node('deptTree')" ,function(obj){
            //将树节点的id传到reloadTable方法中
            window.parent.right.reloadTable(obj.param.nodeId);
        });
    });
</script>
</body>
</html>


12.Right 右侧显示部门具体信息的页面【不做详细,只展示如何拿到左侧部门的ID】


<script type="text/javascript" th:src="@{/resources/layui/layui.js}"></script>
<script type="text/javascript">
    //提升数据表格的作用域,因为底下还有一个reloadTable方法
    var tableIns;
    layui.extend({
        dtree: '/resources/layui_ext/dtree/dtree'
    }).use(['jquery', 'form', 'layer', 'laydate', 'table', 'layedit','dtree'], function () {
        var $ = layui.jquery;
        var form = layui.form;
        var layer = layui.layer;
        var table = layui.table;
        var dtree = layui.dtree;
        //初始化表格 加载数据
        tableIns = table.render({
            elem: "#deptTable",
            title: "部门数据表格",
            url: "/dept/loadAllDept",
            toolbar: "#deptToolBar",
            page: true,
            height: "full-180",
            cols: [ [
                {field: 'id', title: 'ID', align: 'center',width:'50'},
                {field: 'pid', title: '父级部门ID', align: 'center',width:'100'},
                {field: 'name', title: '部门名称', align: 'center',width:'150'},
                {field: 'remark', title: '部门备注', align: 'center',width:'150'},
                {field: 'address', title: '部门地址', align: 'center',width:'100'},
                {field: 'available', title: '是否可用', align: 'center',width:'100',templet:function (d) {
                    return d.available==1?'<font color="blue">可用</font>':'<font color="red">不可用</font>';
                }},
                {field: 'open', title: '是否展开', align: 'center',width:'100',templet:function (d) {
                    return d.open==1?'<font color="blue">展开</font>':'<font color="red">不展开</font>';
                }},
                {field: 'ordernum', title: '排序码', align: 'center',width:'80'},
                {field: 'createtime', title: '部门创建时间', align: 'center',width:'160'},
                {fixed: 'right', title: '操作', toolbar: '#deptRowBar', align: 'center',width:'180'}
            ] ],
            done: function (data, curr, count) {
                //不是第一页时,如果当前返回的数据为0那么就返回上一页
                if (data.data.length == 0 && curr != 1) {
                    tableIns.reload({
                        page: {
                            curr: curr - 1
                        }
                    })
                }
            }
        });
        //监控模糊查询按钮事件
        form.on("submit(doSearch)", function (data) {
            tableIns.reload({
                where: data.field,
                page: {
                    curr: 1
                }
            });
            return false;
        });
        //监控工具条事件
        table.on("toolbar(deptTable)", function (obj) {
            switch (obj.event) {
                case 'add':
                    openAddLayer();
                    break;
            };
        });
        //监控行工具条事件
        table.on("tool(deptTable)", function (obj) {
            //获取当前行数据
            var data = obj.data;
            switch (obj.event) {
                case 'delete':
                    deleteDept(data);
                    break;
                case 'update':
                    updateDept(data);
                    break;
            };
        });
        var mainIndex;
        var url;
        //打开添加弹出层
        function openAddLayer() {
            mainIndex = layer.open({
                type:1,
                content:$("#addOrUpdateDiv"),
                area:['800px','500px'],
                title:'添加部门',
                success:function () {
                    $("#dataFrm")[0].reset();
                    //设置下拉树中父节点的值为空
                    $("#pid").val("");
                    url="/dept/addDept";
                    //初始化排序码
                    $.get("/dept/loadDeptMaxOrderNum",function (res) {
                        $("#ordernum").val(res.value);
                    });
                    //设置下拉树的value值为空
                    selectTree.selectVal("");
                }
            });
        }
        //打开修改的弹出层
        function updateDept(data) {
            mainIndex = layer.open({
                type:1,
                content:$("#addOrUpdateDiv"),
                area:['800px','500px'],
                title:'修改部门',
                success:function () {
                    //清空原有的数据
                    $("#dataFrm")[0].reset();
                    //装载新的数据
                    form.val("dataFrm",data);
                    //选中之前的父级部门  nodeId=data.pid
                    dtree.dataInit("deptTree",data.pid);
                    dtree.selectVal("deptTree");
                    url="/dept/updateDept";
                }
            });
        }
        form.on("submit(doSubmit)",function (data) {
            $.post(url,data.field,function (res) {
                if (res.code==200){
                    tableIns.reload();
                    //重新加载添加弹出层的下拉树
                    selectTree.reload();
                    //重新加载左边的部门树
                    window.parent.left.deptTree.reload();
                }
                layer.msg(res.msg);
                layer.close(mainIndex);
            });
            return false;
        });
        /*$("#doSubmit").click(function () {
            var data = $("#dataFrm").serialize();
            $.post(url,data,function (res) {
                if (res.code==200){
                    tableIns.reload();
                    //重新加载添加弹出层的下拉树
                    selectTree.reload();
                    //重新加载左边的部门树
                    window.parent.left.deptTree.reload();
                }
                layer.msg(res.msg);
                layer.close(mainIndex);
            });
        });*/
        //删除
        function deleteDept(data) {
            $.post("/dept/checkDeptHasChildrenNode", {id: data.id}, function (resoult) {
                if (resoult.value){
                    layer.msg("当前部门节点有子部门,请选择删除子部门!")
                }else {
                    layer.confirm('你确定要删除【' + data.name + '】这个部门吗?', {icon: 3, title: '提示'}, function (index) {
                        $.post("/dept/deleteDept", {id: data.id},function (res) {
                            if (res.code == 200) {
                                tableIns.reload({
                                    where:"",
                                });
                                //刷新下拉树
                                selectTree.reload();
                                //刷新左边的部门树
                                window.parent.left.deptTree.reload();
                            }
                            layer.msg(res.msg);
                        });
                        layer.close(index);
                    });
                }
            });
        }
        //初始化下拉树
        var selectTree = dtree.renderSelect({
            elem: "#deptTree",
            width: "100%", // 可以在这里指定树的宽度来填满div
            dataStyle: "layuiStyle", //使用layui风格的数据格式
            dataFormat: "list",     //配置data的风格为list
            response:{message:"msg",statusCode:0},  //修改response中返回数据的定义
            url: "/dept/loadDeptManagerLeftTreeJson" // 使用url加载(可与data加载同时存在)
        });
        //监听点击的方法
        dtree.on("node(deptTree)",function (obj) {
            $("#pid").val(obj.param.nodeId);
            console.log(obj.param.nodeId);
        })
    });
    //拿到右侧页面接受id,并传给后台,给其它页面刷新当前页面数据表格的方法
    function reloadTable(id) {
        tableIns.reload({
            where:{
                id:id
            },
            page:{
                curr:1
            }
        });
    }
</script>


目录
相关文章
|
3月前
|
Java API 数据库
构建RESTful API已经成为现代Web开发的标准做法之一。Spring Boot框架因其简洁的配置、快速的启动特性及丰富的功能集而备受开发者青睐。
【10月更文挑战第11天】本文介绍如何使用Spring Boot构建在线图书管理系统的RESTful API。通过创建Spring Boot项目,定义`Book`实体类、`BookRepository`接口和`BookService`服务类,最后实现`BookController`控制器来处理HTTP请求,展示了从基础环境搭建到API测试的完整过程。
66 4
|
3月前
|
Java API 数据库
如何使用Spring Boot构建RESTful API,以在线图书管理系统为例
【10月更文挑战第9天】本文介绍了如何使用Spring Boot构建RESTful API,以在线图书管理系统为例,从项目搭建、实体类定义、数据访问层创建、业务逻辑处理到RESTful API的实现,详细展示了每个步骤。通过Spring Boot的简洁配置和强大功能,开发者可以高效地开发出功能完备、易于维护的Web应用。
97 3
|
13天前
|
SQL JavaScript Java
Spring Boot 3 整合 Mybatis-Plus 实现数据权限控制
本文介绍了如何在Spring Boot 3中整合MyBatis-Plus实现数据权限控制,通过使用MyBatis-Plus提供的`DataPermissionInterceptor`插件,在不破坏原有代码结构的基础上实现了细粒度的数据访问控制。文中详细描述了自定义注解`DataScope`的使用方法、`DataPermissionHandler`的具体实现逻辑,以及根据用户的不同角色和部门动态添加SQL片段来限制查询结果。此外,还展示了基于Spring Boot 3和Vue 3构建的前后端分离快速开发框架的实际应用案例,包括项目的核心功能模块如用户管理、角色管理等,并提供Gitee上的开源仓库
117 11
|
3月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
784 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
3月前
|
Java 数据库连接 API
springBoot:后端解决跨域&Mybatis-Plus&SwaggerUI&代码生成器 (四)
本文介绍了后端解决跨域问题的方法及Mybatis-Plus的配置与使用。首先通过创建`CorsConfig`类并设置相关参数来实现跨域请求处理。接着,详细描述了如何引入Mybatis-Plus插件,包括配置`MybatisPlusConfig`类、定义Mapper接口以及Service层。此外,还展示了如何配置分页查询功能,并引入SwaggerUI进行API文档生成。最后,提供了代码生成器的配置示例,帮助快速生成项目所需的基础代码。
257 1
|
3月前
|
Java 数据库连接 mybatis
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
该文档详细介绍了如何在Springboot Web项目中整合Mybatis,包括添加依赖、使用`@MapperScan`注解配置包扫描路径等步骤。若未使用`@MapperScan`,系统会自动扫描加了`@Mapper`注解的接口;若使用了`@MapperScan`,则按指定路径扫描。文档还深入分析了相关源码,解释了不同情况下的扫描逻辑与优先级,帮助理解Mybatis在Springboot项目中的自动配置机制。
228 0
Springboot整合Mybatis,MybatisPlus源码分析,自动装配实现包扫描源码
|
4月前
|
XML Java 关系型数据库
springboot 集成 mybatis-plus 代码生成器
本文介绍了如何在Spring Boot项目中集成MyBatis-Plus代码生成器,包括导入相关依赖坐标、配置快速代码生成器以及自定义代码生成器模板的步骤和代码示例,旨在提高开发效率,快速生成Entity、Mapper、Mapper XML、Service、Controller等代码。
springboot 集成 mybatis-plus 代码生成器
|
3月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 实现动态路由和菜单功能,快速搭建前后端分离的应用框架。首先,确保开发环境已安装必要的工具,然后创建并配置 Spring Boot 项目,包括添加依赖和配置 Spring Security。接着,创建后端 API 和前端项目,配置动态路由和菜单。最后,运行项目并分享实践心得,包括版本兼容性、安全性、性能调优等方面。
217 1
|
2月前
|
JavaScript 安全 Java
如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。
本文介绍了如何使用 Spring Boot 和 Ant Design Pro Vue 构建一个具有动态路由和菜单功能的前后端分离应用。首先,创建并配置 Spring Boot 项目,实现后端 API;然后,使用 Ant Design Pro Vue 创建前端项目,配置动态路由和菜单。通过具体案例,展示了如何快速搭建高效、易维护的项目框架。
145 62
|
1月前
|
存储 JavaScript 前端开发
基于 SpringBoot 和 Vue 开发校园点餐订餐外卖跑腿Java源码
一个非常实用的校园外卖系统,基于 SpringBoot 和 Vue 的开发。这一系统源于黑马的外卖案例项目 经过站长的进一步改进和优化,提供了更丰富的功能和更高的可用性。 这个项目的架构设计非常有趣。虽然它采用了SpringBoot和Vue的组合,但并不是一个完全分离的项目。 前端视图通过JS的方式引入了Vue和Element UI,既能利用Vue的快速开发优势,
130 13