写点什么

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

  • 2022 年 6 月 16 日
  • 本文字数:5955 字

    阅读完需:约 20 分钟

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

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

概要引导

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


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


1.需求实现

1.1 项目管理表

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

1.2 后端接口

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

  • 条件查询接口,返回项目信息列表

  • 项目新增和修改接口,此处合并成一个保存接口


按照之前一篇 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;
@Datapublic 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 透传。

@Datapublic 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]****的使用 ** <br />在之前的系列 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); }}
复制代码


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


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


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>
复制代码


参考资料


发布于: 2022 年 06 月 16 日阅读数: 51
用户头像

自信人生两百年,会当击水三千里。 2018.02.15 加入

分享一些系列测试平台开发教程,也记录一些自己研究的技术,遇到的问题,总之想分享一些干货内容,愿给这个行业贡献微不足道的力量,不断突破不断成长。

评论

发布
暂无评论
测试开发【Mock平台】05开发:项目管理(一)后端接口_测试平台开发教程_大奇测试开发_InfoQ写作社区