视频参考链接:https://www.bilibili.com/video/BV1gW421P7RD/
1.1 项目实战之 Pay 支付微服务
首先配合 boot 实现基本的下订单-支付的功能,在逐个加入微服务的组件。在项目实战中要严格遵守约定>配置>编码
这一规定。

1.1.1 创建项目和 Maven 父工程
Maven 父工程只需要一个 pom.xml
文件,创建步骤如下所示。
打开 IDEA 软件,选择New Project
按钮,工程为 Maven ,JDK 版本为17。
字符编码设置为 UTF-8 ,选择左上角的"四条横线",选择设置(setting),接着在收缩框内输入"encoding",选择"File Encoding",将全部编码修改为UTF-8。

注解生效激活

Java 编译版本选17

File Type 过滤,该设置可操作也可不操作。

然后将pom.xml
文件内容填充完整。
xml
<?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</groupId>
<artifactId>cloud2024</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.30</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>
其中 dependencyManagement 与 dependency 的区别是,dependencyManagement 元素来提供了一种管理依赖版本号的方式。
通常会在一个组织或者项目的最顶层的父 POM 中看到 dependencyManagement 元素。
使用 pom.xml 中的 dependencyManagement 元素能让所有在子项目中引用一个依赖而不用显式的列出版本号。Maven 会沿着父子层次向上走,直到找到一个拥有 dependencyManagement 元素的项目,然后它就会使用这个 dependencyManagement 元素中指定的版本号。
这样做的好处就是:如果有多个子项目都引用同一样依赖,则可以避免在每个使用的子项目里都声明一个版本号,优势:
1 | 这样当想升级或切换到另一个版本时,只需要在顶层父容器里更新,而不需要一个一个子项目的修改 ; |
---|---|
2 | 另外如果某个子项目需要另外的一个版本,只需要声明 version 就可。 |
-
dependencyManagement 里只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖。(即不下载依赖,只有外层为 dependence 才会下载依赖)
-
如果不在子项目中声明依赖,是不会从父项目中继承下来的,只有在子项目中写了该依赖项并且没有指定具体版本,才会从父项目中继承该项且 version 和 scope 都读取自父 pom;
-
如果子项目中指定了版本号,那么会使用子项目中指定的jar版本。
1.1.2 Mapper 之一键生成
创建好项目后,即可开始 Mapper 的一键生成,本文采用 MyBatis 的 Mapper4,具体步骤如下所示。
相关链接网址:
- Mapper4 官网:https://github.com/abel553/Mapper
- Navicat for SQL 下载链接:
- Mapper5 官网:https://github.com/mybatis-mapper/mapper
-
在 SQL 软件 Navicat 中创建数据库名为 db2024 的数据库,然后创建表名为
t_pay
的表,具体 SQL 语句如下所示。sqlDROP 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;
-
创建普通 Maven 工程 mybatis-generater2024 ,具体操作如下。
首先右击父工程 cloud2024 ,选择 New 选项下的 Module 模块,选择图片中的选项,最后单机 Create 按钮即可创建成功。
-
子模块 mybatis-generater2024 创建好后,开始完善子模块的 pom.xml 文件,文件具体内容如下所示。注意:plugin 和 dependceManagement 包裹的依赖不会自动下载,只有单独由 dependces 包裹的依赖才会自行下载。
xml<?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</groupId> <artifactId>cloud2024</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>
-
在目录 src/main/resources 目录下新建文件 config.properties 和 generatorConfig.xml 配置文件,其中 config.properties 文件用于配置 MySQL 相关信息,generatorConfig.xml 用于配置自动生成 Mapper 相关信息。具体配置信息如下所示。
config.properties
properties#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 = root
generatorConfig.xml
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>
-
最后双击 Plugins 目录下的 mybatis-generator:generate 一键生成 entitle+mapper 接口和 xml 实现 SQL。具体步骤如下所示。
生成结果如下图所示。

