微服务实战项目_天机学堂01_初识项目

文章目录

  • 一.项目简述
  • 二.Jenkins
  • 三.模拟真实业务:紧急bug修复和代码阅读


一.项目简述

Q:天机学堂是什么?

A:天机学堂是一个基于微服务架构的生产级在线教育项目

主要有两个端(项目已上线,可以点击查看):

  • 管理后台: https://tjxt-admin.itheima.net 其核心业务主体包括老师、管理员、其他员工,核心业务围绕着老师展开

  • 用户端:链接: https://tjxt-user.itheima.net/#/main/index 其核心业务主体就是学员,所有业务围绕着学员的展开


系统架构图

在这里插入图片描述

技术架构图

在这里插入图片描述


开发模式

一个企业微服务项目,往往包含数十个不同的微服务模块。参与开发的工作人员也从几人到数百人不等。 每个开发人员或者开发小组负责开发部分微服务模块,分工合作,完成整个微服务项目开发。

天机学堂项目组: 后端5人(包含1个开发组长), 前端2人,测试2人, UI 1人,架构师1人。目前没有移动端,只有PC端。

在这里插入图片描述

图片中打○的是部分完成,需要继续开发;打×的是没有开发,需要从基础开发

补充:企业开发环境一般分为本地环境、测试环境、生产环境:

  • 本地开发环境(loacl):自己的电脑环境

  • 测试/开发环境(test/dev):在内网中搭建的一套大家都可以访问使用的环境

  • 生产环境(prod):最终给用户使用的环境


模拟企业开发环境

为了模拟企业中的开发环境,所以我们需要通过VMware导入linux虚拟机,该虚拟机中已经安装了课程中所需要的各种环境,包括,git、maven私服、mysql、RabbitMQ等。


二.Jenkins

首先了解这三个概念:

持续集成(Continuous Integration,CI):
CI 是一种软件开发实践,它要求团队成员将其工作频繁地集成到共享存储库中。每次代码提交后,自动触发构建和测试过程,以确保新代码与现有代码集成,不会导致破坏或错误。CI的目标是尽早发现和解决集成问题,以减少集成阶段的错误。

持续交付(Continuous Delivery,CD):
CD 是在CI的基础上构建的概念。它强调不仅要频繁集成代码,还要自动化部署和测试过程,以便能够随时准备好发布软件。持续交付的目标是确保在任何时候都能够生成可靠的、可部署的软件版本,并在需要时快速地交付给用户。但它并不一定要求立即部署到生产环境。

持续部署(Continuous Deployment,CD):
持续部署是CD实践的更进一步,它要求所有通过CI和CD流程的代码变更都自动部署到生产环境,没有人工干预。这意味着经过测试的代码在通过CI和CD流水线后,自动地、立即地部署到生产环境。持续部署的目标是尽量减少发布的手动步骤,从而降低出错的可能性,并能够更迅速地将新功能、修复和改进推送到用户。

持续集成的优点

  • 自动构建、发布、测试

  • 降低风险


Jenkins,原名Hudson,2011年改为现在的名字 它是一个开源的实现持续集成的软件工具。

官方网站:链接: http://jenkins-ci.org/

先了解Jenkins工作流程:

在这里插入图片描述

1.当在idea上提交和推送代码后,会触发Gogs中Web钩子

举个例子:
gogs上配置, 也就是说当我们有代码提交到gogs, 就会触发 http://192.168.150.101:18080/gogs-webhook/?job=tjxt-dev-build

在这里插入图片描述

2. http://192.168.150.101:18080/gogs-webhook/?job=tjxt-dev-build对应的就是Jenkin的任务

在这里插入图片描述

该任务会根据推送的代码重新集成、测试和部署(先将项目打成jar包后构建docker镜像)整个项目,保持我们的虚拟机(在公司中是服务器)上的项目持续更新


项目结构:

在这里插入图片描述


代码规范

  • 项目结构:目前企业微服务开发项目结构有两种模式

    a. 每个项目对应每一个微服务,需要创建一个Project,尽可能降低耦合

    b. 每个项目创建一个Project ,项目下的多个微服务是Project下的Module,方便管理(天机学堂采取的方式)

  • 实体类规范
    a. DTO:数据传输对象,在客户端与服务端间传递数据,例如微服务之间的请求参数和返回值、前端提交的表单

    b. PO:持久层对象,与数据库表一一对应,作为查询数据库时的返回值

    c. VO:视图对象,返回给前端用于封装页面展示的数据

    d. QUERY:查询对象,一般是用于封装复杂查询条件

  • 接口文档规范
    项目开发注释必不可少,而controller接口紧紧加注释还不够,最好把接口形成规范化文档。一方面方便其它微服务来查看接口,另一方面也方便自己基于接口做测试。天机学堂中采用了swagger来实现接口文档。

  • 依赖注入: Spring提供了依赖注入的功能,方便我们管理和使用各种Bean,常见的方式有:

    a. 字段注入(@Autowired 或 @Resource)

    b. 构造函数注入

    c. set方法注入


