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

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

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 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3197 引用 • 8215 回帖
  • 云计算
    79 引用 • 91 回帖 • 1 关注
  • homepage系列
    7 引用

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • Ubuntu

    Ubuntu(友帮拓、优般图、乌班图)是一个以桌面应用为主的 Linux 操作系统,其名称来自非洲南部祖鲁语或豪萨语的“ubuntu”一词,意思是“人性”、“我的存在是因为大家的存在”,是非洲传统的一种价值观,类似华人社会的“仁爱”思想。Ubuntu 的目标在于为一般用户提供一个最新的、同时又相当稳定的主要由自由软件构建而成的操作系统。

    127 引用 • 169 回帖
  • 负能量

    上帝为你关上了一扇门,然后就去睡觉了....努力不一定能成功,但不努力一定很轻松 (° ー °〃)

    89 引用 • 1243 回帖 • 411 关注
  • LeetCode

    LeetCode(力扣)是一个全球极客挚爱的高质量技术成长平台,想要学习和提升专业能力从这里开始,充足技术干货等你来啃,轻松拿下 Dream Offer!

    209 引用 • 72 回帖 • 2 关注
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    57 引用 • 25 回帖
  • WiFiDog

    WiFiDog 是一套开源的无线热点认证管理工具,主要功能包括:位置相关的内容递送;用户认证和授权;集中式网络监控。

    1 引用 • 7 回帖 • 610 关注
  • 酷鸟浏览器

    安全 · 稳定 · 快速
    为跨境从业人员提供专业的跨境浏览器

    3 引用 • 59 回帖 • 45 关注
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 2 关注
  • ngrok

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

    7 引用 • 63 回帖 • 649 关注
  • Ant-Design

    Ant Design 是服务于企业级产品的设计体系,基于确定和自然的设计价值观上的模块化解决方案,让设计者和开发者专注于更好的用户体验。

    17 引用 • 23 回帖 • 3 关注
  • OkHttp

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

    16 引用 • 6 回帖 • 85 关注
  • Excel
    31 引用 • 28 回帖
  • 设计模式

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

    200 引用 • 120 回帖 • 3 关注
  • 机器学习

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

    83 引用 • 37 回帖 • 1 关注
  • V2Ray
    1 引用 • 15 回帖
  • 正则表达式

    正则表达式(Regular Expression)使用单个字符串来描述、匹配一系列遵循某个句法规则的字符串。

    31 引用 • 94 回帖
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 701 关注
  • abitmean

    有点意思就行了

    37 关注
  • 招聘

    哪里都缺人,哪里都不缺人。

    189 引用 • 1057 回帖 • 5 关注
  • 爬虫

    网络爬虫(Spider、Crawler),是一种按照一定的规则,自动地抓取万维网信息的程序。

    106 引用 • 275 回帖 • 2 关注
  • 工具

    子曰:“工欲善其事,必先利其器。”

    298 引用 • 763 回帖 • 1 关注
  • Webswing

    Webswing 是一个能将任何 Swing 应用通过纯 HTML5 运行在浏览器中的 Web 服务器,详细介绍请看 将 Java Swing 应用变成 Web 应用

    1 引用 • 15 回帖 • 642 关注
  • 资讯

    资讯是用户因为及时地获得它并利用它而能够在相对短的时间内给自己带来价值的信息,资讯有时效性和地域性。

    56 引用 • 85 回帖 • 1 关注
  • HHKB

    HHKB 是富士通的 Happy Hacking 系列电容键盘。电容键盘即无接点静电电容式键盘(Capacitive Keyboard)。

    5 引用 • 74 回帖 • 503 关注
  • HBase

    HBase 是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的 Google 论文 “Bigtable:一个结构化数据的分布式存储系统”。就像 Bigtable 利用了 Google 文件系统所提供的分布式数据存储一样,HBase 在 Hadoop 之上提供了类似于 Bigtable 的能力。

    17 引用 • 6 回帖 • 60 关注
  • 浅吟主题

    Jeffrey Chen 制作的思源笔记主题,项目仓库:https://github.com/TCOTC/Whisper

    1 引用 • 28 回帖
  • Redis

    Redis 是一个开源的使用 ANSI C 语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value 数据库,并提供多种语言的 API。从 2010 年 3 月 15 日起,Redis 的开发工作由 VMware 主持。从 2013 年 5 月开始,Redis 的开发由 Pivotal 赞助。

    286 引用 • 248 回帖 • 1 关注
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    28 引用 • 197 回帖 • 33 关注