01-微服务1-3章的笔记-牛翰网

01-微服务1-3章的笔记

前言

这是尚硅谷2024Cloud教程的笔记,只是记录学习历程,方便自己以后查询。周阳老师讲的很好,给出原视频地址
对应1.Boot和Cloud选项,2.Cloud组件的停更,升级,替换,3.Base工程构建。

1.Boot和Cloud选项

1.JDK

SpringBoot3.0开始,对于JDK的最低版本是JDK17,强制要求,从JDK8.x 到JDK17的转变。又因OracleJDK的协议,推荐使用OpenJDK。OpenJDK官网下载。在语法层面和OracleJDK没有区别,只是Oracle在OpenJDK上,加了一些额外的商业特性。日常使用,OpenJDK可以了。

2.Maven

Spring官网,对于SpringBoot3.0+的maven版本要求是3.6.3+。注意该组件的版本,会影响idea的版本,因为较高的Maven,在idea2021某个版本之前的版本无法使用,亲自踩坑/(ㄒoㄒ)/~~。可以使用3.6.3,对各个版本的boot和idea兼容新都不错。推荐,使用Maven3.6.3,但是为和老师,保持一致,故使用3.9.5。

3.MySQL

MySQL8.x版本,推出于2018年,距今已有较长时间。在稳定性,社区活跃度等方面都不错,以及免费的特性,实际项目开发中有较多使用。

备注:Spring官网,查看框架基础的依赖组件的版本要求

选择一个版本的Boot,查看Reference Doc,其中的Getting Started中的System Requirements有本版本下,对于jdk,maven,tomcat最低的版本要求。

因为,要选择不同的jdk,不同的maven,所以需要这些信息。甚至,高版本的maven还需要和更高版本的idea适配。

4.技术选项问题

如果是新项目,直接上微服务,是Cloud版本决定,Boot版本。旧项目改造,是Boot版本决定Cloud版本,因为整体项目从boot2.7.x,升级到3.x的代价还是比较高的。在Spring官网,中有Cloud和与Boot的版本依赖关系。官网地址

5.本次课程介绍

5.1 上篇

SpringCloud

5.2 下篇

SpringCloud Alibaba

5.3 说明

SpringCloud和SpringCloud Alibaba相互独立,都是微服务思想的具体实现的产物,相同点就是Spring官方,将Alibaba纳入到了其维护的项目中,不过alibaba也在维护,且alibaba版本会更快。因为毕竟是自己的产品,之后才会同步到Spring社区。

6.SpringBoot版本选择

6.1 GitHub地址

https://github.com/spring-projects/spring-boot/releases

6.2 官网看Boot版本

6.3 SpringBoot3.0的崛起

图片[1]-01-微服务1-3章的笔记-牛翰网
Spring Boot 3.0 requires Java 17 as a minimum version. SpringBoot3.0对于JDK的最低版本要求是JDK17。

7.SpringCloud版本选择

7.1 github地址

https://github.com/spring-cloud

7.2 官网看Cloud版本

7.2.1 Cloud命名规则

SpringCloud的版本关系

Spring Cloud 采用了英国伦敦地铁站的名称来命名,并由地铁站名称字母A-Z依次类推的形式来发布迭代版本

SpringCloud是一个由许多子项目组成的综合项目,各子项目有不同的发布节奏。为了管理SpringCloud与各子项目的版本依赖关系,发布了一个清单,其中包括了某个SpringCloud版本对应的子项目版本。为了避免SpringCloud版本号与子项目版本号混淆,SpringCloud版本采用了名称而非版本号的命名,这些版本的名字采用了伦敦地铁站的名字,根据字母表的顺序来对应版本时间顺序。例如Angel是第一个版本, Brixton是第二个版本。

当SpringCloud的发布内容积累到临界点或者一个重大BUG被解决后,会发布一个”service releases”版本,简称SRX版本,比如Greenwich.SR2就是SpringCloud发布的Greenwich版本的第2个SRX版本。

