homepage 第六期:user 微服务搭建,单元测试,可用性测试准备

本贴最后更新于 2136 天前,其中的信息可能已经时移俗易

1.首先创建服务层接口 IUserService,里边包含了三个方法,即创建用户,根据 id 获取用户,和根据 id 获取用户和用户的课程信息

package cn.chenforcode.homepage.service; import cn.chenforcode.homepage.UserInfo; import cn.chenforcode.homepage.vo.CreateUserRequest; import cn.chenforcode.homepage.vo.UserCourseInfo; /** * @author <a href="http://www.chenforcode.cn">PKUCoder</a> * @date 2019/11/13 2:33 下午 * @description 用户服务的服务层接口 */ public interface IUserService { /** * @Author <a href="http://www.chenforcode.cn">PKUCoder</a> * @Date 2019/11/13 2:35 下午 * @Param [request] * @Return cn.chenforcode.homepage.UserInfo * @Description 创建一个user **/ UserInfo creatUser(CreateUserRequest request); /** * @Author <a href="http://www.chenforcode.cn">PKUCoder</a> * @Date 2019/11/13 2:36 下午 * @Param [id] * @Return cn.chenforcode.homepage.UserInfo * @Description 根据id获取userinfo信息 **/ UserInfo getUserInfo(Long id); /** * @Author <a href="http://www.chenforcode.cn">PKUCoder</a> * @Date 2019/11/13 2:36 下午 * @Param [id] * @Return cn.chenforcode.homepage.vo.UserCourseInfo * @Description 获取用户的信息和课程信息 **/ UserCourseInfo getUserCourseInfo(Long id); }

2.对该接口进行实现,这里对大部分的代码都进行了注释。但是要注意一点,在获取用户的课程信息的时候是调用了课程微服务,所以需要把 courseClient 也注入进来。但是从 userClient 获取 courseInfo 的时候注意调用函数所需要的参数。