配置文件

在这里插入图片描述


异常处理

在项目运行过程中,或者业务代码流程中,可能会出现各种类型异常,为了加以区分,我们定义了一些自定义异常对应不同场景:

在这里插入图片描述

在开发业务的过程中,如果出现对应类型的问题,应该优先使用这些自定义异常。

当微服务抛出这些异常时,需要一个统一的异常处理类,同样在tj-common模块中定义了:

package com.tianji.common.autoconfigure.mvc.advice;import com.tianji.common.constants.Constant;
import com.tianji.common.domain.R;
import com.tianji.common.exceptions.CommonException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.WebUtils;
import feign.FeignException;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.util.NestedServletException;import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;@RestControllerAdvice
@Slf4j
public class CommonExceptionAdvice {@ExceptionHandler(DbException.class)public Object handleDbException(DbException e) {log.error("mysql数据库操作异常 -> ", e);return processResponse(e.getStatus(), e.getCode(), e.getMessage());}@ExceptionHandler(CommonException.class)public Object handleBadRequestException(CommonException e) {log.error("自定义异常 -> {} , 状态码:{}, 异常原因:{}  ",e.getClass().getName(), e.getStatus(), e.getMessage());log.debug("", e);return processResponse(e.getStatus(), e.getCode(), e.getMessage());}@ExceptionHandler(FeignException.class)public Object handleFeignException(FeignException e) {log.error("feign远程调用异常 -> ", e);return processResponse(e.status(), e.status(), e.contentUTF8());}@ExceptionHandler(MethodArgumentNotValidException.class)public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {String msg = e.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage).collect(Collectors.joining("|"));log.error("请求参数校验异常 -> {}", msg);log.debug("", e);return processResponse(400, 400, msg);}@ExceptionHandler(BindException.class)public Object handleBindException(BindException e) {log.error("请求参数绑定异常 ->BindException, {}", e.getMessage());log.debug("", e);return processResponse(400, 400, "请求参数格式错误");}@ExceptionHandler(NestedServletException.class)public Object handleNestedServletException(NestedServletException e) {log.error("参数异常 -> NestedServletException,{}", e.getMessage());log.debug("", e);return processResponse(400, 400, "请求参数异常");}@ExceptionHandler(ConstraintViolationException.class)public Object handViolationException(ConstraintViolationException e) {log.error("请求参数异常 -> ConstraintViolationException, {}", e.getMessage());return processResponse( HttpStatus.OK.value(), HttpStatus.BAD_REQUEST.value(),e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).distinct().collect(Collectors.joining("|")));}@ExceptionHandler(Exception.class)public Object handleRuntimeException(Exception e) {log.error("其他异常 uri : {} -> ", WebUtils.getRequest().getRequestURI(), e);return processResponse(500, 500, "服务器内部异常");}private Object processResponse(int status, int code, String msg){// 1.标记响应异常已处理(避免重复处理)WebUtils.setResponseHeader(Constant.BODY_PROCESSED_MARK_HEADER, "true");// 2.如果是网关请求,http状态码修改为200返回,前端基于业务状态码code来判断状态// 如果是微服务请求,http状态码基于异常原样返回,微服务自己做fallback处理return WebUtils.isGatewayRequest() ?R.error(code, msg).requestId(MDC.get(Constant.REQUEST_ID_HEADER)): ResponseEntity.status(status).body(msg);}
}

需要说明的是:

@RestControllerAdvice 是 Spring Boot 中用于全局处理异常的注解。它是在 Spring MVC 中的 @ControllerAdvice 注解的基础上,专门用于处理 RESTful 服务的异常情况。

在一个 Spring Boot 应用中,@RestControllerAdvice 注解的类可以包含多个被 @ExceptionHandler 注解修饰的方法,这些方法用于处理不同类型的异常。当在控制器(@RestController 注解的类或方法)中抛出异常时,@RestControllerAdvice 注解的类中匹配的异常处理方法会被调用,从而实现全局异常处理的功能。


三.模拟真实业务:紧急bug修复和代码阅读

1.BUG复现

使用Jack登录,能删除自己购买的课程(订单); 使用Rose登录,不能够删除自己的购买的课程;

2.分析

阅读代码

如果是我们自己写的代码,肯定很容易找到业务入口、整个业务线路。但现在我们是接手他人项目,所以只能通过其它途径来梳理业务:

  1. 如果开发业务的同事还在,直接与开发该业务的同事交流

  2. 如果开发者已离职,可以查看相关接口文档

  3. 如果没有文档,也可以查看前端请求,顺藤摸瓜