但是从2020年开始,以2020.0.x的方式命名版本,解决了,令人无法理解的版本命名。

7.2.2 官网地址

https://spring.io/projects/spring-cloud

8.SpringCloud Alibaba版本选择

8.1 SpringCloud官网

https://spring.io/projects/spring-cloud-alibaba

注意,此方式无法看到最新版。有延后。

8.2 Spring Cloud Alibaba官网GitHub说明

图片[2]-01-微服务1-3章的笔记-牛翰网
和老师保持一致,选择2020.x。

8.3 SpringCloudAlibaba版本

https://github.com/alibaba/spring-cloud-alibaba/releases

本次视频定稿

框架间的版本适配,请严格依照官网,或者GitHub。

SpringCloud和SpringBoot和SpringCloud Alibaba三者,制约关系。是Cloud版本决定,Boot版本。

下图是SpringCloudAlibaba – SpringCloud – SpringBoot的版本关系。

结论

基础组件 版本
JDK Java17+
Maven 3.9+
MySQL 8.0+
Spring Cloud 2023.0.0
Spring Boot 3.2.0
Spring Cloud Alibaba 2022.0.0.0-RC2

2.Cloud组件的听更,升级,替换

1.微服务理论知识入门

1.1 形象一点来说

微服务架构就像搭积木,每个微服务都是一个零件一个积木,并使用这些积木零件组装出不同的形状,出来最后一个完整的物体。

1.2 通俗来说

微服务架构就是把一个大系统按业务功能分解成多个职责单一的小系统,每一个小模块尽量专一的只做一件事,并利用简单的方法使多个小系统相互协作,组成一个大系统再统一对外提供整体服务。

1.3 学科派一点

专注一单一责任小型功能模块为基础,并利用轻量化机制(通常为HTTP RESTFUL API)实现通信完成复杂业务搭建的一种架构思想。

2.Spring Cloud是什么?

方便程序员专注于业务逻辑的,由分布式思想落地的框架和一些中间件“有机结合”的产物。

3.本次讲解的内容-粗略版

4.本次讲解的内容-详推版

4.1 2018第一季

4.2 Netflix OSS被移除的原因

Netflix OSS(Open Source System),是Netflix公司开发的一套代码框架和库,SpringCloud Netflix是在Netflix OSS基础之上的封装。

更新版本没有什么大惊小怪的,但是本次更新却正式开启了Spring Cloud Netflix体系的终结进程。Netflix公司是目前微服务落地中最成功的公司。它开源了诸如EurekaHystrixZuulFeignRibbon等等广大开发者所知微服务套件,统称为Netflix OSS。在当时 Netflix OSS成为微服务组件上事实的标准。但是微服务兴起不久,也就是在2018年前后Netflix公司宣布其核心组件EurekaHystrixZuulFeignRibbon等进入维护状态,不再进行新特性开发,只修BUG。

这直接影响了Spring Cloud项目的发展路线,Spring官方不得不采取了应对措施,在2019年的在SpringOne2019大会中,Spring Cloud宣布 Spring Cloud Netflix项目进入维护模式,并在2020年移除相关的Netflix OSS组件。

4.2.1 Netflix那些被移除了?

图片[3]-01-微服务1-3章的笔记-牛翰网
2019年进入Maintenance Mode。

维护模式,就是被动的修复bugs,不再接收合并请求,不再发布新版本。换句话说就是,除非出现特别严重的bug,否则没人管了。

4.2.2 由停更引发的“升级惨案”

图片[4]-01-微服务1-3章的笔记-牛翰网
红叉:不能再使用了;感叹号:能用但是不推荐;对号:推荐使用。

图片[5]-01-微服务1-3章的笔记-牛翰网
备注,remove的组件都不能使用。

3.Base工程构建

1.订单->支付,业务需求说明

2.约定>配置>编码

约定,业内基本达成共识的一些想法,比如在Web开发中,Post请求,往往用来添加数据,Get请求,用来获取数据,Delete请求,用来删除数据等。

