Mock平台头图5.png

【Mock平台】为系列测试开发教程,从0到1编码带你一步步使用Spring Boot 和 Antd React框架完成搭建一个测试工具平台,希望作为一个实战项目对各位的测试开发学习之路有帮助,欢迎关注《大奇测试开发》公众号、博客、语雀等原创渠道获取最佳阅读,大奇一个专注测试技术干货原创与分享的家伙。

概要引导

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

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

需求实现

项目管理表

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

字段 类型 必填 说明
mp_id int 自增ID
mp_name varchar 项目名称
mp_type varchar 项目属性 公开-public(默认) ,私有-private
mp_desc varchar 项目更多描述信息 500以内字符
mp_owner varchar 项目负责人(联系人)
mp_create_user varchar 创建人
mp_update_user varchar 修改人
mp_create_date datetime 创建时间,默认CURRENT_TIMESTAMP
mp_update_date datetime 修改时间,随修改自动修改

后端接口

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

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

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

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

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

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

  1. import lombok.Data;
  2. @Data
  3. public class MockProjectEntity extends BaseEntity{
  4. // 自增ID编号
  5. private Integer id;
  6. // 项目名称
  7. private String name;
  8. // 项目类型 public 或 private
  9. private String type;
  10. // 项目描述
  11. private String desc;
  12. // 项目管理人或者负责人
  13. private String owner;
  14. }

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

  1. @Data
  2. public class MockProjectRequest {
  3. // 项目ID
  4. private Integer id;
  5. // 项目名称
  6. @NotBlank(message = "项目名称不能为空")
  7. private String name;
  8. // 项目描述
  9. private String desc;
  10. // 项目负责人
  11. private String owner;
  12. // 项目属性 public-公开,private-私有
  13. private String type;
  14. // 操作人
  15. private String operator;
  16. }

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

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

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

  1. /**
  2. * @param name
  3. * @return List<MockProjectEntity>
  4. * @desc 数据库项目表,根据id查询project详细信息
  5. */
  6. @Select("SELECT * FROM mock_project WHERE mp_name LIKE CONCAT(CONCAT('%',#{name},'%'))")
  7. @ResultMap("projectMap")
  8. List<MockProjectEntity> searchMockProject(String name);
  9. /**
  10. * @param projectEntity
  11. * @return 影响数量 插入成功默认1
  12. * @desc 项目插入SQL
  13. */
  14. @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())"})
  15. @ResultMap("projectMap")
  16. int insertProject(MockProjectEntity projectEntity);
  17. /**
  18. * 项目修改SQL
  19. * @param projectEntity
  20. * @return 影响数量 更新成功默认1
  21. */
  22. @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}"})
  23. @ResultMap("projectMap")
  24. int updateProject(MockProjectEntity projectEntity);

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

  1. /**
  2. * The annotation that specify a mapping definition for the property.
  3. *
  4. * @see Results
  5. * @author Clinton Begin
  6. */
  7. @Documented
  8. @Retention(RetentionPolicy.RUNTIME)
  9. @Target(ElementType.METHOD)
  10. @Repeatable(Results.class)
  11. public @interface Result {
  12. /**
  13. * Returns whether id column or not.
  14. * @return {@code true} if id column; {@code false} if otherwise
  15. */
  16. boolean id() default false;
  17. /**
  18. * Return the column name(or column label) to map to this argument.
  19. * @return the column name(or column label)
  20. */
  21. String column() default "";
  22. /**
  23. * Returns the property name for applying this mapping.
  24. * @return the property name
  25. */
  26. String property() default "";
  27. /**
  28. * Return the java type for this argument.
  29. * @return the java type
  30. */
  31. Class<?> javaType() default void.class;
  32. /**
  33. * Return the jdbc type for column that map to this argument.
  34. * @return the jdbc type
  35. */
  36. JdbcType jdbcType() default JdbcType.UNDEFINED;
  37. /**
  38. * Returns the {@link TypeHandler} type for retrieving a column value from result set.
  39. * @return the {@link TypeHandler} type
  40. */
  41. Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;
  42. /**
  43. * Returns the mapping definition for single relationship.
  44. * @return the mapping definition for single relationship
  45. */
  46. One one() default @One;
  47. /**
  48. * Returns the mapping definition for collection relationship.
  49. * @return the mapping definition for collection relationship
  50. */
  51. Many many() default @Many;
  52. }

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

  1. public interface MockProjectService {
  2. RespResult selectMockProjectList();
  3. RespResult searchMockProject(String name, int current, int pageSize);
  4. RespResult saveMockProject(MockProjectRequest mockProject);
  5. }

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

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.stereotype.Service;
  3. @Service("MockProjectService")
  4. public class MockProjectServiceImpl implements MockProjectService {
  5. @Autowired
  6. MockProjectMapper mockProjectMapper;
  7. /***
  8. * 获取项目列表
  9. * @return Resp
  10. */
  11. @Override
  12. public RespResult selectMockProjectList() {
  13. List<MockProjectEntity> mockProjectEntityList= mockProjectMapper.selectMockProject();
  14. return RespResult.success(mockProjectEntityList);
  15. }
  16. /**
  17. * 根据搜索条件搜索项目List
  18. * name为空的时候按全部条件搜索
  19. * @param name
  20. * @return
  21. */
  22. @Override
  23. public RespResult searchMockProject(String name, int current, int pageSize) {
  24. List<MockProjectEntity> mockProjectEntityList;
  25. // 分页 https://pagehelper.github.io/docs/howtouse/ 使用文档
  26. PageHelper.startPage(current, pageSize);
  27. if (name.isEmpty()){
  28. mockProjectEntityList = mockProjectMapper.selectMockProject();
  29. } else{
  30. mockProjectEntityList = mockProjectMapper.searchMockProject(name);
  31. }
  32. PageInfo pageData = new PageInfo(mockProjectEntityList);
  33. return RespResult.success(pageData);
  34. }
  35. /**
  36. * 项目添加和保存实现
  37. * @param mockProject
  38. * @return
  39. */
  40. public RespResult saveMockProject(MockProjectRequest mockProject) {
  41. MockProjectEntity mockProjectEntity = new MockProjectEntity();
  42. mockProjectEntity.setName(mockProject.getName());
  43. mockProjectEntity.setDesc(mockProject.getDesc());
  44. mockProjectEntity.setType(mockProject.getType());
  45. mockProjectEntity.setOwner(mockProject.getOwner());
  46. if(mockProject.getId() == null){
  47. mockProjectEntity.setCreateUser(mockProject.getOperator());
  48. mockProjectMapper.insertProject(mockProjectEntity);
  49. }
  50. else {
  51. mockProjectEntity.setId(mockProject.getId());
  52. mockProjectEntity.setUpdateUser(mockProject.getOperator());
  53. mockProjectMapper.updateProject(mockProjectEntity);
  54. }
  55. return RespResult.success();
  56. }
  57. }

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

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

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

  1. <dependency>
  2. <groupId>com.github.pagehelper</groupId>
  3. <artifactId>pagehelper-spring-boot-starter</artifactId>
  4. <version>1.4.2</version>
  5. </dependency>

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

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

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

  1. @RestController
  2. @RequestMapping("/api/mock/")
  3. public class MockProjectController {
  4. @Autowired
  5. private MockProjectService mockProjectService;
  6. @GetMapping(value = "/project/list")
  7. public RespResult getProjectList() {
  8. return mockProjectService.selectMockProjectList();
  9. }
  10. @RequestMapping(value = "/project/search", method = RequestMethod.GET)
  11. public RespResult searchProject(@RequestParam(value = "name") String name, int current, int pageSize) {
  12. return mockProjectService.searchMockProject(name, current, pageSize);
  13. }
  14. /***
  15. * 项目增加保存类
  16. * @param mockProject
  17. * @return
  18. */
  19. @PostMapping(value = "/project/save")
  20. public RespResult saveProject(@RequestBody MockProjectRequest mockProject) {
  21. try {
  22. return mockProjectService.saveMockProject(mockProject);
  23. }catch (Exception e){
  24. System.out.println(e);
  25. }
  26. return RespResult.failure(RespCode.SYSTEM_ERROR);
  27. }
  28. }

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

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

遇到的报错问题解决

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

  1. Description:
  2. The dependencies of some of the beans in the application context form a cycle:
  3. ┌──->──┐
  4. | com.github.pagehelper.autoconfigure.PageHelperAutoConfiguration
  5. └──<-──┘

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

  1. <dependency>
  2. <groupId>com.github.pagehelper</groupId>
  3. <artifactId>pagehelper-spring-boot-starter</artifactId>
  4. + <version>1.4.2</version>
  5. - <!--<version>1.2.10</version>-->
  6. </dependency>

参考资料
[1] https://pagehelper.github.io/docs/howtouse/