测试开发【Mock平台】05开发:项目管理功能(一)后端接口

112 阅读8分钟

在这里插入图片描述

【Mock平台】为系列测试开发教程,从0到1编码带你一步步使用Spring Boot 和 Antd React
框架完成搭建一个测试工具平台,希望作为一个实战项目能为你的测试开发学习有帮助。

概要引导

从这篇要开始和大家分享需求实现了,项目管理是基础功能也是比较简单的结构,我们先从简单入手,多花几篇把前后端用到的讲到说明白,夯牢基石才能在后边游刃有余,这里还是要强调一点,此系列是要求对JAVA有基础,以及了解些前端的一些知识,否则跟下来还是有一定难度的,但如果读者比较多想先学些基础,可以留言根据人数看看是否需要开个JAVA基础系列。

回归Mock需求开发,之前的PRD文档给出了项目管理的需求说明,贴下原型图,具体参考头篇文章《Mock01-开篇:平台原型和需求说明》本节重点后端接口实现,有大量源代码,强烈建议使用电脑浏览学习。
在这里插入图片描述

需求实现

项目管理表

首先设计所需的项目管理表,表名定义为 mock_project 结构如下表,需要在qmock 数据库中将数据表创建好。

字段类型必填说明
mp_idint自增ID
mp_namevarchar项目名称
mp_typevarchar项目属性 公开-public(默认) ,私有-private
mp_descvarchar项目更多描述信息 500以内字符
mp_ownervarchar项目负责人(联系人)
mp_create_uservarchar创建人
mp_update_uservarchar修改人
mp_create_datedatetime创建时间,默认CURRENT_TIMESTAMP
mp_update_datedatetime修改时间,随修改自动修改

后端接口

从项目管理需求上来讲,后端暂需要实现如下接口

  • 条件查询接口,返回项目信息列表
  • 项目新增和修改接口,此处合并成一个保存接口

按照之前一篇springboot resful api的实现步骤,来回顾和优化顺序

  1. 创建数据库对应的Entity 字段实体类
  2. 创建对应接口请求request实体类,按需或者共用entity
  3. 创建Mapper数据库接口类,并在此类中实现SQL语句,或者通过xml映射
  4. 创建Service服务接口及实现类,做逻辑业务逻辑处理
  5. 创建Controller接口类,实现接口定定义

给出一张截图,主观的先展示下后端新增的代码(红色),修改的部分文件(蓝色)文件。
在这里插入图片描述
接下来一次给出实现的代码,其中有新的内容我会给出必要的讲解

Part1 对应数据库表的实体类 MockProjectEntity 创建修改人和日期基础字段集成BaseEntity,其中字段对应的getter和setter使用Lombok实现。


import lombok.Data;

@Data
public class MockProjectEntity extends BaseEntity{
    // 自增ID编号
    private Integer id;
    
    // 项目名称
    private String name;
    
    // 项目类型 public 或 private
    private String type;
    
    // 项目描述
    private String desc;
    
    // 项目管理人或者负责人
    private String owner;
}

Part2 项目的保存操作需要一个请求body实体类 MockProjectRequest,其中时间信息不需要,创建人修改统一通过operator 透传。

@Data
public class MockProjectRequest {
    // 项目ID
    private Integer id;

    // 项目名称
    @NotBlank(message = "项目名称不能为空")
    private String name;

    // 项目描述
    private String desc;

    // 项目负责人
    private String owner;

    // 项目属性 public-公开,private-私有
    private String type;

    // 操作人
    private String operator;
}

Part3 编写数据操作接口类 MockProjectMapper ,直接使用mybatis中的注解方式进行查询、插入和修改语句操作,使用这些注解需要导入 import org.apache.ibatis.annotations.*;
在这里插入图片描述
为了实现前端一些演示交互和服务类的必要逻辑,数据操作分别实现如下几个方法

  • selectMockProject 全量查询方法,上一篇讲过自动下划线自动转驼峰,这里从上Entity和Request实体类看到,并不符合这个规则,所以新的注解@Results作用可以实现数据表字段和自定义实体类字段匹配。
  • searchMockProject 根据名称模糊查询方法
  • insertProject 项目插入方法
  • updateProject 项目根据id修改方法

除了截图中看到的方法其他代码实现如下

