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

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

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 回帖 • 2 关注
  • 云计算
    80 引用 • 93 回帖 • 1 关注
  • homepage系列
    7 引用

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 设计模式

    设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。

    201 引用 • 120 回帖 • 2 关注
  • Swift

    Swift 是苹果于 2014 年 WWDC(苹果开发者大会)发布的开发语言,可与 Objective-C 共同运行于 Mac OS 和 iOS 平台,用于搭建基于苹果平台的应用程序。

    34 引用 • 37 回帖 • 561 关注
  • 笔记

    好记性不如烂笔头。

    311 引用 • 794 回帖
  • Chrome

    Chrome 又称 Google 浏览器,是一个由谷歌公司开发的网页浏览器。该浏览器是基于其他开源软件所编写,包括 WebKit,目标是提升稳定性、速度和安全性,并创造出简单且有效率的使用者界面。

    63 引用 • 289 回帖
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    21 引用 • 31 回帖 • 6 关注
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1444 引用 • 10083 回帖 • 507 关注
  • InfluxDB

    InfluxDB 是一个开源的没有外部依赖的时间序列数据库。适用于记录度量,事件及实时分析。

    2 引用 • 106 关注
  • Typecho

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

    12 引用 • 67 回帖 • 445 关注
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    26464 引用 • 110077 回帖 • 1 关注
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 624 关注
  • 反馈

    Communication channel for makers and users.

    120 引用 • 906 回帖 • 280 关注
  • QQ

    1999 年 2 月腾讯正式推出“腾讯 QQ”,在线用户由 1999 年的 2 人(马化腾和张志东)到现在已经发展到上亿用户了,在线人数超过一亿,是目前使用最广泛的聊天软件之一。

    45 引用 • 557 回帖
  • 链书

    链书(Chainbook)是 B3log 开源社区提供的区块链纸质书交易平台,通过 B3T 实现共享激励与价值链。可将你的闲置书籍上架到链书,我们共同构建这个全新的交易平台,让闲置书籍继续发挥它的价值。

    链书社

    链书目前已经下线,也许以后还有计划重制上线。

    14 引用 • 257 回帖
  • Log4j

    Log4j 是 Apache 开源的一款使用广泛的 Java 日志组件。

    20 引用 • 18 回帖 • 39 关注
  • RabbitMQ

    RabbitMQ 是一个开源的 AMQP 实现,服务器端用 Erlang 语言编写,支持多种语言客户端,如:Python、Ruby、.NET、Java、C、PHP、ActionScript 等。用于在分布式系统中存储转发消息,在易用性、扩展性、高可用性等方面表现不俗。

    49 引用 • 60 回帖 • 352 关注
  • ngrok

    ngrok 是一个反向代理,通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道。

    7 引用 • 63 回帖 • 656 关注
  • GitHub

    GitHub 于 2008 年上线,目前,除了 Git 代码仓库托管及基本的 Web 管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器、协作图谱(报表)、代码片段分享(Gist)等功能。正因为这些功能所提供的便利,又经过长期的积累,GitHub 的用户活跃度很高,在开源世界里享有深远的声望,并形成了社交化编程文化(Social Coding)。

    209 引用 • 2040 回帖
  • Flume

    Flume 是一套分布式的、可靠的,可用于有效地收集、聚合和搬运大量日志数据的服务架构。

    9 引用 • 6 回帖 • 663 关注
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    77 引用 • 37 回帖
  • Netty

    Netty 是一个基于 NIO 的客户端-服务器编程框架,使用 Netty 可以让你快速、简单地开发出一个可维护、高性能的网络应用,例如实现了某种协议的客户、服务端应用。

    49 引用 • 33 回帖 • 44 关注
  • Hadoop

    Hadoop 是由 Apache 基金会所开发的一个分布式系统基础架构。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。

    93 引用 • 122 回帖 • 613 关注
  • Sym

    Sym 是一款用 Java 实现的现代化社区(论坛/BBS/社交网络/博客)系统平台。

    下一代的社区系统,为未来而构建

    524 引用 • 4601 回帖 • 710 关注
  • Vue.js

    Vue.js(读音 /vju ː/,类似于 view)是一个构建数据驱动的 Web 界面库。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。

    268 引用 • 666 回帖
  • Thymeleaf

    Thymeleaf 是一款用于渲染 XML/XHTML/HTML5 内容的模板引擎。类似 Velocity、 FreeMarker 等,它也可以轻易的与 Spring 等 Web 框架进行集成作为 Web 应用的模板引擎。与其它模板引擎相比,Thymeleaf 最大的特点是能够直接在浏览器中打开并正确显示模板页面,而不需要启动整个 Web 应用。

    11 引用 • 19 回帖 • 397 关注
  • SOHO

    为成为自由职业者在家办公而努力吧!

    7 引用 • 55 回帖 • 3 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 565 关注
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖 • 2 关注