zoukankan      html  css  js  c++  java
  • 【测试开发】八、接口测试-后端-模块树列表接口实现,使用HutoolUtil中TreeUtil快速处理树形结构

    国庆节快乐!基于 springboot+vue 的测试平台开发继续更新。

    上次完成了接口定义功能的前端页面,那么后端现在开始逐一实现对应的功能,首先就是提供模块列表接口,这个模块是支持子层级的,所以大概结构是这样:

    [
      {
        id: 1,
        label: '默认',
        children: [
          {
            id: 4,
            label: '二级子模块1',
            children: [
              {
                id: 9,
                label: '三级子模块1'
              }, 
              {
                id: 10,
                label: '三级子模块2'
              }
            ]
          }
        ]
      }, 
      {
        id: 2,
        label: '一级子模块2',
        children: [
          {
            id: 5,
            label: '二级子模块 1'
          }, 
          {
            id: 6,
            label: '二级子模块 2'
          }
        ]
      }
    ]
    

    通常来说,可以写递归代码来找出子层级的数据,然后再进行封装返回出来,比较麻烦。

    后来发现 HutoolUtil 中有个工具类 TreeUtil 可以完成我需求,非常便捷,本次就使用它来实现。

    HutoolUtil 这个框架还是大奇分享给我的,这货是个测试领域资深大佬,它的公众号里更是干活满满。而且最近他在更新基于python语言的web开发知识,不容错过。
    VX搜索【大奇测试开发】即可找到他。

    言归正传,下面来完成接口功能的开发。

    一、引用 HutoolUtil

    Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

    Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;

    Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。

    要使用它直接添加依赖即可:

        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.12</version>
        </dependency>
    

    官方文档:https://www.hutool.cn/docs/#/

    内容很详细,不仅后面的树结构工具,像常用的集合类、JSON、日志、缓存、文件、线程和并发等等应有尽有。

    二、建表

    给模块建一张新表api_module:

    CREATE TABLE `api_module` (
      `id` bigint NOT NULL AUTO_INCREMENT COMMENT 'id',
      `projectId` bigint NOT NULL COMMENT '该节点所属项目id',
      `name` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '节点名称',
      `parentId` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '父节点id',
      `level` int DEFAULT '1' COMMENT '节点层级',
      `createTime` datetime NOT NULL DEFAULT '1900-01-01 00:00:00' COMMENT '创建时间',
      `updateTime` datetime NOT NULL DEFAULT '1900-01-01 00:00:00' COMMENT '更新时间',
      `pos` double DEFAULT NULL COMMENT '节点顺序位置',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='模块表';
    

    重要字段:

    • projectId:与项目进行关联
    • parentId:该节点的父节点,一级目录的父节点我会设置为 0 。
    • level:该节点对应层级,从 1 开始。
    • pos:表示该节点在父节点下的位置顺序。

    三、后端接口实现

    1. Controller 层

    新建 ApiModuleController 类,添加一个处理器方法 getNodeByProjectId,通过项目 ID 查询出下面的所有模块。

    package com.pingguo.bloomtest.controller;
    
    import com.pingguo.bloomtest.common.Result;
    import com.pingguo.bloomtest.service.ApiModuleService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.*;
    
    @RestController
    @RequestMapping("module")
    public class ApiModuleController {
    
        @Autowired
        ApiModuleService apiModuleService;
    
        @GetMapping("/list/{projectId}")
        public Result getNodeByProjectId(@PathVariable Long projectId) {
            return Result.success(apiModuleService.getNodeTreeByProjectId(projectId));
        }
    }
    

    2. DAO层

    dao 层自然也要有。

    package com.pingguo.bloomtest.dao;
    
    import com.baomidou.mybatisplus.core.mapper.BaseMapper;
    import com.pingguo.bloomtest.pojo.ApiModule;
    import org.springframework.stereotype.Repository;
    
    
    @Repository
    public interface ApiModuleDAO extends BaseMapper<ApiModule> {
    }
    

    3. Service 层

    实现 getNodeTreeByProjectId 方法。

        public List<Tree<String>> getNodeTreeByProjectId(Long projectId) {
            this.getDefaultNode(projectId);
            // 根据 projectId 查询所有节点
            QueryWrapper<ApiModule> wrapperApiModule = new QueryWrapper<>();
            List<ApiModule> apiModules = apiModuleDAO.selectList(wrapperApiModule.eq("projectId", projectId));
            // 配置
            TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
            // 自定义属性名 ,即返回列表里对象的字段名
            treeNodeConfig.setIdKey("id");
            treeNodeConfig.setWeightKey("pos");
            treeNodeConfig.setParentIdKey("parentId");
            treeNodeConfig.setChildrenKey("children");
            // 最大递归深度
    //        treeNodeConfig.setDeep(5);
            treeNodeConfig.setNameKey("name");
            //转换器
            List<Tree<String>> treeNodes = TreeUtil.build(apiModules, "0", treeNodeConfig,
                    (treeNode, tree) -> {
                        tree.setId(treeNode.getId().toString());
                        tree.setParentId(treeNode.getParentId().toString());
                        tree.setWeight(treeNode.getPos());
                        tree.setName(treeNode.getName());
                        // 扩展属性 ...
                        tree.putExtra("projectId", treeNode.getProjectId());
                        tree.putExtra("level", treeNode.getLevel());
                        tree.putExtra("label", treeNode.getName());
                        tree.putExtra("createTime", treeNode.getCreateTime());
                        tree.putExtra("updateTime", treeNode.getUpdateTime());
    
                    });
            return treeNodes;
    
        }
    

    这里开头有个方法 getDefaultNode,在这里面会判断当前项目下是否有默认模块,没有则添加默认模块。

        private void getDefaultNode(Long projectId) {
            QueryWrapper<ApiModule> wrapperApiModule = new QueryWrapper<>();
            wrapperApiModule.eq("projectId", projectId)
                            .eq("pos", 1.0);
            // 判断当前项目下是否有默认模块,没有则添加默认模块
            if (apiModuleDAO.selectCount(wrapperApiModule) == 0) {
                ApiModule apiModule = new ApiModule();
                apiModule.setName("默认");
                apiModule.setPos(1.0);
                apiModule.setLevel(1);
                apiModule.setParentId(0L);
                apiModule.setCreateTime(new Date());
                apiModule.setUpdateTime(new Date());
                apiModule.setProjectId(projectId);
                apiModuleDAO.insert(apiModule);
            }
        }
    

    然后通过 项目id 把项目下所有的数据查询出来:

    接下来使用 TreeUtil 来完成树结构处理。

    首先,创建一个配置类 TreeNodeConfig 对象,在这个对象里设置属性,对应的就是返回出来的字段名。

    还可以设置最大递归深度,也可以不设。我测试之后就注释掉了,先不加限制。

    最后就是构建树结构 treeNodes,完成处理后返回给 controller 层。

    因为我要返回的还有其他的字段,可以使用tree.putExtra来添加要返回的其他字段,比如:

    tree.putExtra("projectId", treeNode.getProjectId());
    

    第一个参数是定义的字段名称,第二个参数就是使用这个结点的 get 方法获取对应的属性值。

    最后返回到上层的是List<Tree<String>>类型,可以直接塞到统一结果里去返回。

    四、测试一下

    1. 测试结构数据

    测试一下接口,先手动网表里插入了对应结构的数据。

    请求接口,传入 projectId 为 3。

    {
        "code": 20000,
        "message": "成功",
        "data": [
            {
                "id": "9",
                "parentId": "0",
                "pos": 1.0,
                "name": "默认",
                "projectId": 3,
                "level": 1,
                "label": "默认",
                "createTime": "2021-09-29 10:50:00",
                "updateTime": "2021-09-29 10:50:00",
                "children": [
                    {
                        "id": "14",
                        "parentId": "9",
                        "pos": 1.0,
                        "name": "默认-2",
                        "projectId": 3,
                        "level": 2,
                        "label": "默认-2",
                        "createTime": "1900-01-01 08:00:00",
                        "updateTime": "1900-01-01 08:00:00"
                    },
                    {
                        "id": "10",
                        "parentId": "9",
                        "pos": 1.0,
                        "name": "默认-1",
                        "projectId": 3,
                        "level": 2,
                        "label": "默认-1",
                        "createTime": "2021-10-01 08:00:00",
                        "updateTime": "1900-01-01 08:00:00",
                        "children": [
                            {
                                "id": "11",
                                "parentId": "10",
                                "pos": 1.0,
                                "name": "默认-1-1",
                                "projectId": 3,
                                "level": 3,
                                "label": "默认-1-1",
                                "createTime": "1900-01-01 08:00:00",
                                "updateTime": "1900-01-01 08:00:00",
                                "children": [
                                    {
                                        "id": "12",
                                        "parentId": "11",
                                        "pos": 1.0,
                                        "name": "默认-1-1-1",
                                        "projectId": 3,
                                        "level": 4,
                                        "label": "默认-1-1-1",
                                        "createTime": "1900-01-01 08:00:00",
                                        "updateTime": "1900-01-01 08:00:00",
                                        "children": [
                                            {
                                                "id": "13",
                                                "parentId": "12",
                                                "pos": 1.0,
                                                "name": "默认-1-1-1-1",
                                                "projectId": 3,
                                                "level": 5,
                                                "label": "默认-1-1-1-1",
                                                "createTime": "1900-01-01 08:00:00",
                                                "updateTime": "1900-01-01 08:00:00"
                                            }
                                        ]
                                    }
                                ]
                            }
                        ]
                    }
                ]
            }
        ]
    }
    

    结果正确。

    2. 测试新增默认

    传入一个 projectId 为 4 ,localhost:8080/bloomtest/module/list/4

    {
        "code": 20000,
        "message": "成功",
        "data": [
            {
                "id": "15",
                "parentId": "0",
                "pos": 1.0,
                "name": "默认",
                "projectId": 4,
                "level": 1,
                "label": "默认",
                "createTime": "2021-10-01 12:25:54",
                "updateTime": "2021-10-01 12:25:54"
            }
        ]
    }
    

    返回正确。

    落库正常。

    --不要用肉体的勤奋,去掩盖思考的懒惰--
  • 相关阅读:
    ASCII码对照表
    createPopup 超链接
    说说回车键触发表单提交的问题
    linux下配java环境的小结
    spring bind checkbox 传递值问题
    用Common validator为springMVC做验证时遇到的一个问题小记
    [转载]对android LinearLayout中layout_weight属性使用初探
    linux下tomcat启动正常,但用http://22.22.33.33:8080却访问不了,防火墙的设置问题
    Java 遍历Map时 删除元素
    ftp用户登录时不能进自己的目录,被拒绝登录的解决方法
  • 原文地址:https://www.cnblogs.com/pingguo-softwaretesting/p/15341673.html
Copyright © 2011-2022 走看看