/**
     * @param name
     * @return List<MockProjectEntity>
     * @desc 数据库项目表,根据id查询project详细信息
     */
    @Select("SELECT * FROM mock_project WHERE mp_name LIKE CONCAT(CONCAT('%',#{name},'%'))")
    @ResultMap("projectMap")
    List<MockProjectEntity> searchMockProject(String name);


    /**
     * @param projectEntity
     * @return 影响数量 插入成功默认1
     * @desc 项目插入SQL
     */
    @Insert({"INSERT INTO mock_project (mp_name,mp_desc,mp_type,mp_owner,mp_create_user,mp_create_date) VALUES ( #{name},#{desc},#{type},#{owner},#{createUser},NOW())"})
    @ResultMap("projectMap")
    int insertProject(MockProjectEntity projectEntity);


    /**
     * 项目修改SQL
     * @param projectEntity
     * @return 影响数量 更新成功默认1
     */
    @Update({"UPDATE mock_project SET mp_name=#{name},mp_desc=#{desc},mp_type=#{type},mp_owner=#{owner},mp_update_user=#{updateUser},mp_update_date=NOW() WHERE mp_id=#{id}"})
    @ResultMap("projectMap")
    int updateProject(MockProjectEntity projectEntity);

扩展说明:@Results无需每个方法重复添加,一般只需要一个方法上定好id名,其他方法上引用即可,关于内部value Result的更多属性定义,可以在IDE中点击跳转查看

/**
 * The annotation that specify a mapping definition for the property.
 *
 * @see Results
 * @author Clinton Begin
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(Results.class)
public @interface Result {
  /**
   * Returns whether id column or not.
   * @return {@code true} if id column; {@code false} if otherwise
   */
  boolean id() default false;

  /**
   * Return the column name(or column label) to map to this argument.
   * @return the column name(or column label)
   */
  String column() default "";

  /**
   * Returns the property name for applying this mapping.
   * @return the property name
   */
  String property() default "";

  /**
   * Return the java type for this argument.
   * @return the java type
   */
  Class<?> javaType() default void.class;

  /**
   * Return the jdbc type for column that map to this argument.
   * @return the jdbc type
   */
  JdbcType jdbcType() default JdbcType.UNDEFINED;

  /**
   * Returns the {@link TypeHandler} type for retrieving a column value from result set.
   * @return the {@link TypeHandler} type
   */
  Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;

  /**
   * Returns the mapping definition for single relationship.
   * @return the mapping definition for single relationship
   */
  One one() default @One;

  /**
   * Returns the mapping definition for collection relationship.
   * @return the mapping definition for collection relationship
   */
  Many many() default @Many;
}

Part4 编写服务类,包括两个一个是接口类,只有方法名和返回值,这其中涉及的java的基础知识,如果还不知道这些,最好去花个两天的时间补充下基础知识,或者留言给我,我单独开个java基础系列分享。

public interface MockProjectService {

    RespResult selectMockProjectList();

    RespResult searchMockProject(String name, int current, int pageSize);

    RespResult saveMockProject(MockProjectRequest mockProject);
}

另一个是实现类,这里再次强调的重点是@Autowired自动注解,是实现标记类在有需要的时候的自动声明,也可以使用@Resource替代,这块的知识点如果要弄明白原理有点复杂,随着系列分享的递进,我专门弄的扩展篇讲解下,这里还是先习惯和熟练它的用法。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("MockProjectService")
public class MockProjectServiceImpl implements MockProjectService {

    @Autowired
    MockProjectMapper mockProjectMapper;

    /***
     * 获取项目列表
     * @return Resp
     */
    @Override
    public RespResult selectMockProjectList() {
        List<MockProjectEntity> mockProjectEntityList= mockProjectMapper.selectMockProject();
        return RespResult.success(mockProjectEntityList);
    }

    /**
     * 根据搜索条件搜索项目List
     * name为空的时候按全部条件搜索
     * @param name
     * @return
     */
    @Override
    public RespResult searchMockProject(String name, int current, int pageSize) {
        List<MockProjectEntity> mockProjectEntityList;
        
        // 分页 https://pagehelper.github.io/docs/howtouse/ 使用文档
        PageHelper.startPage(current, pageSize);

        if (name.isEmpty()){
            mockProjectEntityList = mockProjectMapper.selectMockProject();
        } else{
            mockProjectEntityList = mockProjectMapper.searchMockProject(name);
        }

        PageInfo pageData = new PageInfo(mockProjectEntityList);
        return RespResult.success(pageData);
    }