配置,是提前确定好,使用的组件的版本信息,因为版本冲突的问题,导致的配置,是让人特别厌恶和反感的。这也是一般微服务项目,都会有一个公共的父模块,在这个父模块的pom文件中,定义好使用的各种框架,组建的版本。各个子模块,在自己的pom文件中,使用定义好的版本的依赖。

编码,就是写代码。

3.IDEA新建Project和Maven父工程

3.1 微服务cloud整体聚合Maven父工程

3.1.1 New Project

略,注意,创建父工程时,不要使用Spring的初始化工具,创建Maven项目。

3.1.2 定义父工程名字
<!-- 这里是视频教程中的名称,实际使用中,自定义 在父模块的pom文件中定义 -->
<groupId>com.atguigu.cloud</groupId>
<artifactId>cloud</artifactId>
<version>1.0-SNAPSHOT</version>
3.1.3 定义字符编码

File -> Settings -> Editor -> File Encodings

设置Global Encoding,Project Encoding,Default encoding for properties files 都为UTF-8,以及勾选Transparent native-to-ascii conversion。

3.1.4 注解生效激活

File -> Settings -> Build,Execution,Deployment -> Complier -> Annotation Processors

Enable annotation processing勾选。

3.1.5 Java编译版本选17

File -> Settings -> Build,Execution,Deployment -> Complier -> Java Complie

Target bytecode version选择17

3.1.6 File Type过滤

File -> Settings -> Editor -> File Types

Ignored FIles and Folders

添加*.idea文件

小结

以上配置,都可以配置在新创建项目中,也就是说新建的项目,会自动使用,配置好的。

File -> New Project Setup -> Settings for New Projects

3.2 父工程POM文件内容

这也是父工程存在的意义,提前定义好,本系统中,可能会使用的依赖的版本,防止,因版本冲突问题出现bug。注意,这里实际不引入jar包,只是定义版本。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.atguigu.cloud</groupId>
    <artifactId>mscloudV5</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <hutool.version>5.8.22</hutool.version>
        <lombok.version>1.18.26</lombok.version>
        <druid.version>1.1.20</druid.version>
        <mybatis.springboot.version>3.0.2</mybatis.springboot.version>
        <mysql.version>8.0.11</mysql.version>
        <swagger3.version>2.2.0</swagger3.version>
        <mapper.version>4.2.3</mapper.version>
        <fastjson2.version>2.0.40</fastjson2.version>
        <persistence-api.version>1.0.2</persistence-api.version>
        <spring.boot.test.version>3.1.5</spring.boot.test.version>
        <spring.boot.version>3.2.0</spring.boot.version>
        <spring.cloud.version>2023.0.0</spring.cloud.version>
        <spring.cloud.alibaba.version>2022.0.0.0-RC2</spring.cloud.alibaba.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!--springboot 3.2.0-->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>${spring.boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springcloud 2023.0.0-->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--springcloud alibaba 2022.0.0.0-RC2-->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring.cloud.alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!--SpringBoot集成mybatis-->
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>${mybatis.springboot.version}</version>
            </dependency>
            <!--Mysql数据库驱动8 -->
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql.version}</version>
            </dependency>
            <!--SpringBoot集成druid连接池-->
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid-spring-boot-starter</artifactId>
                <version>${druid.version}</version>
            </dependency>
            <!--通用Mapper4之tk.mybatis-->
            <dependency>
                <groupId>tk.mybatis</groupId>
                <artifactId>mapper</artifactId>
                <version>${mapper.version}</version>
            </dependency>
            <!--persistence-->
            <dependency>
                <groupId>javax.persistence</groupId>
                <artifactId>persistence-api</artifactId>
                <version>${persistence-api.version}</version>
            </dependency>
            <!-- fastjson2 -->
            <dependency>
                <groupId>com.alibaba.fastjson2</groupId>
                <artifactId>fastjson2</artifactId>
                <version>${fastjson2.version}</version>
            </dependency>
            <!-- swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html -->
            <dependency>
                <groupId>org.springdoc</groupId>
                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
                <version>${swagger3.version}</version>
            </dependency>
            <!--hutool-->
            <dependency>
                <groupId>cn.hutool</groupId>
                <artifactId>hutool-all</artifactId>
                <version>${hutool.version}</version>
            </dependency>
            <!--lombok-->
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok.version}</version>
                <optional>true</optional>
            </dependency>
            <!-- spring-boot-starter-test -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-test</artifactId>
                <version>${spring.boot.test.version}</version>
                <scope>test</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