1.1.3 Rest 通用 Base 工程构建
构建工程 cloud-provider-payment8001 微服务支付模块,实现支付功能。具体操作步骤如下所述。
1.1.3.1 支付项目构建过程
-
构建 module 模块,模块名为 cloud-provider-payment8001 ,首先右击 cloud2024 选择 module,输入如下图所示的信息即可创建微服务支付模块。并添加一个实体类 PayDTO。
javapackage com.atguigu.entities; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.math.BigDecimal; @Data @AllArgsConstructor @NoArgsConstructor public class PayDTO implements Serializable { private Integer id; private String payNo; private String orderNo; private Integer orderId; private BigDecimal amount; }
-
改写 pom 文件,该文件主要内容如下。
xml<?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</groupId> <artifactId>cloud2024</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> <version>8.0.33</version> </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> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
在 src/main/resources 目录下创建 application.yml 文件,并配置信息。具体配置内容如下所示。
ymlserver: port: 8001 # ==========applicationName + druid-mysql8 driver=================== spring: application: name: cloud-payment-service datasource: type: com.alibaba.druid.pool.DruidDataSource url: jdbc:mysql://localhost:3306/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true username: root password: root druid: driver-class-name: com.mysql.cj.jdbc.Driver # ========================mybatis=================== mybatis: mapper-locations: classpath:mapper/*.xml type-aliases-package: com.atguigu.entities configuration: map-underscore-to-camel-case: true
-
修改类 Main 为 Main8001,然后将其更改为应用类。具体代码如下所示。
javapackage com.atguigu; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import tk.mybatis.spring.annotation.MapperScan; @SpringBootApplication @MapperScan("com.atguigu.mapper") public class Main8001 { public static void main(String[] args) { SpringApplication.run(Main8001.class, args); } }
-
将业务类补充完整。具体操作如下。
-
首先将生成的 Mapper 相关内容复制到同包位置,将 mapper 目录的 xml 文件复制到 resources 目录下的 mapper 文件中。具体操作如下所示。
-
业务逻辑层 service ,主要包含接口 PayService 和 impl 包下的 实现类 PayServiceImpl。具体代码如下所示。
PayService:
javapackage com.atguigu.service; import com.atguigu.entities.Pay; import com.atguigu.mapper.PayMapper; import com.atguigu.service.impl.PayServiceImpl; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import java.util.List; @Service public class PayService implements PayServiceImpl { @Resource private PayMapper payMapper; @Override public int add(Pay pay) { return payMapper.insertSelective(pay); } @Override public int delete(Integer id) { return payMapper.deleteByPrimaryKey(id); } @Override public int update(Pay pay) { return payMapper.updateByPrimaryKeySelective(pay); } @Override public Pay getById(Integer id) { return payMapper.selectByPrimaryKey(id); } @Override public List<Pay> getAll() { return payMapper.selectAll(); } }
PayServiceImpl:
javapackage com.atguigu.service.impl; import com.atguigu.entities.Pay; import java.util.List; // 实现增删改查的接口 public interface PayServiceImpl { public int add(Pay pay); public int delete(Integer id); public int update(Pay pay); public Pay getById(Integer id); public List<Pay> getAll(); }
-
1.1.3.2 支付项目调试
1.1.3.2.1 PostMan 测试
-
添加记录测试
通过输入以下代码添加支付记录,具体代码如下所示。
json{ "payNo": "17204076", "orderNo": "6544de1c424a", "userId": "2", "amount": "19.90" }
-
删除记录测试
通过输入路径参数 id,删除指定的记录。输入
http://localhost:8001/pay/del/2
并发送删除记录。 -
更新记录测试
-
通过属性 id 查询数据
-
查询全部数据
1.1.3.2.2 Swagger3 测试
前置条件,在 pom.xml 文件中导入如下依赖。
xml
<!-- Swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html -->
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
</dependency>
知识点:详细情况见SpringCloud第3季2024.html-工程v1测试

