• 【测试开发】十二、接口测试-实现接口列表功能-递归查询子节点下的接口


    基于 springboot+vue 的测试平台开发继续更新。

    模块树节点的开发暂告一段落,现在开发右边接口相关的部分,今天先完成列表的功能。

    功能是这样,当点击树的某个节点时候,右侧列表展示这个节点下的所有接口,带分页(最终效果图)。

    需要注意的是,因为节点下还有子节点,所以列表的功能需要使用递归来查询。

    一、后端

    1. 建表

    想了一些字段,可能后续还会有些改动,暂时先这样:

    CREATE TABLE `api_definition` (
      `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
      `projectId` bigint NOT NULL COMMENT '所属项目id',
      `name` varchar(255) NOT NULL COMMENT '接口名称',
      `method` varchar(64) NOT NULL COMMENT '请求方法',
      `path` varchar(1000) DEFAULT NULL COMMENT '接口路径',
      `description` longtext COMMENT '接口描述',
      `apiHeader` varchar(255) DEFAULT NULL COMMENT '请求头',
      `request` longtext COMMENT '请求内容 (JSON format)',
      `response` longtext COMMENT '响应内容 (JSON format)',
      `createTime` datetime DEFAULT '1900-01-01 00:00:00' COMMENT '创建时间',
      `updateTime` datetime DEFAULT '1900-01-01 00:00:00' COMMENT '更新时间',
      `createUser` varchar(30) DEFAULT NULL COMMENT '创建人',
      `moduleId` bigint NOT NULL COMMENT '所属模块id',
      `host` varchar(255) DEFAULT NULL COMMENT '接口域名',
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='接口定义表';
    

    2. 列表接口

    (1)实体类 ApiDefinition

    @Data
    @TableName("api_definition")
    public class ApiDefinition {
    
        @TableId(type = IdType.AUTO)
        private Long id;
        private Long projectId;
        private String name;
        private String method;
        private String path;
        private String host;
        private String description;
        private String apiHeader;
        private String request;
        private String response;
        private Long moduleId;
        private String createUser;
        @TableField(fill = FieldFill.INSERT)        // 新增的时候填充数据
        private Date createTime;
        @TableField(fill = FieldFill.INSERT_UPDATE) // 新增或修改的时候填充数据
        private Date updateTime;
    }
    

    (2)DAO层

    @Repository
    public interface ApiDefinitionDAO extends BaseMapper<ApiDefinition> {
    }
    

    (3)Controller 层

    @RestController
    @RequestMapping("apiDefinition")
    public class ApiDefinitionController {
        @Autowired
        ApiDefinitionService apiDefinitionService;
        @GetMapping("/list/{projectId}/{moduleId}/{currentPage}/{pageSize}")
        public Result list(@PathVariable Long projectId,
                           @PathVariable Long moduleId,
                           @PathVariable int currentPage,
                           @PathVariable int pageSize) {
            IPage<ApiDefinition> IPageProject = apiDefinitionService.list(projectId, moduleId, currentPage, pageSize);
            return Result.success(IPageProject);
        }
    }
    

    这里路径有 4 个参数,moduleId 用来查询模块下的所有接口(包含本节点+子节点),后面2个则是分页查询参数。

    (4)Service 层

    在 service 层实现 list 方法,用来查询接口。

    @Service
    public class ApiDefinitionService {
        @Autowired
        ApiDefinitionDAO apiDefinitionDAO;
        @Autowired
        ApiModuleDAO apiModuleDAO;
    
        public IPage<ApiDefinition> list(Long projectId, Long moduleId, int currentPage, int pageSize) {
            // 查询项目id下所有模块
            QueryWrapper<ApiModule> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("projectId", projectId);
            List<ApiModule> apiModules = apiModuleDAO.selectList(queryWrapper);
            // 调用递归查询,childrenIds存放查询到的模块 id
            List<Long> childrenIds = new ArrayList<>();
            List<Long> ids = moduleRecursion(childrenIds, apiModules, moduleId);
            // 添加上入参的模块id
            ids.add(moduleId);
            // 查询模块id下的api
            Page<ApiDefinition> pageApiDefinition = new Page<>(currentPage, pageSize);
    
            QueryWrapper<ApiDefinition> queryApiWrapper = new QueryWrapper<>();
            queryApiWrapper.in("moduleId", ids)
                           .orderByDesc("id");
            return apiDefinitionDAO.selectPage(pageApiDefinition, queryApiWrapper);
        }
    
        private List<Long> moduleRecursion(List<Long> children, List<ApiModule> modules, Long pid) {
            for (ApiModule apiModule : modules) {
                //遍历出父id等于pid,add进子节点集合
                if (apiModule.getParentId().equals(pid)) {
                    // 递归遍历下一级
                    moduleRecursion(children, modules, apiModule.getId());
                    children.add(apiModule.getId());
                }
            }
            return children;
        }
    
    }
    

    list方法中调用递归查询方法moduleRecursion,有3个参数:

    • List<Long> children:用来存放子节点的 id,最后返回出来
    • List<ApiModule> modules:项目id下的模块
    • Long pid:就是当前要查询的模块id

    for 循环遍历项目下的所有模块id,每一层里判断apiModule.getParentId().equals(pid),相等的话继续递归遍历,最后把结果返回。

    list方法拿到之后,还有一步别忘记了,就是入参的这个模块本身,也需要加进去ids.add(moduleId),最后进行分页查询。

    在表里加点测试数据,然后测试下查询接口没问题。

    二、前端

    1. 准备工作

    新建apiDefinition.js文件,存放接口。

    import request from '@/utils/request'
    
    export function getApiListByModuleId(projectId, moduleId, current, size) {
      return request({
        url: `/bloomtest/apiDefinition/list/${projectId}/${moduleId}/${current}/${size}`,
        method: 'get'
      })
    }
    

    接着,去掉之前写死的假数据,变成空数组,从后端接口拿到的数组就放到这。

    2. 请求接口

    组件里有个事件node-click,节点被点击时的回调。

    这里绑定了一个方法getApi,在这个方法里会进行接口请求的操作,来实现这个方法:

    传入 data 是可以获得节点 id 的,可以直接用。

    注意,这里还是需要用到一个中间字段currentNode,本来没有用直接使用 data,后来发现点击分页的时候有bug。

    这是因为 data 是点击左侧树节点的时候才有,所以还是先存起来。

    列表中的这些prop的值注意跟接口返回的字段对应。

    分页的地方,注意下调用的方法即可。

    3. 测试效果

    在表里新建了个数据,点击这个接口关联的模块,列表可以呈现数据。

    4. 发现问题

    问题1

    功能实现了,但是发现了个问题。

    就是当我点击节点上的 添加、编辑等按钮的时候,也会触发这个事件,调用了接口列表的方法。

    但是看在不影响各自功能的使用,先不去管它。

    问题2

    刚才我测试是在项目3下进行的,是可以查出来一条数据。但是当我切换项目到还没数据的项目2下,页面没有刷新,还是呈现的刚才的数据。

    修改方法就是当切换项目的时候,查询出这个项目下的所有接口数据。

    找到下来框的元素,之前已经绑定过一个方法queryModuleList,然后现在再加一个方法,用来查询项目下的接口。

    @change="queryModuleList();initProjectApi()",方法加上括号,2个方法用;隔开。

    实现这个新的方法initProjectApi

    依然是调用列表接口,这里的模块id可以直接传 0,因为所有项目下的模块,顶级的节点id都是 0 。

    测试功能正常。

    --不要用肉体的勤奋,去掩盖思考的懒惰--
  • 相关阅读:
    shell函数
    sed命令
    交互式输入与for语句
    day01_云计算概述及kvm介绍
    grep与正则表达式
    shell的编程原理
    shell的文本处理工具
    shell的基础入门
    深入理解JavaScript中 fn() 和 return fn() 的区别
    一篇笔记带你快速掌握面向对象的Javascript(纯手打)
  • 原文地址:https://www.cnblogs.com/pingguo-softwaretesting/p/15365670.html
Copyright © 2020-2023  润新知