3.3.Maven工程细节复习

Maven中的dependencyManagement和dependencies。

Maven 使用dependencyManagement元素来提供了一种管理依赖版本号的方式。

通常会在一个组织或者项目的最顶层的父POM 中看到dependencyManagement元素。

使用pom.xml 中的dependencyManagement元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。Maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用这个dependencyManagemen元素中指定的版本号。

这样做的好处就是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,优势:

  • 1.这样当想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个子项目的修改 ;
  • 2.另外如果某个子项目需要另外的一个版本,只需要声明version就可。

dependencyManagement里只是声明依,并不实现引入,因此子项目需要显示的声明需要用的依赖。

如果不在子项目中声明依赖,是不会从父项目中继承下来的,只有在子项目中写了该依赖项并且没有指定具体版本,才会从父项目中继承该项 且version和scope都读取自父pom;

如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。

Maven中跳过单元测试

1.配置

<build><!-- maven中跳过单元测试 -->
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-surefire-plugin</artifactId>
            <configuration>
                <skip>true</skip>
            </configuration>
        </plugin>
    </plugins>
</build>

2.IDEA工具支持(推荐)

3.4 MySQL驱动说明

3.4.1 MySQL 5.7
# mysql5.7---JDBC四件套
jdbc.driverClass = com.mysql.jdbc.Driver
jdbc.url= jdbc:mysql://localhost:3306/db2024?useUnicode=true&characterEncoding=UTF-8&useSSL=false
jdbc.user = root
jdbc.password =123456
# Maven的POM文件处理
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>
3.4.2 MySQL 8.0

推荐使用MySQL8.0

# mysql8.0---JDBC四件套
jdbc.driverClass = com.mysql.cj.jdbc.Driver
jdbc.url= jdbc:mysql://localhost:3306/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
jdbc.user = root
jdbc.password =123456
# Maven的POM
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.11</version>
</dependency>

4.Mapper4之一键生成

4.1 mybatis-generator

http://mybatis.org/generator

一款生成mapper的插件。

4.2 MyBatis通用Mapper4官网

https://github.com/abel533/Mapper

4.3 Mapper5官网

https://github.com/mybatis-generator/mapper

4.4 一键生成步骤

4.4.1 建表SQL
#注意,只提供了建表sql,要自己建立数据库。演示sql,无实际意义。
DROP TABLE IF EXISTS `t_pay`;