    /**
     * 项目添加和保存实现
     * @param mockProject
     * @return
     */
    public RespResult saveMockProject(MockProjectRequest mockProject) {
        MockProjectEntity mockProjectEntity = new MockProjectEntity();
        mockProjectEntity.setName(mockProject.getName());
        mockProjectEntity.setDesc(mockProject.getDesc());
        mockProjectEntity.setType(mockProject.getType());
        mockProjectEntity.setOwner(mockProject.getOwner());

        if(mockProject.getId() == null){
            mockProjectEntity.setCreateUser(mockProject.getOperator());
            mockProjectMapper.insertProject(mockProjectEntity);
        }
        else {
            mockProjectEntity.setId(mockProject.getId());
            mockProjectEntity.setUpdateUser(mockProject.getOperator());
            mockProjectMapper.updateProject(mockProjectEntity);
        }

        return RespResult.success();
    }
}

在代码中saveMockProject服务方法是根据是否传了ID,将增加和修改合并处理了。

插一个新知识点:分页查询PageHelper[1] 的使用
在之前的系列python做数据查询的分页的时候,通过控制sql语句用limit实现的,在JAVA 使用Mybatis框架中有pagehelper 插件可以帮助其快速实现分页,它支持很多方法,上边代码也是官方比较推荐的第二种方法 ,Mapper接口方式的调用,即在执行mapper查询语句前加 PageHelper.startPage() PageHelper.offsetPage()更多方法,也找个时机单独研究下分享给大家。

最后要使用这个插件时候需要在pom.xml添加依赖

<dependency>
  <groupId>com.github.pagehelper</groupId>
  <artifactId>pagehelper-spring-boot-starter</artifactId>
  <version>1.4.2</version>
</dependency>

以及优化 RespResult 增加了个多重结构方法,处理分页对象数据的格式化返回

// 分页数据成功响应
public static RespResult success(PageInfo pageData) {
    RespResult respResult = new RespResult();
    respResult.setResultCode(RespCode.SUCCESS);
    respResult.setData(pageData.getList());
    respResult.setTotal(pageData.getTotal());
    return respResult;
}

Part5 接口实现,到了最后一步MockProjectController真正接口的控制类实现,以上是笔者个人习惯从里到外层的顺序写法,也有些比较习惯先从这层写开始,按照接口需要逐层按照方法往下写。

@RestController
@RequestMapping("/api/mock/")
public class MockProjectController {

    @Autowired
    private MockProjectService mockProjectService;

    @GetMapping(value = "/project/list")
    public RespResult getProjectList() {
        return mockProjectService.selectMockProjectList();
    }

    @RequestMapping(value = "/project/search", method = RequestMethod.GET)
    public RespResult searchProject(@RequestParam(value = "name") String name, int current, int pageSize) {
        return mockProjectService.searchMockProject(name, current, pageSize);
    }

    /***
     * 项目增加保存类
     * @param mockProject
     * @return
     */
    @PostMapping(value = "/project/save")
    public RespResult saveProject(@RequestBody MockProjectRequest mockProject) {
        try {
            return mockProjectService.saveMockProject(mockProject);
        }catch (Exception e){
            System.out.println(e);
        }
        return RespResult.failure(RespCode.SYSTEM_ERROR);
    }
}

以上所有罗列的说明和代码就构成了,项目管理功能所需要接口服务的后端代码,开发完最后还有一项非常重要的事情要做就是进行测试,接口功能测试应该是测试人员最强的部分,用例就详细罗列了,直接给出笔者某接口的测试结果,以示接口服务的正常。
在这里插入图片描述

本篇代码量有点多,一口气的实现项目管理的需要的全部接口,大家可以先编写实现,熟悉这个套路为主,如果有余力可以先查询资料理解下强调的新知识点。接下来会有2篇左右来实现前端交互,也可到攒到那时根据用到接口按需编码。

遇到的报错问题解决

后端在参照之前项目添加pagehelper依赖的时候报了个循环依赖错误,心如如下:

Description:

The dependencies of some of the beans in the application context form a cycle:

┌──->──┐
|  com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration
└──<-──┘

经过排查和搜索,此问题为版本依赖冲突引起的,如图所示在对maven依赖进行分析的时候有一条红线表示有冲突,并且在右侧以来包列表中也可以看到。
在这里插入图片描述
这个问题解决办法pom.xml升级依赖版本到最新pagehelper-spring-boot-starter版本,或者降级spring-boot-starter-parent 均可以。

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper-spring-boot-starter</artifactId>
+    <version>1.4.2</version>
- <!--<version>1.2.10</version>-->
</dependency>

参考资料
[1] pagehelper.github.io/docs/howtou…