1.1.3.3 优化项目
1.1.3.3.1 统一时间格式
统一时间格式有两种方案,第一种是通过注解@JsonFormat
统一,第二种是通过 application.yml 配置文件统一,本节通过注解方式统一格式问题。
**方案1:**在数据访问层对应时间属性上添加注解@JsonFormate
java
@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
**方案2:**在 SpringBoot 项目的配置文件 application.yml 中也可以配置格式
yml
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
timezone: GMT+8
1.1.3.3.2 统一返回值
定义返回标准格式有3大标配和一个扩展,具体内容如下所示。
-
code 状态值:由后端统一定义各种格式的状态码。
-
message 描述:错误状态码的描述信息。
-
data 数据:返回数据。
-
timestamp 时间戳:接口调用时间。
**新建枚举类 ReturnCodeEnum:**举值-构造-遍历
java
package com.atguigu.resp;
import lombok.Getter;
import java.util.Arrays;
// 举值-构造-遍历
@Getter
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 static ReturnCodeEnum getReturnCodeEnumV1(String code) {
for (ReturnCodeEnum element:ReturnCodeEnum.values()) {
if (element.getCode().equalsIgnoreCase(code)) {
return element;
}
}
return null;
}
// 流处理
public static ReturnCodeEnum getReturnCodeEnumV2(String code) {
return Arrays.stream(ReturnCodeEnum.values())
.filter(x -> x.getCode().equalsIgnoreCase(code))
.findFirst().orElse(null);
}
}
新建统一返回对象 ResultData:
java
package com.atguigu.resp;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain=true) //链式写法
public class ResultData <T>{
private String code;
private String messsage;
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.setMesssage(ReturnCodeEnum.RC200.getMessage());
resultData.setData(data);
return resultData;
}
public static <T> ResultData<T> fail(String code,String messsage){
ResultData<T> resultData = new ResultData<>();
resultData.setCode(code);
resultData.setMesssage(messsage);
return resultData;
}
}
修改 PayController 控制类:
java
package com.atguigu.controller;
import com.atguigu.entities.Pay;
import com.atguigu.entities.PayDTO;
import com.atguigu.resp.ResultData;
import com.atguigu.service.impl.PayServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/pay")
public class PayController {
@Resource
private PayServiceImpl payService;
@PostMapping("/add")
public ResultData<String> addPay(@RequestBody Pay pay) {
System.out.println(pay.toString());
int i = payService.add(pay);
return ResultData.success("成功插入记录,返回:"+i);
}
@DeleteMapping("/del/{id}")
public ResultData<Integer> deletePay(@PathVariable("id") Integer id) {
return ResultData.success(payService.delete(id));
}
@PutMapping("/update")
public ResultData<String> updatePay(@RequestBody PayDTO payDYO) {
Pay pay = new Pay();
BeanUtils.copyProperties(payDYO, pay);
int i = payService.update(pay);
return ResultData.success("成功修改记录,返回:"+i);
}
@GetMapping("/get/{id}")
public ResultData<Pay> getPay(@PathVariable("id") Integer id) {
return ResultData.success(payService.getById(id));
}
@GetMapping("/get")
public ResultData<List<Pay>> getAll() {
return ResultData.success(payService.getAll());
}
}
**测试:**请参考1.1.3.2
1.1.3.3.3 全局异常处理
由于支付微服务没有异常处理,所以需要添加异常处理机制。异常处理机制有两种方式,分别是全局异常处理器、try-catch-finaly。
全局异常处理器类 GlobalExceptionHandler:
java
package com.atguigu.exp;
import com.atguigu.resp.ResultData;
import com.atguigu.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 {
@ExceptionHandler(RuntimeException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResultData<String> Exception(Exception e){
System.out.println("-----come in GlobalExceptionHandler-----");
log.error("全局异常信息:{}",e.getMessage(),e);
return ResultData.fail(ReturnCodeEnum.RC500.getCode(), e.getMessage());
}
}
异常处理PayController:
java
package com.atguigu.controller;
import com.atguigu.entities.Pay;
import com.atguigu.entities.PayDTO;
import com.atguigu.resp.ResultData;
import com.atguigu.resp.ReturnCodeEnum;
import com.atguigu.service.impl.PayServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/pay")
public class PayController {
@Resource
private PayServiceImpl payService;
@PostMapping("/add")
public ResultData<String> addPay(@RequestBody Pay pay) {
System.out.println(pay.toString());
int i = payService.add(pay);
return ResultData.success("成功插入记录,返回:"+i);
}
@DeleteMapping("/del/{id}")
public ResultData<Integer> deletePay(@PathVariable("id") Integer id) {
return ResultData.success(payService.delete(id));
}
@PutMapping("/update")
public ResultData<String> updatePay(@RequestBody PayDTO payDYO) {
Pay pay = new Pay();
BeanUtils.copyProperties(payDYO, pay);
int i = payService.update(pay);
return ResultData.success("成功修改记录,返回:"+i);
}
@GetMapping("/get/{id}")
public ResultData<Pay> getPay(@PathVariable("id") Integer id) {
if(id==-4) throw new RuntimeException("id不能为负数");
return ResultData.success(payService.getById(id));
}
@GetMapping("/get")
public ResultData<List<Pay>> getAll() {
return ResultData.success(payService.getAll());
}
@RequestMapping(value = "/error",method = RequestMethod.GET)
public ResultData<Integer> error() {
Integer i=Integer.valueOf(200);
try {
System.out.println("-----come here");
int data=10/0;
}catch (Exception e){
e.printStackTrace();
return ResultData.fail(ReturnCodeEnum.RC500.getCode(), e.getMessage());
}
return ResultData.success(i);
}
}
整体目录结构如下所示。

1.1.4 订单微服务80 调用支付微服务8001
1.1.4.1 构建订单微服务80模块 cloud-consumer-order80
-
创建模块 cloud-consumer-order80
首先右击 cloud2024 选择 Module 模块,输入如下属性即可创建订单微服务。
-
改 pom.xml 文件
在 pom 文件输入以下内容。
xml<?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</groupId> <artifactId>cloud2024</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>cloud-consumer-order80</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> <!--web + actuator--> <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> <!--lombok--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--hutool-all--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> </dependency> <!--fastjson2--> <dependency> <groupId>com.alibaba.fastjson2</groupId> <artifactId>fastjson2</artifactId> </dependency> <!-- swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html --> <dependency> <groupId>org.springdoc</groupId> <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
-
写 yml 文件
在 src/main/resourcs 目录下创建 application.yml 文件,并输入以下内容。
ymlserver: port: 80
-
主启动类设置
将主启动类 Main 更改为Main80。
javapackage com.atguigu; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class Main80 { public static void main(String[] args) { SpringApplication.run(Main80.class, args); } }
-
业务类设置
**entities:**构造PayDTO类
javapackage com.atguigu.entities; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; import java.math.BigDecimal; @Data @AllArgsConstructor @NoArgsConstructor public class PayDTO implements Serializable { private Integer id; private String payNo; private String orderNo; private Integer userId; private BigDecimal amount; }
**ResulData:**直接将支付微服务部分粘贴过来,本节将不在写代码。
RestTemplate:
RestTemplate提供了多种便捷访问远程Http服务的方法, 是一种简单便捷的访问restful服务模板类,是Spring提供的用于访问Rest服务的客户端模板工具集。RestTemplate官网地址。
RestTemplate常用API 使用说明:
使用restTemplate访问restful接口非常的简单粗暴无脑。(url, requestMap, ResponseBean.class)这三个参数分别代表 REST 请求地址、请求参数、HTTP响应转换被转换成的对象类型。
GET 请求方法:用于查询数据,参数
("支付微服务url",返回值类型.class,传递参数,如无传递参数最后一个参数才可不写)
txt<T> T getForObject(String url, Class<T> responseType, Object... uriVariables); <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables); <T> T getForObject(URI url, Class<T> responseType); <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables); <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables); <T> ResponseEntity<T> getForEntity(URI var1, Class<T> responseType);
POST 请求方法:用于更新、删除、添加数据,参数
("支付微服务url",传递参数,返回值类型.class)
txt<T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables); <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables); <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType); <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables); <T> ResponseEntity<T> postForEntity(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables); <T> ResponseEntity<T> postForEntity(URI url, @Nullable Object request, Class<T> responseType);
**config 配置类:**在 config 目录下创建配置类 RestTemplateConfig
javapackage com.atguigu.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class RestTemplateConfig { @Bean public RestTemplate restTemplate(){ return new RestTemplate(); } }
controller 控制层:
javapackage com.atguigu.controller; import com.atguigu.entities.PayDTO; import com.atguigu.resp.ResultData; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/consumer/pay") public class OrderController { public static final String PAYMENTSRV_URL = "http://localhost:8001"; @Resource private RestTemplate restTemplate; @GetMapping("/add") public ResultData addOrder(PayDTO payDTO){ return restTemplate.postForObject(PAYMENTSRV_URL+"/pay/add",payDTO,ResultData.class); } @GetMapping("/del/{id}") public ResultData deletePayInfo(@PathVariable("id") Integer id){ return restTemplate.postForObject(PAYMENTSRV_URL+"/del/"+id,id,ResultData.class); } @GetMapping("/update/") public ResultData updatePayInfo(PayDTO payDTO){ return restTemplate.postForObject(PAYMENTSRV_URL+"/update/",payDTO,ResultData.class); } @GetMapping("/get/{id}") public ResultData getPayInfo(@PathVariable("id") Integer id){ return restTemplate.getForObject(PAYMENTSRV_URL+"/get/"+id,ResultData.class,id); } @GetMapping("/get/") public ResultData getPayAllInfo(){ return restTemplate.getForObject(PAYMENTSRV_URL+"/get/",ResultData.class); } }
-
测试
首先启动订单微服务(Main80.class)和支付微服务(Main8001.class),然后点击"Service"图标选择 "Add Service"中的SpringBoot 将两个微服务放在一起。具体操作如下所示。