3.根据流程找到bug出处(很重要的思路)

在这里插入图片描述

  1. 找到到请求入口:在企业内开发,我们是接手他人代码,可以通过交流弄清楚入口。否则就只能通过前端入手。

  2. 理清请求链路:找到入口后,先总览项目结构,弄清楚前端请求如何抵达微服务,经过了哪些地方,这对解决BUG会有帮助。

  3. 紧跟主线:源码非常繁杂,不要试图弄清楚每一个细枝末节。紧跟业务主线,先梳理整体脉络,形成整体业务流程图。

  4. 步步深入:最后,基于业务场景,定位核心问题点,抽丝剥茧,展开看来阅读细节,寻找问题所在。

我们可以根据流程思路按照之前我们的环境部署方案,api.tianji.com这个域名会被解析到192.168.150.101这个地址,然后被Nginx反向代理到网关微服务。而网关则会根据请求路径和路由规则,把请求再路由到具体微服务。这里请求路径以/ts开头,对应的微服务是trade-service,也就是交易微服务。这样,整个请求链路就比较清楚了:

在这里插入图片描述

通过我们的分析,请求的入口是tj-trade服务下的deleteOrder()接口

4.分析找到出错接口后,就可以使用debug来调试,找出具体出错的代码了

部署本地服务

1.debug启动本地tj-trade服务(注意:配置走local环境)

2.让测试环境网关路由到本地,只需要在本地启动服务,然后将测试环境的tj-trade服务权重设置为0或者停止

权重设置为0:

在这里插入图片描述
停止服务:

docker stop tj-trade

使用我们本地的微服务后,就可以使用断点调试了:

1.在OrderServiceImpl的deleteOrder方法加断点

在这里插入图片描述
2.分别使用Rose和Jack登录删除自己的订单

3.我们发现当是Rose登录时候,进入到了if里面, Rose的userId是129

在这里插入图片描述

4.userId使用的是包装类型Long, 当值>128时候,不能用!=判断是否相等了

具体来说,Long类型中使用了享元的机制,当数字在[-128,127]之间,Long是同一个对象即范围内的整数值都是缓存中的同一个实例,故jack删除订单会显示删除成功,而rose在范围之外,使用==对比的是两个对象的地址,故返回不能删除他人的订单

在这里插入图片描述

5.解决

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/628690.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT上位机开发(dock窗口在软件布局中的应用)

【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 在软件开发中,一般有主窗口和子窗口之分。主窗口也就是main window,是最重要的操作界面。子窗口就是各种属性配置、参数配置…

NOIP2018提高组day2 - T1:旅行

题目链接 [NOIP2018 提高组] 旅行 题目描述 小 Y 是一个爱好旅行的 OIer。她来到 X 国,打算将各个城市都玩一遍。 小 Y 了解到,X 国的 n n n 个城市之间有 m m m 条双向道路。每条双向道路连接两个城市。 不存在两条连接同一对城市的道路&#xff…

uniapp使用安装sass

1.首先你要安装node-sass npm install node-sass --save-dev2.安装sass-loader npm install sass-loader --save-dev3.修改style标签&#xff0c;声明使用sass <style lang"scss" scoped>

做完十年数据分析后的思考与总结

种一棵树最好的时间是十年前&#xff0c;其次是现在。十年了&#xff0c;本次分享大多来自工作中的日常所思所想&#xff0c;欢迎自取。 01 数据分析的本质 数据是基础&#xff0c;分析才是重点。 行业内有专门的统计岗&#xff0c;就是只负责做好数据统计就可以了&#xff0…

【Python】PyCharm设置控制台输出的行数限制

在使用PyCharm的时候&#xff0c;如果在控制台输出的信息过多室&#xff0c;控制台仅会保留一部分的输出信息。想要改变这个限制&#xff0c;设置方法如下&#xff1a; 进入到PyCharm的安装目录下&#xff0c;我的是C:\Develop\PyCharm202303\PyCharm 2023.3进入bin找到文件id…

群晖NAS上安装部署开源工作流自动化工具n8n

一、开源工作流自动化工具n8n简介 n8n是它是一个与其他应用集成的应用程序&#xff0c;目标是自动化各应用之间的流程;利用 n8n 你可以方便地实现当 A 条件发生&#xff0c;触发 B 服务这样的自动工作流程。 n8n优点是&#xff1a;代码开源、可以自托管、下载安装方便、易于使用…

Java毕业设计第90期-基于springboot的学习英语管理系统

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于springboot的学习英语管理系统&#xff1a;前端 thymeleaf、jquery&#xff0c;后端 maven、springmvc、spring、mybatis&#xff0c;角色分为管理员、用户&#xff…

