01-微服務1-3章的筆記

长名06發表於2024-09-26

前言

這是尚矽谷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的崛起


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說明


和老師保持一致,選擇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那些被移除了?


2019年進入Maintenance Mode。

維護模式,就是被動的修復bugs,不再接收合併請求,不再發布新版本。換句話說就是,除非出現特別嚴重的bug,否則沒人管了。

4.2.2 由停更引發的“升級慘案”


紅叉:不能再使用了;感嘆號:能用但是不推薦;對號:推薦使用。


備註,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實戰。

只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。

相關文章