操作完成之后即可打开 Postman 测试工具进行测试。
请输入http://localhost/consumer/pay/get/1
、http://localhost/consumer/pay/del/5
、http://localhost/consumer/pay/update?id=1&payNo=1314&orderNo=1213&userId=2&account=3.33
和http://localhost/consumer/pay/add?payNo=1213&orderNo=1213&userId=2&account=3.33
进行查询、删除、更新和添加测试。
1.1.4.2 优化项目
这部分是工程重构的部分,有部分功能是共用的,为避免重复编写代码将其封装到一个通用的模块中,并进行 install
安装成 jar 包,并在需要的模块中引入坐标。
-
新建通用模块 cloud-api-commons
-
改写 pom.xml 文件
xml<?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</groupId> <artifactId>cloud2024</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>cloud-api-commons</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> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!--hutool--> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> </dependency> </dependencies> </project>
-
引入通用部分内容和全局异常处理器
-
安装通用工具包,需要先 clean 在 install。由于父工程的lombok 版本1.8.26太低,需要升级版本到1.8.30版本及以上。
-
删除订单80和支付8001中重复部分的内容,并引入步骤4打包的工具包的坐标
xml<!--自定义依赖--> <dependency> <groupId>com.atguigu</groupId> <artifactId>cloud-api-commons</artifactId> <version>1.0-SNAPSHOT</version> </dependency>
只保留如下图所示的图片。
-
测试
测试与1.1.4.1测试一致,此处不在赘述。
1.1.5 项目实战存在的问题

微服务所在的IP地址和端口号硬编码到订单微服务中,会存在非常多的问题
(1)如果订单微服务和支付微服务的IP地址或者端口号发生了变化,则支付微服务将变得不可用,需要同步修改订单微服务中调用支付微服务的IP地址和端口号。
(2)如果系统中提供了多个订单微服务和支付微服务,则无法实现微服务的负载均衡功能。
(3)如果系统需要支持更高的并发,需要部署更多的订单微服务和支付微服务,硬编码订单微服务则后续的维护会变得异常复杂。
所以,在微服务开发的过程中,需要引入服务治理功能,实现微服务之间的动态注册与发现,从此刻开始我们正式进入SpringCloud实战