VSCode使用技巧

选择python 解释器 使用快捷键CtrlShiftP Python: Select Interpreter快捷键 返回上一次光标的位置 重新设置一下 navigate

【LLM】Prompt微调

Prompt 在机器学习中&#xff0c;Prompt通常指的是一种生成模型的输入方式。生成模型可以接收一个Prompt作为输入&#xff0c;并生成与该输入相对应的输出。Prompt可以是一段文本、一个问题或者一个片段&#xff0c;用于指导生成模型生成相应的响应、续写文本等。 Prompt优化…

ROS第 2 课 ROS 系统安装和环境搭建

文章目录 方法一&#xff1a;一键安装&#xff08;推荐&#xff09;方法二&#xff1a;逐步安装&#xff08;常规安装方式&#xff09;1.版本选择2.检查 Ubuntu 的软件和更新源3.设置 ROS 的下载源3.1 设置国内下载源3.2 设置公匙3.3 更新软件包 4. 安装 ROS5. 设置环境变量6. …

SpringBoot Redis入门(四)——Redis单机、哨兵、集群模式

单机模式&#xff1a;单台缓存服务器&#xff0c;开发、测试环境下使用&#xff1b;哨兵模式&#xff1a;主-从模式&#xff0c;提高缓存服务器的高可用和安全性。所有缓存的数据在每个节点上都一致。每个节点添加监听器&#xff0c;不断监听节点可用状态&#xff0c;一旦主节点…

主流人工智能AI工具测评

主流人工智能AI工具测评 主流的人工智能AI工具ChatGPT ——OpenAI研发CHAT_BISON——Google研发Qwen通义千问 ——阿里云研发文心一言——百度研发 根据10个问题分析人工智能的回答女朋友生气了怎么哄千元机性价比推荐小米13 和 vivo iQOO 11s哪个好计算机专业毕业论文护士年终…

kafka-ui通过docker部署

创建docker-compose.yaml services:kafka-ui:container_name: kafka-uiimage: provectuslabs/kafka-ui:latestports:- "8080:8080"environment:DYNAMIC_CONFIG_ENABLED: "true"volumes:- ~/kui:/etc/kafkauiextra_hosts:- "kafka1:10.10.33.30"…

web前端第二次作业

1&#xff0c;计算用户指定的数值内的奇数和 效果运行图&#xff1a; 代码&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>计算用户指定的数值内的奇数和</title> </head>…

使用 Haproxy 搭建Web群集

本章主要学习&#xff1a; 熟悉 Haproxy 功能以常用群集配置调度算法学会Haproxy 常用配置学会 Haproxy 参数优化 简介 在前面已经学习了使用Nginx&#xff0c;LVS 做负载均衡群集&#xff0c;他们都具有各自的特点&#xff0c;本章将要介绍另一款比较流行的群集调度工具 Hap…

CMU15-445-Spring-2023-Project #3 - 前置知识(lec10-14)

Lecture #10_ Sorting & Aggregation Algorithms Query Plan 数据库系统会将 SQL 编译成查询计划。查询计划是一棵运算符树。 Sorting DBMS 需要对数据进行排序&#xff0c;因为根据关系模型&#xff0c;表中的tuple没有特定的顺序。排序使用 ORDER BY、GROUP BY、JOIN…

虚拟机 以及 Centos 7的 安装全过程

目录 安装VMwere Workstion 虚拟机的操作过程 CentOS 7 安装过程 install CentOS 7 安装操作系统 安装VMwere Workstion 虚拟机的操作过程 更改安装位置 到下面图片中的这一个步骤&#xff0c;可以点击许可证&#xff0c;输入密钥就可以使用了&#xff0c; 密钥可以去某度或…

阿里云有哪些优势?为什么选择阿里云?

为什么选择阿里云&#xff1f;阿里云服务器有哪些优势&#xff1f;阿里云全球第三&#xff0c;国内第一云&#xff0c;阿里云服务器网aliyunfuwuqi.com分享云服务器ECS在丰富ECS实例架构、弹性灵活、稳定可靠、便捷易用、安全保障和成本优化多方面优势&#xff1a; 阿里云服务…

Nvidia-docker的基础使用方法

安装&#xff1a; 安装nvidia-docker&#xff1a; distribution$(. /etc/os-release;echo $ID$VERSION_ID)curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.l…

代码随想录 Leetcode344. 反转字符串

题目&#xff1a; 代码(首刷自解 2024年1月16日&#xff09;&#xff1a; class Solution { public:void reverseString(vector<char>& s) {int n s.size();int left 0, right n - 1;while (left < right) {char tep s[left];s[left] s[right];s[right] te…