CREATE TABLE `t_pay` (
  `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  `pay_no` VARCHAR(50) NOT NULL COMMENT '支付流水号',
  `order_no` VARCHAR(50) NOT NULL COMMENT '订单流水号',
  `user_id` INT(10) DEFAULT '1' COMMENT '用户账号ID',
  `amount` DECIMAL(8,2) NOT NULL DEFAULT '9.9' COMMENT '交易金额',
  `deleted` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0' COMMENT '删除标志,默认0不删除,1删除',
  `create_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='支付交易表';

INSERT INTO t_pay(pay_no,order_no) VALUES('pay17203699','6544bafb424a');

SELECT * FROM t_pay;
4.4.2 建立generator模块

4.4.3 POM
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.atguigu.cloud</groupId>
        <artifactId>mscloudV5</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <!--我自己独一份,只是一个普通Maven工程,与boot和cloud无关-->
    <artifactId>mybatis_generator2024</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!--Mybatis 通用mapper tk单独使用,自己独有+自带版本号-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.13</version>
        </dependency>
        <!-- Mybatis Generator 自己独有+自带版本号-->
        <dependency>
            <groupId>org.mybatis.generator</groupId>
            <artifactId>mybatis-generator-core</artifactId>
            <version>1.4.2</version>
        </dependency>
        <!--通用Mapper-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
        </dependency>
        <!--mysql8.0-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--persistence-->
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <resources>
            <resource>
                <directory>${basedir}/src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
            <resource>
                <directory>${basedir}/src/main/resources</directory>
            </resource>
        </resources>
        <plugins>
            <!-- 该插件,在实际中无法使用,注释掉也没关系 -->
            <plugin>
                <>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.4.2</version>
                <configuration>
                    <configurationFile>${basedir}/src/main/resources/generatorConfig.xml</configurationFile>
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.33</version>
                    </dependency>
                    <dependency>
                        <groupId>tk.mybatis</groupId>
                        <artifactId>mapper</artifactId>
                        <version>4.2.3</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

</project>
4.4.4 配置

resource文件夹下

config.properties

#User表包名
package.name=com.atguigu.cloud
# mysql5.7
jdbc.driverClass = com.mysql.jdbc.Driver
jdbc.url= jdbc:mysql://localhost:3306/db2024?useUnicode=true&characterEncoding=UTF-8&useSSL=false
jdbc.user = root
jdbc.password =123456
#或
#t_pay表包名
package.name=com.atguigu.cloud
# mysql8.0
jdbc.driverClass = com.mysql.cj.jdbc.Driver
jdbc.url= jdbc:mysql://localhost:3306/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
jdbc.user = root
jdbc.password =123456

generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">

<generatorConfiguration>
    <properties resource="config.properties"/>
    <context id="Mysql" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <property name="beginningDelimiter" value="`"/>
        <property name="endingDelimiter" value="`"/>
        <plugin type="tk.mybatis.mapper.generator.MapperPlugin">
            <property name="mappers" value="tk.mybatis.mapper.common.Mapper"/>
            <property name="caseSensitive" value="true"/>
        </plugin>
        <jdbcConnection driverClass="${jdbc.driverClass}"
                        connectionURL="${jdbc.url}"
                        userId="${jdbc.user}"
                        password="${jdbc.password}">
        </jdbcConnection>
        <javaModelGenerator targetPackage="${package.name}.entities" targetProject="src/main/java"/>
        <sqlMapGenerator targetPackage="${package.name}.mapper" targetProject="src/main/java"/>
        <javaClientGenerator targetPackage="${package.name}.mapper" targetProject="src/main/java" type="XMLMAPPER"/>
        <table tableName="t_pay" domainObjectName="Pay">
            <generatedKey column="id" sqlStatement="JDBC"/>
        </table>
    </context>
</generatorConfiguration>
4.4.5 点击插件运行既可

5.通用Base工程构建

5.1 v1工程

cloud-provider-payment8001为例

5.1.1 微服务小口诀
  • 1.建module
  • 2.改POM
  • 3.写YML
  • 4.主启动
  • 5.业务类
5.1.2 步骤

建module

略,创建完成后,父工程pom文件会多一个

<modules>
        <module>generator</module> <!-- 生成代码模块-->
        <module>cloud-provider-payment8001</module> <!--本次新建模块名-->
    </modules>

改POM

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.atguigu.cloud</groupId>
        <artifactId>mscloudV5</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <artifactId>cloud-provider-payment8001</artifactId>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>


    <dependencies>
        <!--SpringBoot通用依赖模块-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--SpringBoot集成druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
        </dependency>
        <!-- Swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html -->
        <dependency>
            <groupId>org.springdoc</groupId>
            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
        </dependency>
        <!--mybatis和springboot整合-->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <!--Mysql数据库驱动8 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!--persistence-->
        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
        </dependency>
        <!--通用Mapper4-->
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper</artifactId>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
        </dependency>
        <!-- fastjson2 -->
        <dependency>
            <groupId>com.alibaba.fastjson2</groupId>
            <artifactId>fastjson2</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
            <scope>provided</scope>
        </dependency>
        <!--test-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <!--<build> 引用不到,略,后续pom文件,不再有该插件
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>-->

</project>

写yml

server:
  port: 8001

# ==========applicationName + druid-mysql8 driver===================
spring:
  application:
    name: cloud-payment-service

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    #连接的url替换为自己安装的端口好,和数据库
    url: jdbc:mysql://localhost:3306/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
    username: xxx 替换为自己账号
    password: xxx 替换为自己密码

# ========================mybatis===================
mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.atguigu.cloud.entities
  configuration:
    map-underscore-to-camel-case: true

主启动

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tk.mybatis.spring.annotation.MapperScan;

/**
 * @auther zzyy
 * @create 2023-11-03 17:54
 */
@SpringBootApplication
@MapperScan("com.atguigu.cloud.mapper") //import tk.mybatis.spring.annotation.MapperScan;
public class Main8001
{
    public static void main(String[] args)
    {
        SpringApplication.run(Main8001.class,args);
    }
}

业务类

5.1.3 测试

Swagger3常用注解

注解 标注位置 作用
@Tag Contoller类 标识Controller
@Paramter 参数 标识参数
@Paramters 参数 参数多重说明
@Schema Model层的JavaBean或DTO 描述模型作用及每个属性
@Operation 方法 描述方法作用
@ApiResponse 方法 描述响应状态码

举例

@Tag(name = "支付微服务模块", description = "支付CRUD")
public class PayController {
    
@Operation(summary = "新增", description = "新增支付流水方法,json串做参数")
public ResultData<String> addPay(@RequestBody Pay pay) {
    
@Schema(title = "支付交易表Entity")
public class Pay {
    
    /**
     * 订单流水号
     */
    @Schema(title = "订单流水号")
    private String orderNo;

配置类

import io.swagger.v3.oas.models.ExternalDocumentation;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Info;
import org.springdoc.core.models.GroupedOpenApi;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @auther zzyy
 * @create 2023-11-04 10:40
 */
@Configuration
public class Swagger3Config
{
    @Bean
    public GroupedOpenApi PayApi()
    {
        return GroupedOpenApi.builder().group("支付微服务模块").pathsToMatch("/pay/**").build();
    }
    @Bean
    public GroupedOpenApi OtherApi()
    {
        return GroupedOpenApi.builder().group("其它微服务模块").pathsToMatch("/other/**", "/others").build();
    }
    /*@Bean
    public GroupedOpenApi CustomerApi()
    {
        return GroupedOpenApi.builder().group("客户微服务模块").pathsToMatch("/customer/**", "/customers").build();
    }*/

    @Bean
    public OpenAPI docsOpenApi()
    {
        return new OpenAPI()
                .info(new Info().title("cloud2024")
                        .description("通用设计rest")
                        .version("v1.0"))
                .externalDocs(new ExternalDocumentation()
                        .description("www.atguigu.com")
                        .url("https://yiyan.baidu.com/"));
    }
}
5.1.4 上述模块存在的问题

1.时间格式

返回的时间格式不是yyyy-MM-dd HH:mm:ss

2.统一设计API接口实现统一格式返回

3 全局异常接入返回的标准格式

5.2 v2工程

5.2.1 解决时间格式问题

1.使用@JsonFormat注解

/**
 * 创建时间
 */
@Column(name = "create_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GBT+8")
private Date createTime;

/**
 * 更新时间
 */
@Column(name = "update_time")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GBT+8")
private Date updateTime;

2.Spring Boot项目,也可以在application.yml文件中指定:

#建议使用该方式
spring:  
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
5.2.2 解决统一返回值

思路:定义返回标准格式,三大标配:

  • code状态值:由后端统一定义各种返回结果的状态码。
  • message描述:本次接口调用结果的描述。
  • data数据:本次返回的数据。

扩展:接口调用时间:

  • timestamp:接口调用时间

新建枚举类

import java.util.Arrays;

public enum ReturnCodeEnum {
    /**
     * 操作失败
     **/
    RC999("999", "操作XXX失败"),
    /**
     * 操作成功
     **/
    RC200("200", "success"),
    /**
     * 服务降级
     **/
    RC201("201", "服务开启降级保护,请稍后再试!"),
    /**
     * 热点参数限流
     **/
    RC202("202", "热点参数限流,请稍后再试!"),
    /**
     * 系统规则不满足
     **/
    RC203("203", "系统规则不满足要求,请稍后再试!"),
    /**
     * 授权规则不通过
     **/
    RC204("204", "授权规则不通过,请稍后再试!"),
    /**
     * access_denied
     **/
    RC403("403", "无访问权限,请联系管理员授予权限"),
    /**
     * access_denied
     **/
    RC401("401", "匿名用户访问无权限资源时的异常"),
    RC404("404", "404页面找不到的异常"),
    /**
     * 服务异常
     **/
    RC500("500", "系统异常,请稍后重试"),
    RC375("375", "数学运算异常,请稍后重试"),

    INVALID_TOKEN("2001", "访问令牌不合法"),
    ACCESS_DENIED("2003", "没有权限访问该资源"),
    CLIENT_AUTHENTICATION_FAILED("1001", "客户端认证失败"),
    USERNAME_OR_PASSWORD_ERROR("1002", "用户名或密码错误"),
    BUSINESS_ERROR("1004", "业务逻辑异常"),
    UNSUPPORTED_GRANT_TYPE("1003", "不支持的认证模式");

    private final String code;

    private final String message;

    ReturnCodeEnum(String code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }

    public static ReturnCodeEnum getReturnCodeEnum(String code) {
        for (ReturnCodeEnum rce : ReturnCodeEnum.values()) {
            if (rce.getCode().equals(code)) {
                return rce;
            }
        }
        return null;
    }

    public static ReturnCodeEnum getReturnCodeEnumV2(String code) {
        return Arrays.stream(ReturnCodeEnum.values())
                .filter(r -> r.getCode().equals(code))
                .findFirst()
                .orElse(null);
    }
}

新建统一定义返回对象ResultData

import lombok.Data;
import lombok.experimental.Accessors;

@Data
@Accessors(chain = true)
public class ResultData<T> {

    private String code;
    private String message;
    private T data;

    private long timestamp;

    public ResultData(){
        this.timestamp = System.currentTimeMillis();
    }

    public static <T> ResultData<T> success(T data){
        ResultData<T> resultData = new ResultData<>();
        resultData.setCode(ReturnCodeEnum.RC200.getCode());
        resultData.setMessage(ReturnCodeEnum.RC200.getMessage());
        resultData.setData(data);
        return resultData;
    }

    public static <T> ResultData<T> fail(String code,String message){
        ResultData<T> resultData = new ResultData<>();
        resultData.setCode(code);
        resultData.setMessage(message);
        return resultData;
    }

}

修改PayController

测试

5.2.3 全局异常接入返回的标准格式

新建全局异常类

import com.atguigu.cloud.resp.ResultData;
import com.atguigu.cloud.resp.ReturnCodeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 默认全局异常处理
     * @param e
     * @return
     */
    @ExceptionHandler(RuntimeException.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public ResultData<String> exception(Exception e) {
        logger.error("----come in GlobalExceptionHandler");
        log.error("全局异常信息exception:{}", e.getMessage(), e);
        return ResultData.fail(ReturnCodeEnum.RC500.getCode(),e.getMessage());
    }

}

修改Controller

6.引入微服务概念

6.1 订单微服务,如何才能调用到支付微服务8001

6.2 新建cloud-consumer-order80

不过,80端口,是HTTP协议的默认端口,一般开启浏览器,都会占用,所以修改为其他的端口即可,这里模块名未做修改。

这里,建moudle,改pom,写yml,主启动,业务类,都略,只是记笔记,不能再将编码,都重复一变,见视频

记一下,其中的核心的东西

新建立了PayDTO,用以微服务间的数据传输的载体。

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.math.BigDecimal;

/**
 * @author 长名06
 * @year 2024
 * 一般而言,调用者不应该获悉服务提供者的entity资源并知道表结构关系,所以服务提供方给出的
 * 接口文档都都应成为DTO
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PayDTO implements Serializable {
    private Integer id;

    /**
     * 支付流水号
     */
    private String payNo;

    /**
     * 订单流水号
     */
    private String orderNo;

    /**
     * 用户账号ID
     */
    private Integer userId;

    /**
     * 交易金额
     */
    private BigDecimal amount;

}

6.3 RestTemplate

RestTemplate提供了多种便捷访问远程Http服务的方法, 是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集。

restful可以看作是一种构建思想,也可以看作,标记服务器资源的协议(约定可能更合适)。比如Post接口,一般都是新增,Get接口,是查询等,都是Restful的体现。

官网地址

使用restTemplate访问restful接口非常的简单粗暴无脑。

(url, requestMap, ResponseBean.class)这三个参数分别代表

REST请求地址、请求参数、HTTP响应转换被转换成的对象类型。

具体见官网API说明,这些东西,记不住,也正常。毕竟在计算机的世界里,要学的东西实在是太多了,学东西重要的是理解其思想。记不住就找笔记,或百度,问生成式AI都可以。

6.4 RestTemplate配置类

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

6.5 OrderController

import com.atguigu.cloud.dto.PayDTO;
import com.atguigu.cloud.resp.ResultData;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

@RestController
@RequestMapping("/consumer")
public class OrderController {

    public static final String PAYMENT_SRV_URL = "http://localhost:8001";//硬编码


    @Resource
    private RestTemplate restTemplate;

    /**
     * 一般情况下,通过浏览器的地址栏输入url,发送的只能是get请求
     * 我们底层调用的是post方法,模拟消费者发送get请求,客户端消费者
     * 参数可以不添加@RequestBody
     * @param payDTO
     * @return
     */
    @GetMapping("/pay/add")
    public ResultData addOrder(PayDTO payDTO){
        return restTemplate.postForObject(PAYMENT_SRV_URL + "/pay/add",payDTO,ResultData.class);
    }

    @GetMapping("/pay/get/{id}")
    public ResultData getPayInfo(@PathVariable("id") Integer id){
        return restTemplate.getForObject(PAYMENT_SRV_URL + "/pay/get/" + id,ResultData.class,id);
    }

    @DeleteMapping("/pay/delete/{id}")
    public void deletePay(@PathVariable("id") Integer id){
        restTemplate.delete(PAYMENT_SRV_URL + "/pay/delete/"+id);
    }

    @GetMapping("/pay/update")
    public void updatePay(PayDTO payDTO){
        restTemplate.put(PAYMENT_SRV_URL + "/pay/update",payDTO);
    }

}

测试略

6.6 工程重构

PayDTOResultDataReturnCodeEnum类提到common模块,打包到本地库,以及修改Order80,Pay8001的类和POM的修改,这些都略。

6.7 硬编码问题

微服务所在的IP地址和端口号硬编码到订单微服务中,会存在非常多的问题

  • (1)如果订单微服务和支付微服务的IP地址或者端口号发生了变化,则支付微服务将变得不可用,需要同步修改订单微服务中调用支付微服务的IP地址和端口号。
  • (2)如果系统中提供了多个订单微服务和支付微服务,则无法实现微服务的负载均衡功能。
  • (3)如果系统需要支持更高的并发,需要部署更多的订单微服务和支付微服务,硬编码订单微服务则后续的维护会变得异常复杂。

所以,在微服务开发的过程中,需要引入服务治理功能,实现微服务之间的动态注册与发现,从此刻开始我们正式进入SpringCloud实战。

只是为了记录自己的学习历程,且本人水平有限,不对之处,请指正。

请登录后发表评论

    没有回复内容