package cn.chenforcode.homepage.service.impl; import cn.chenforcode.homepage.CourseInfo; import cn.chenforcode.homepage.CourseInfosRequest; import cn.chenforcode.homepage.UserInfo; import cn.chenforcode.homepage.client.CourseClient; import cn.chenforcode.homepage.entity.HomepageUser; import cn.chenforcode.homepage.entity.HomepageUserCourse; import cn.chenforcode.homepage.repository.HomepageUserCourseRepository; import cn.chenforcode.homepage.repository.HomepageUserRepository; import cn.chenforcode.homepage.service.IUserService; import cn.chenforcode.homepage.vo.CreateUserRequest; import cn.chenforcode.homepage.vo.UserCourseInfo; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; /** * @author <a href="http://www.chenforcode.cn">PKUCoder</a> * @date 2019/11/13 2:37 下午 * @description 用户服务服务层实现类 */ @Slf4j @Service public class UserServiceImpl implements IUserService { @Autowired private HomepageUserRepository userRepository; @Autowired private HomepageUserCourseRepository userCourseRepository; @Autowired private CourseClient courseClient; @Override public UserInfo creatUser(CreateUserRequest request) { //首先判断request是否合法 if (!request.validate()) { return UserInfo.invalid(); } HomepageUser oldUser = userRepository.findByUsername(request.getUsername()); //判断是否已经存在了这个用户名的用户 if (null == oldUser) { return UserInfo.invalid(); } HomepageUser newUser = userRepository.save( new HomepageUser(request.getUsername(), request.getEmail()) ); return new UserInfo(newUser.getId(), newUser.getUsername(), newUser.getEmail()); } @Override public UserInfo getUserInfo(Long id) { Optional<HomepageUser> user = userRepository.findById(id); //如果不存在这个id的用户 if (!user.isPresent()) { return UserInfo.invalid(); } HomepageUser curUser = user.get(); return new UserInfo(curUser.getId(), curUser.getUsername(), curUser.getEmail()); } @Override public UserCourseInfo getUserCourseInfo(Long id) { Optional<HomepageUser> user = userRepository.findById(id); //如果不存在这个id的用户 if (!user.isPresent()) { return UserCourseInfo.invalid(); } HomepageUser homepageUser = user.get(); //得到userInfo UserInfo userInfo = new UserInfo(homepageUser.getId(), homepageUser.getUsername(), homepageUser.getEmail()); //开始拿到课程信息 //拿到userCourse的信息,即用户和课程的一一对应信息 List<HomepageUserCourse> homepageUserCourses = userCourseRepository.findAllByUserId( homepageUser.getId() ); //如果这个人没有课程,就返回一个只有用户信息和空列表的userCourseInfo if (CollectionUtils.isEmpty(homepageUserCourses)) { return new UserCourseInfo(userInfo, Collections.emptyList()); } //理解一下这里,首先如果要拿到courseInfos就需要一个courseInfosRequest对象,然后这个对象里的属性是一个ids,即 //所有的课程id的list,那么这个list就从homepageUser的list用lambda表达式拿到 List<CourseInfo> courseInfos = courseClient.getCourseInfos( new CourseInfosRequest(homepageUserCourses.stream() .map(HomepageUserCourse::getId) .collect(Collectors.toList())) ); return new UserCourseInfo(userInfo, courseInfos); } }

3.用户服务 controller 层

package cn.chenforcode.homepage.controller; import cn.chenforcode.homepage.UserInfo; import cn.chenforcode.homepage.service.IUserService; import cn.chenforcode.homepage.vo.CreateUserRequest; import cn.chenforcode.homepage.vo.UserCourseInfo; import com.alibaba.fastjson.JSON; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; /** * @author <a href="http://www.chenforcode.cn">PKUCoder</a> * @date 2019/11/13 4:21 下午 * @description 用户服务对外接口 */ @Slf4j @RestController public class HomepageUserController { @Autowired private IUserService userService; @PostMapping("/create/user") public UserInfo createUser(@RequestBody CreateUserRequest request) { log.info("<homepage-user> : create user -> {}", JSON.toJSONString(request)); return userService.creatUser(request); } @GetMapping("/get/user") public UserInfo getUser(Long id) { log.info("<homepage-user> : get user -> {}", id); return userService.getUserInfo(id); } @GetMapping("/get/user/course") public UserCourseInfo getUserCourseInfo(Long id) { log.info("<homepage-user> : get user course info -> {}", id); return userService.getUserCourseInfo(id); } }

4.完成相关功能性测试,创建 test resources 目录,并将 main 目录的配置文件拷贝进来。但是由于想要在测试用例中调用其他的 feign 接口,需要吧 course 服务单独启动起来,那么我们现在先不这样做,我们只是测试一下 user 的功能。所以在配置文件中删除 feign 相关的配置

5.建立测试启动类

package cn.chenforcode.homepage; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.openfeign.EnableFeignClients; /** * @author <a href="http://www.chenforcode.cn">PKUCoder</a> * @date 2019/11/13 4:58 下午 * @description user服务测试启动类 */ @EnableFeignClients(basePackages = {"cn.chenforcode.homepage"}) @SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }

6.测试增加用户

@Test @Transactional public void testCreateUser() { System.out.println(userService.createUser( new CreateUserRequest("pkucoder", "pkucoder@qq.com") )); }

@Transactional 是 org.springframework.transaction.annotation.Transactional 包下的,作用是测试用例执行完之后对数据库进行回滚

6.测试获取用户信息

//{"email":"pkucoder@qq.com","id":10,"username":"pkucoder"} @Test public void testGetUserInfo() { System.out.println(JSON.toJSONString( userService.getUserInfo(10L) )); }

7.由于测试获取课程需要先启动课程服务,在单元测试中不好实现,所以需要在后续的 postman 中直接用 http 的方式去测试,所以在这里先预先加入一些 mock 数据,即增加 homepageUserCourse

@Test public void testCreateHomepageUserCourse() { HomepageUserCourse userCourse1 = new HomepageUserCourse(); userCourse1.setUserId(10L); userCourse1.setCourseId(8L); HomepageUserCourse userCourse2 = new HomepageUserCourse(); userCourse2.setUserId(10L); userCourse2.setCourseId(9L); System.out.println(userCourseRepository.saveAll(Arrays.asList(userCourse1, userCourse2)).size()); }

8.可用性测试之前的准备,配置网关服务,修改 zuul 的 application.yml
增加如下内容,
@1.prefix 的意思是所有的网关访问如下服务需要带上 chenforcode 的前缀,这个前缀可有可无
@2.course 和 user 是随便起的,但是尽量和服务相关
@3.path 代表所有带上这个前缀的服务都会被发送到 serviceId 所指定的服务中
@4.strip-prefix 代表是否去除请求的前缀,置为 false

zuul: prefix: /chenforcode routes: course: path: /homepage-course/** serviceId: eureka-client-homepage-course strip-prefix: false user: path: /homepage-user/** serviceId: eureka-client-homepage-user strip-prefix: false
  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3203 引用 • 8217 回帖
  • 云计算
    80 引用 • 93 回帖 • 1 关注
  • homepage系列
    7 引用

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • OkHttp

    OkHttp 是一款 HTTP & HTTP/2 客户端库,专为 Android 和 Java 应用打造。

    16 引用 • 6 回帖 • 94 关注
  • Access
    1 引用 • 3 回帖 • 1 关注
  • OneNote
    2 引用 • 5 回帖 • 4 关注
  • Typecho

    Typecho 是一款博客程序,它在 GPLv2 许可证下发行,基于 PHP 构建,可以运行在各种平台上,支持多种数据库(MySQL、PostgreSQL、SQLite)。

    12 引用 • 67 回帖 • 446 关注
  • Kotlin

    Kotlin 是一种在 Java 虚拟机上运行的静态类型编程语言,由 JetBrains 设计开发并开源。Kotlin 可以编译成 Java 字节码,也可以编译成 JavaScript,方便在没有 JVM 的设备上运行。在 Google I/O 2017 中,Google 宣布 Kotlin 成为 Android 官方开发语言。

    19 引用 • 33 回帖 • 91 关注
  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1062 引用 • 3455 回帖 • 139 关注
  • CSDN

    CSDN (Chinese Software Developer Network) 创立于 1999 年,是中国的 IT 社区和服务平台,为中国的软件开发者和 IT 从业者提供知识传播、职业发展、软件开发等全生命周期服务,满足他们在职业发展中学习及共享知识和信息、建立职业发展社交圈、通过软件开发实现技术商业化等刚性需求。

    14 引用 • 155 回帖
  • FFmpeg

    FFmpeg 是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。

    24 引用 • 33 回帖
  • 大疆创新

    深圳市大疆创新科技有限公司(DJI-Innovations,简称 DJI),成立于 2006 年,是全球领先的无人飞行器控制系统及无人机解决方案的研发和生产商,客户遍布全球 100 多个国家。通过持续的创新,大疆致力于为无人机工业、行业用户以及专业航拍应用提供性能最强、体验最佳的革命性智能飞控产品和解决方案。

    2 引用 • 14 回帖
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    90 引用 • 113 回帖
  • RIP

    愿逝者安息!

    8 引用 • 92 回帖 • 420 关注
  • danl
    192 关注
  • 印象笔记
    3 引用 • 21 回帖 • 1 关注
  • SpaceVim

    SpaceVim 是一个社区驱动的模块化 vim/neovim 配置集合,以模块的方式组织管理插件以
    及相关配置,为不同的语言开发量身定制了相关的开发模块,该模块提供代码自动补全,
    语法检查、格式化、调试、REPL 等特性。用户仅需载入相关语言的模块即可得到一个开箱
    即用的 Vim-IDE。

    3 引用 • 31 回帖 • 115 关注
  • 知乎

    知乎是网络问答社区,连接各行各业的用户。用户分享着彼此的知识、经验和见解,为中文互联网源源不断地提供多种多样的信息。

    10 引用 • 66 回帖 • 1 关注
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖
  • Swagger

    Swagger 是一款非常流行的 API 开发工具,它遵循 OpenAPI Specification(这是一种通用的、和编程语言无关的 API 描述规范)。Swagger 贯穿整个 API 生命周期,如 API 的设计、编写文档、测试和部署。

    26 引用 • 35 回帖 • 6 关注
  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    20 引用 • 245 回帖 • 240 关注
  • Git

    Git 是 Linux Torvalds 为了帮助管理 Linux 内核开发而开发的一个开放源码的版本控制软件。

    212 引用 • 358 回帖
  • Vim

    Vim 是类 UNIX 系统文本编辑器 Vi 的加强版本,加入了更多特性来帮助编辑源代码。Vim 的部分增强功能包括文件比较(vimdiff)、语法高亮、全面的帮助系统、本地脚本(Vimscript)和便于选择的可视化模式。

    29 引用 • 66 回帖 • 1 关注
  • Postman

    Postman 是一款简单好用的 HTTP API 调试工具。

    4 引用 • 3 回帖
  • Android

    Android 是一种以 Linux 为基础的开放源码操作系统,主要使用于便携设备。2005 年由 Google 收购注资,并拉拢多家制造商组成开放手机联盟开发改良,逐渐扩展到到平板电脑及其他领域上。

    337 引用 • 324 回帖 • 2 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    167 引用 • 408 回帖 • 482 关注
  • 安全

    安全永远都不是一个小问题。

    201 引用 • 818 回帖 • 1 关注
  • Node.js

    Node.js 是一个基于 Chrome JavaScript 运行时建立的平台, 用于方便地搭建响应速度快、易于扩展的网络应用。Node.js 使用事件驱动, 非阻塞 I/O 模型而得以轻量和高效。

    139 引用 • 269 回帖
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 65 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 293 关注