一、Spring Cloud(Base工程构建)

一、Spring Cloud(Base工程构建)

1.1 Spring Cloud 简述

1.1.1 Spring Cloud 版本推荐

  • 在讲解 Spring Cloud 之前,首先推荐一下各个依赖的版本,以免出现版本错误

  • 版本推荐

  • 必须根据以上版本,否则可能会出现一些不必要的错误

1.1.2 Spring Cloud 能做什么

  • 它是一种微服务架构的工具包
  • 可以帮助服务找到其他服务并互相连接
  • 能集中管理服务的设置信息
  • 有熔断和限流的功能,让系统更稳定
  • 可以把请求分摊到不同的服务实例上
  • 处理多个服务间的事务问题
  • 能监控服务的状态和性能

1.2.3 Spring Cloud 不同功能对应的不同的组件

Spring Cloud 可以用于实现很多功能,方便我们开发

这些功能都对应着Spring Cloud 中的不同的组件

以下是不同服务分别对应的组件

image-20240314133910116

1.2 微服务架构编码 Base 工程模块构建

这边我们直接使用项目来了解微服务

通过 下订单,做支付这个案例

先做 Base 工程,再依次添加各种模块组件

先简单的做一个通用的 boot微服务

然后逐步挨个引入 cloud 组件纳入微服务支撑体系

1.2.1 微服务 cloud 整体聚合 maven 父工程 Project

1、New Project

  • 新建项目,请按照我一下的配置进行创建

  • image-20240319172632663

  • 将这些多余的包删除,这个仅仅是作为我们 maven 的父工程

  • image-20240316104535170

2、聚合总父工程的名字

  • 这个就是父工程的名字
  • image-20240319172720836

3、字符编码

  • 设置字符编码为 UTF-8 ,以防出现乱码

  • image-20240316104839525

  • image-20240316105005801

4、注解激活生效

  • 当引入一些新的组件时,可能会激活不了,所以需要设置

  • image-20240316105236102

5、java 编译版本选择 17

  • image-20240316105338006

1.2.2 Maven 父工程 pom 文件内容

  • 在 maven 中添加 <packaging>pom</packaging>

  • 表示该项目作为一个父工程,用于组织和管理其他子项目的依赖关系、版本控制等

  • image-20240319172921463

  • 将以下依赖和版本复制进 pom文件中

  •  <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.3</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>
    
  • <properties> 标签内的是依赖的版本号

    • 这样分开写版本号,是为了在子工程中添加依赖时,如果依赖没有添加版本号,则会直接使用父工程的版本
    • 更好的实现版本的统一
  • <dependencyManagement> 标签来提供一种管理依赖版本号的方式

    • 一般都会在 pom 父工程中使用
    • 它能够让所有子工程中不用显示的列出版本号
    • 因为 maven 会沿着父子层向上走,直接找到拥有 <dependencyManagement> 元素的项目
    • 然后子工程就会使用 <dependencyManagement> 元素中指定的版本号
    • 可以避免每个子项目中都要引入一个版本号
    • 如果子项目需要另外一个版本,只需要声明 <version> 即可
  • <dependencyManagement> 只是声明依赖,并不实现引入,因此子项目需要显示的声明需要用的依赖

  • 如果不在子项目中声明依赖,是不会从父项目中继承下来的

  • 只有在子项目中写了该依赖,并没没有指定版本号,才会从父项目中该项

1.2.3 Mysql 驱动说明

1、如果是 Mysql5

  • JDBC 配置

  • # 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
    
  • pom 文件依赖

  • # Maven的POM文件处理
    <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version>
    </dependency>

2、如果是 Mysql8

  • JDBC 配置

  • # 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
    
  • pom 文件依赖

  • # MavenPOM
    <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.11</version>
    </dependency>
    

1.3 Mapper4 一键生成增删改查

1.3.1 数据库搭建

  • 生成增删改查代码之前,首先需要我们的 支付订单的数据库

  • 首先创建数据库,数据库名为 db2024

  • 然后创建数据表,将以下代码导入即可

  • 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;
    

1.3.2 在项目中创建第一个子工程

  • 创建一个子工程名为 mybatis_generator2024

  • 它与业务无关,就是一个普通的 maven 工程

  • 有他专门生成数据库的增删改查

  • image-20240316145005493

  • image-20240319173105684

  • 在子工程中导入这个模块所需的依赖

  • 复制替换子工程的 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>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>
    

1.3.3 设置各种配置

  • 这里需要设置数据库配置和生成增删改查的配置

  • 创建 config.properties 数据库配置文件

  • image-20240316150415056

  • #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
    
  • 创建自动生成配置文件 generatorConfig.xml

  • image-20240316150659251

  • <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE generatorConfigurationPUBLIC "-//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>
    

1.3.4 一键生成增删改查

  • image-20240316150921837

  • 打开 pom 管理,找到 mybatis_generator2024 的模块,点击 mybatis-genertor:generate 即可一键生成

1.4 标准构建微服务工程

完整构建微服务的步骤

1、建 module 模块

2、改写 pom 文件

3、写 yml,启动类配置

4、创建主启动类

5、创建业务类

首先构建一个微服务的提供者,支付 Module 模块

1.4.1 构建提供者微服务模块

  • 提供者模块名为 cloud-provider-payment8001

  • image-20240316155909923

1.4.2 改写 pom 文件

  • 改写 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>org.atguigu.com</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></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>
    

1.4.3 编写 yml 文件,启动类配置

  • 编写 yml 文件,启动类的配置

  • server:port: 8001# ==========applicationName + druid-mysql8 driver===================
    spring:application:name: cloud-payment-servicedatasource:type: com.alibaba.druid.pool.DruidDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/db2024?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=trueusername: rootpassword: 123456# ========================mybatis===================
    mybatis:mapper-locations: classpath:mapper/*.xmltype-aliases-package: com.atguigu.cloud.entitiesconfiguration:map-underscore-to-camel-case: true
    
  • 并且创建一个 mapper 包

  • image-20240316160521841

1.4.4 创建主启动类

  • 创建主启动类,命名为 Main8001

  • image-20240319004538330

  • 添加 @MapperScan 注解

  • image-20240321184139430

  • 注意不要导错包

1.4.5 创建业务类

1、entities(实体类)

  • 创建两个实体 Pay 和 PayDTO

    • Pay 是主实体类
    • PayDTO 是给前端传递数据用的实体类
    • PayDTO 内的属性是前端传给后端的数据
  • Pay 实体类直接复制 mybatis-generator2024 模块内自动生成的实体类即可

  • image-20240316162034838

  • 然后创建 PayDTO 传递数据实体类

  • package com.atguigu.cloud.entities;import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;import java.math.BigDecimal;@Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class PayDTO {private Integer id;//支付流水号private String payNo;//订单流水号private String orderNo;//用户账号IDprivate Integer userId;//交易金额private BigDecimal amount;
    }
  • image-20240316162249475

2、mapper

  • 分别在 cloud 包下和 resources 包下创建 mapper 包

  • cloud 包下的 mapper 包存放接口

  • resources 包下的 mapper 存放 xml 文件

  • 也是同样复制 mybatis-generator2024 模块内自动生成的 mapper即可

  • image-20240316162628408

  • image-20240316162934370

3、Service

  • 创建服务接口 PayService,定义增删改查方法

  • image-20240316163741669

  • package com.atguigu.cloud.service;import com.atguigu.cloud.entities.Pay;import java.util.List;public interface PayService {//增public int add(Pay pay);//根据id删public int delete(Integer id);//改public int update(Pay pay);//根据id查public Pay getById(Integer id);//查询所有public List<Pay> getAll();
    }
    • 创建服务实现类 PayServiceImpl,实现增删改查方法
  • image-20240316164349748

  • package com.atguigu.cloud.service.impl;import com.atguigu.cloud.entities.Pay;
    import com.atguigu.cloud.mapper.PayMapper;
    import com.atguigu.cloud.service.PayService;
    import jakarta.annotation.Resource;
    import org.springframework.stereotype.Service;import java.util.List;@Service
    public class PayServiceImpl implements PayService {@ResourcePayMapper payMapper;@Overridepublic int add(Pay pay) {return payMapper.insertSelective(pay);}@Overridepublic int delete(Integer id) {//按照主键删除return payMapper.deleteByPrimaryKey(id);}@Overridepublic int update(Pay pay) {//按照主键,主键不为空则更新return payMapper.updateByPrimaryKeySelective(pay);}@Overridepublic Pay getById(Integer id) {//根据主键查return payMapper.selectByPrimaryKey(id);}@Overridepublic List<Pay> getAll() {return payMapper.selectAll();}
    }

4、controller

  • 创建 PayController

  • image-20240318234657424

  • PayController 代码部分

  • package com.atguigu.cloud.controller;import cn.hutool.core.bean.BeanUtil;
    import com.atguigu.cloud.entities.Pay;
    import com.atguigu.cloud.entities.PayDTO;
    import com.atguigu.cloud.service.PayService;
    import jakarta.annotation.Resource;
    import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
    public class PayController {@Resourceprivate PayService payService;@PostMapping("/pay/add")public String addPay(@RequestBody Pay pay){int add = payService.add(pay);return "添加成功,返回值"+add;}@DeleteMapping("/pay/delete/{id}")public Integer removePay(@PathVariable("id") Integer id){return payService.delete(id);}@PutMapping("/pay/update")public String updatePay(@RequestBody PayDTO payDTO){Pay pay=new Pay();BeanUtil.copyProperties(payDTO,pay);int i=payService.update(pay);return "修改成功,返回值"+i;}@GetMapping("pay/get/{id}")public Pay getById(@PathVariable("id") Integer id){return payService.getById(id);}@GetMapping("pay/getAll")public List<Pay> getAll(){return payService.getAll();}
    }

1.5 Swagger3 代码测试

Swagger3 是一个用于测试接口的框架

使用 Swagger3 之前需要导入一个依赖

 <!-- Swagger3 调用方式 http://你的主机IP地址:5555/swagger-ui/index.html --><dependency><groupId>org.springdoc</groupId><artifactId>springdoc-openapi-starter-webmvc-ui</artifactId></dependency>

1.5.1 Swagger3 常用注解

  • 使用 Swagger3 需要在代码中嵌入注解

  • 以下是常用注解

  • 注解标注位置作用
    @Tagcontroller 类表示 controller 的作用
    @Parmeter参数标识参数作用
    @Parmeters参数参数多重说明
    @Schemamodel 层的 JavaBena描述模型作用及每个属性
    @Operation方法描述方法的作用
    @ApiResponse方法描述响应状态码等
    @Schema实体类或实体类字段描述实体类或实体类字段的作用
  • 在我们编写的 PayController 中加入注解

  • package com.atguigu.cloud.controller;import cn.hutool.core.bean.BeanUtil;
    import com.atguigu.cloud.entities.Pay;
    import com.atguigu.cloud.entities.PayDTO;
    import com.atguigu.cloud.service.PayService;
    import io.swagger.v3.oas.annotations.Operation;
    import io.swagger.v3.oas.annotations.tags.Tag;
    import jakarta.annotation.Resource;
    import org.springframework.beans.BeanUtils;
    import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
    @Tag(name = "支付微服务模块",description = "支付CRUD")
    public class PayController {@ResourcePayService payService;@PostMapping(value = "/pay/add")@Operation(summary = "新增", description = "新增支付流水方法,json串做参数")public String addPay(@RequestBody Pay pay) {System.out.println(pay.toString());int i = payService.add(pay);return "成功插入记录,返回值:" + i;}@DeleteMapping(value = "/pay/del/{id}")@Operation(summary = "删除", description = "删除支付流水方法")public Integer deletePay(@PathVariable("id") Integer id) {return payService.delete(id);}@PutMapping(value = "/pay/update")@Operation(summary = "修改", description = "修改支付流水方法")public String updatePay(@RequestBody PayDTO payDTO) {Pay pay = new Pay();BeanUtils.copyProperties(payDTO, pay);int i = payService.update(pay);return "成功修改记录,返回值:" + i;}@GetMapping(value = "/pay/get/{id}")@Operation(summary = "按照ID查流水", description = "查询支付流水方法")public Pay getById(@PathVariable("id") Integer id) {return payService.getById(id);}
    }
    
  • 在我们的实体类 Pay 中添加注解,描述实体类及字段的作用

  • package com.atguigu.cloud.entities;import io.swagger.v3.oas.annotations.media.Schema;import javax.persistence.Column;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import java.math.BigDecimal;
    import java.util.Date;/*** 表名:t_pay
    */
    @Table(name = "t_pay")
    @Schema(title = "支付交易表")
    public class Pay {@Id@GeneratedValue(generator = "JDBC")private Integer id;/*** 支付流水号*/@Column(name = "pay_no")@Schema(title = "支付流水号")private String payNo;/*** 订单流水号*/@Column(name = "order_no")@Schema(title = "订单流水号")private String orderNo;/*** 用户账号ID*/@Column(name = "user_id")@Schema(title = "用户账号ID")private Integer userId;/*** 交易金额*/private BigDecimal amount;/*** 删除标志,默认0不删除,1删除*/private Byte deleted;/*** 创建时间*/@Column(name = "create_time")@Schema(title = "创建时间")private Date createTime;/*** 更新时间*/@Column(name = "update_time")@Schema(title = "更新时间")private Date updateTime;/*** @return id*/public Integer getId() {return id;}/*** @param id*/public void setId(Integer id) {this.id = id;}/*** 获取支付流水号** @return payNo - 支付流水号*/public String getPayNo() {return payNo;}/*** 设置支付流水号** @param payNo 支付流水号*/public void setPayNo(String payNo) {this.payNo = payNo;}/*** 获取订单流水号** @return orderNo - 订单流水号*/public String getOrderNo() {return orderNo;}/*** 设置订单流水号** @param orderNo 订单流水号*/public void setOrderNo(String orderNo) {this.orderNo = orderNo;}/*** 获取用户账号ID** @return userId - 用户账号ID*/public Integer getUserId() {return userId;}/*** 设置用户账号ID** @param userId 用户账号ID*/public void setUserId(Integer userId) {this.userId = userId;}/*** 获取交易金额** @return amount - 交易金额*/public BigDecimal getAmount() {return amount;}/*** 设置交易金额** @param amount 交易金额*/public void setAmount(BigDecimal amount) {this.amount = amount;}/*** 获取删除标志,默认0不删除,1删除** @return deleted - 删除标志,默认0不删除,1删除*/public Byte getDeleted() {return deleted;}/*** 设置删除标志,默认0不删除,1删除** @param deleted 删除标志,默认0不删除,1删除*/public void setDeleted(Byte deleted) {this.deleted = deleted;}/*** 获取创建时间** @return createTime - 创建时间*/public Date getCreateTime() {return createTime;}/*** 设置创建时间** @param createTime 创建时间*/public void setCreateTime(Date createTime) {this.createTime = createTime;}/*** 获取更新时间** @return updateTime - 更新时间*/public Date getUpdateTime() {return updateTime;}/*** 设置更新时间** @param updateTime 更新时间*/public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}
    }
    

1.5.2 创建迭代的 config 配置类

  • 使用 Swagger3 之前还需要创建含分组迭代的 config 配置类

  • 因此我们需要创建一个 Swagger3 相关的配置类

  • image-20240319002438753

  • 编写相关代码

  • package com.atguigu.cloud.config;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;@Configuration
    public class Swagger3Config {@Beanpublic GroupedOpenApi PayApi(){return GroupedOpenApi.builder().group("支付微服务模块").pathsToMatch("/pay/**").build();}@Beanpublic GroupedOpenApi OtherApi(){return GroupedOpenApi.builder().group("其它微服务模块").pathsToMatch("/other/**", "/others").build();}@Beanpublic 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/"));}
    }
  • 我们微服务的接口会有很多,这个配置类就是专门进行了分组

  • 例如

  • image-20240319002706013

  • 这两个方法分别对应两个不同的模块

    • PayApi() 对应支付模块
    • OtherApi() 对应其他模块
  • PayApi() 方法中调用的 PathsToMatch() 方法当中的参数 /pay/** 就表示,只要开头为 /pay 的都属于这个模块

  • docsOpenApi() 方法中的内容则是对文档的一些说明

1.5.3 使用 Swagger3 进行测试

  • 运行启动类

  • 然后打开浏览器输入网址:http://localhost:8001/swagger-ui/index.html

  • 成功访问的界面

  • image-20240319005405605

  • 此时右上角就是你在配置类中定义的分组

  • image-20240319184525905

  • 这里进行测试即可

1.6 微服务工程项目改进

1.6.1 时间格式问题优化

  • 测试代码时,返回给我们的时间格式不是我们常用的类型

  • 这里我们可以使用两种方式来进行优化

1、在相应的类的属性上使用 @JsonFormat 注解

  • 在实体类的时间格式的属性上添加 @JsonFormat
  • image-20240322144814532

2、在 Spring boot 项目中还可以在 application.yml 文件中指定

  • 在 application.yml 文件中指定如下

  • spring:jackson:date-format: yyyy-MM-dd HH:mm:sstime-zone:GMT+8
    

这里才是返回了我们想要的时间格式

image-20240322145103253

1.6.2 统一返回值格式

1、具体思路

  • 我们需要封装一个对象,给前端返回一个 KV 键值对

  • 定义返回的标准格式(三大标配)

    • code 状态值:由后端统一定义各种返回结果的状态码
    • message描述:本次接口调用的结果描述
    • data数据:本次返回的数据
    • code 和 message 就是我们的 key 值
    • data 就是我们的 value 值
  • 定义接口调用时间之类

    • 用于排查错误
    • 告诉程序员什么时候调用接口
    • 第几次调用接口,什么时间段出的故障
    • 这就会添加 timestamp :接口调用时间

2、主要步骤

  • 新建枚举类 ReturnCodeEnum

  • 让我们的状态码尽量与 HTTP 的相对应

  • HTTP 请求返回的状态码

  • image-20240322150233960

  • 定义 ReturnCodeEnum 枚举类

  • image-20240322151405544

  • 具体代码

  • package com.atguigu.cloud.resp;import lombok.Getter;import java.util.Arrays;
    /*** @auther zzyy* @create 2023-11-04 11:51*/
    @Getter
    public enum ReturnCodeEnum {/**1.举值**//**操作失败**/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;}/**遍历**///遍历枚举V1public static ReturnCodeEnum getReturnCodeEnum(String code){for (ReturnCodeEnum element:ReturnCodeEnum.values()) {if (element.code.equals(code)){return element;}}return null;}//遍历枚举V2public static ReturnCodeEnum getReturnCodeEnumV2(String code){return Arrays.stream(ReturnCodeEnum.values()).filter(x -> x.getCode().equalsIgnoreCase(code)).findFirst().orElse(null);}/*public static void main(String[] args){System.out.println(getReturnCodeEnumV2("200"));System.out.println(getReturnCodeEnumV2("200").getCode());System.out.println(getReturnCodeEnumV2("200").getMessage());}*/
    }

3、如何定义一个通用的枚举类

  • 这里主要讲解一下我们定义枚举的三个小步骤

  • 举值-构造-遍历

  • 举值

    • 罗列出你的枚举值每一个 code 对应的 message 分别是什么

    • 例如我们上面的代码中

    • 第一个举值 RC999

    • image-20240322151822444

    • 在这个枚举里面,第一个举值 999

    • 对应的 message 就是 操作失败

  • 构造

    • 我们的枚举是有两个具体的值
    • 所以在构造上面我们就要创建有两个参数的构造函数
    • 这个就叫做构造
    • image-20240322152116475
  • 遍历

    • 我们需要遍历我们的枚举
    • 根据我们传过来的 code 状态码,来返回所需要的枚举
    • 如果没有找到对应的枚举,就需要返回一个 null
    • 我们这里遍历枚举用了两种方法
    • image-20240322152339441

4、新建统一返回对象 ResultData

  • 新建类 ResultData

  • image-20240322153349457

  • 添加四个变量 codemessagedatatimestamp

  • 在构造函数中,给 timestamp 设置时间,表示方法的调用时间

  • 创建两个方法,成功和失败,设置返回结果

  • package com.atguigu.cloud.resp;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 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 resultData=new ResultData();resultData.setCode(code);resultData.setMessage(message);resultData.setData(null);return resultData;}
    }
    

5、修改 PayController 类中的返回值

  • 设置好同意的返回值后,我们需要修改先前的 PayController 类中的返回值

  • 将当中方法的返回值实现统一

  • 修改后的代码

  • package com.atguigu.cloud.controller;import cn.hutool.core.bean.BeanUtil;
    import com.atguigu.cloud.entities.Pay;
    import com.atguigu.cloud.entities.PayDTO;
    import com.atguigu.cloud.resp.ResultData;
    import com.atguigu.cloud.service.PayService;
    import io.swagger.v3.oas.annotations.Operation;
    import io.swagger.v3.oas.annotations.tags.Tag;
    import jakarta.annotation.Resource;
    import org.springframework.beans.BeanUtils;
    import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
    @Tag(name = "支付微服务模块",description = "支付CRUD")
    public class PayController {@ResourcePayService payService;@PostMapping(value = "/pay/add")@Operation(summary = "新增", description = "新增支付流水方法,json串做参数")public ResultData<String> addPay(@RequestBody Pay pay) {System.out.println(pay.toString());int i = payService.add(pay);return ResultData.success("成功插入记录,返回值:" + i);}@DeleteMapping(value = "/pay/del/{id}")@Operation(summary = "删除", description = "删除支付流水方法")public ResultData<Integer> deletePay(@PathVariable("id") Integer id) {return ResultData.success(payService.delete(id));}@PutMapping(value = "/pay/update")@Operation(summary = "修改", description = "修改支付流水方法")public ResultData<String> updatePay(@RequestBody PayDTO payDTO) {Pay pay = new Pay();BeanUtils.copyProperties(payDTO, pay);int i = payService.update(pay);return ResultData.success("成功修改记录,返回值:" + i);}@GetMapping(value = "/pay/get/{id}")@Operation(summary = "按照ID查流水", description = "查询支付流水方法")public ResultData<Pay> getById(@PathVariable("id") Integer id) {return ResultData.success(payService.getById(id));}
    }
    
  • 然后进行测试即可

  • image-20240322155020704

1.6.3 全局异常处理

  • 定义全局异常处理后将不需要再使用 try-cath 来解决异常了

  • 首先给我们 Controller 类中抛出一个错误

  • 当传输的 id 为 -4 时,抛出错误

  • image-20240323135725722

  • 定义全局异常处理类 GlobalExceptionHandler

  • package com.atguigu.cloud.exp;import com.atguigu.cloud.resp.ResultData;
    import com.atguigu.cloud.resp.ReturnCodeEnum;
    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;@RestControllerAdvice
    public class GlobalExceptionHandler {@ExceptionHandler(RuntimeException.class)@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)public ResultData<String> exception(Exception e){System.out.println("#### come in GlobalExceptionHandler");return ResultData.fail(ReturnCodeEnum.RC500.getCode(), ReturnCodeEnum.RC500.getMessage());}
    }
  • image-20240323140316521

  • @ExceptionHandler 注解是具体要捕获的异常类型

  • @ResponseStatus 注解中的 HttpStatus枚举是定义异常和 BUG 的一个标准和规范

  • @ResponseStatus主要作用是为了改变 Http 响应的状态码

  • 测试一下即可,执行查询方法,传入 id 为 -4

  • image-20240323140751358

1.7 引入微服务理念

这里主要讲解不同模块之间如何调用

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

1.7.1 RestTemplate

  • 在引入微服务之前,需要介绍一下 API RestTemplate

  • RestTemplate 提供了多种远程范围 HTTP 服务的方法

  • 是一种简单便捷的 restful 服务类

  • 是 Spring 提供的用于访问 Rest 服务的客户端模板工具集

  • 官网访问地址:https://docs.spring.io/spring-framework/docs/6.0.11/javadoc-api/org/springframework/web/client/RestTemplate.html

  • image-20240323144554418

  • image-20240323144614769

  • 看官网的方法便可得知,它提供了两个微服务之间调用的增删改查的方法

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

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

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

  • HTTP响应转换被转换成的对象类型简单理解就是要返回的对象

常用方法

  • image-20240323144928815

  • 如果访问的是 getForEntity 方法,则返回是 RestTemplate 自己封装的一层对象

    • 主要包含了一些重要信息
    • 例如响应头,响应状态码,响应体等
  • 如果访问的是 getForObject方法,则直接返回我们指定的返回的对象

  • GET 请求方法

  • image-20240323145343867

  • POST 请求方法

  • image-20240323145417260

使用 RestTemplate 的两种方式

  • 直接 new 出来

  • 使用 配置类来返回 RestTemplate

    • @Configuration
      public class RestTemplateConfig
      {@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
      }

1.7.2 RestTemplate 增删改查使用的方法

以下推荐一下我自己增删改查使用的方法

  • 增:postForObject(url,传递参数,返回的对象)
  • 删:delete(url,传递参数,返回的对象)
  • 改:put(url,传递参数,返回的对象)
  • 查:getForObject(url,返回的对象,传递的参数)

1.7.3 新建模块 80

  • 按照之前的步骤:建模块-改pom-写yml-创建主启动类-创建业务类,来创建模块

  • 创建模块 cloud-consumer-order80

  • image-20240323143244052

  • 改写 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>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 文件

  • server:port: 80
    
  • 创建主启动类,名为 Main80

  • image-20240323143613653

  • package com.atguigu.cloud;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);}
    }
    
  • 创建业务类

  • 创建实体类 PayDTO 与 8001 模块的 DTO 一致

  • 因为消费者 80 产生的数据只应该是 支付者 8001 暴露出来的东西

  • 给消费者 80 尝试填写,对于其他敏感信息,其他信息是不应该暴露的

  • 所以需要使用 DTO 来传输数据

  • image-20240323144105487

  • 将之前在 8001 模块内定义的 统一返回对象拷贝过来

  • image-20240323150629399

  • 创建 RestTemplat 配置类

  • image-20240323150025269

  • 创建 Controller

  • 定义两个属性

    • REST请求地址
    • RestTemplate
  • image-20240323153003718

  • package com.atguigu.cloud.controller;import jakarta.annotation.Resource;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;@RestController
    public class OrderController {public static final String PaymentSrv_URL ="https://localhost:8001";@Resourceprivate RestTemplate restTemplate;}
    

1.7.4 微服务调用,实现 80 模块调用 8001 模块中的增删改查方法

  • 然后就可以编写我们的增删改查方法了

  • 首先我们编写一个增加方法,用于测试

  • image-20240323155207448

  • package com.atguigu.cloud.controller;import com.atguigu.cloud.entities.PayDTO;
    import com.atguigu.cloud.resp.ResultData;
    import io.swagger.v3.oas.annotations.Operation;
    import io.swagger.v3.oas.annotations.tags.Tag;
    import jakarta.annotation.Resource;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.client.RestTemplate;@RestController
    @Tag(name = "微服务消费模块",description = "消费调用支付的CRUD")
    public class OrderController {public static final String PaymentSrv_URL ="http://localhost:8001";@Resourceprivate RestTemplate restTemplate;@PostMapping("/consumer/pay/add")@Operation(summary = "消费调用支付的新增", description = "新增支付流水方法,json串做参数")public ResultData addOrder(PayDTO payDTO){return restTemplate.postForObject(PaymentSrv_URL+"/pay/add", payDTO, ResultData.class);}
    }
  • postForObject 方法传递的三个参数就是对应 REST请求地址、请求参数、HTTP响应转换被转换成的对象类型(及返回的对象类型)

  • 然后启动两个程序 Main8001 和 Main80

  • 一个个启动的话会比较麻烦,这边推荐设置到一起启动

  • 右上角编辑配置

  • image-20240323152420370

  • 选择 Spring boot,添加新的运行配置

  • image-20240323152505949

  • 命名,并且指定模块

  • image-20240323152550319

  • 选择模块内的主启动类

  • image-20240323152641358

  • 然后右键运行即可

  • image-20240323152726750

  • 然后进行测试即可

  • 增删改查的所有代码如下

  • package com.atguigu.cloud.controller;import com.atguigu.cloud.entities.PayDTO;
    import com.atguigu.cloud.resp.ResultData;
    import io.swagger.v3.oas.annotations.Operation;
    import io.swagger.v3.oas.annotations.tags.Tag;
    import jakarta.annotation.Resource;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.client.RestTemplate;@RestController
    @Tag(name = "微服务消费模块",description = "消费调用支付的CRUD")
    public class OrderController {public static final String PaymentSrv_URL ="http://localhost:8001";@Resourceprivate RestTemplate restTemplate;//增@PostMapping("/consumer/pay/add")@Operation(summary = "消费调用支付的新增", description = "新增支付流水方法,json串做参数")public ResultData addOrder(PayDTO payDTO){return restTemplate.postForObject(PaymentSrv_URL+"/pay/add", payDTO, ResultData.class);}//删@DeleteMapping( "/consumer/pay/del/{id}")@Operation(summary = "消费调用支付删除", description = "删除支付流水方法")public ResultData delByIdOrder(@PathVariable("id") Integer id){restTemplate.delete(PaymentSrv_URL+"/pay/del/{id}",id,ResultData.class);return ResultData.success("okx");}//改@PutMapping("/consumer/pay/update")@Operation(summary = "消费调用支付的修改",description = "修改支付流水方法")public ResultData updatePay(@RequestBody PayDTO payDTO){restTemplate.put(PaymentSrv_URL+"/pay/update",payDTO,ResultData.class);return ResultData.success("ok");}//查@GetMapping("/consumer/pay/get/{id}")@Operation(summary = "消费调用支付的按照ID查流水", description = "查询支付流水方法")public ResultData getById(@PathVariable("id") Integer id){return restTemplate.getForObject(PaymentSrv_URL+"/pay/get/{id}",ResultData.class,id);}
    }
    

1.8 工程重复代码提取

1.8.1 观察问题

  • 在我们的 8001 支付模块和 80 订单模块 两个模块当中,都存在一些相同的类,例如

  • image-20240326104757465

  • 可见系统中存在相同的部分

  • 此时我们可以新建一个模块,当作项目的一个包

  • 将这些重复的部分写入模块,在使用时即可直接调用

1.8.2 新建通用组件模块

  • 新建模块 cloud-api-commons

  • 用于对外暴露通用的组件/api/接口/工具类等

  • image-20240326105159622

  • 改写 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>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>
    
  • 将两个模块通用的部分添加进新模块

  • image-20240326105535265

  • 使用 maven,将 cloud-api-commons 模块打成一个公用的 jar 包

  • image-20240326105747881

1.8.3 对模块 8001 和 80 进行改造

  • 将模块 cloud-api-commons 打成 jar 包后,需要在 8001 和 80 两个模块之间进行引用

  • 在 pom 文件中添加此依赖进行引用

  • <!-- 引入自己定义的api通用包 -->
    <dependency><groupId>com.atguigu.cloud</groupId><artifactId>cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version>
    </dependency>
    
  • image-20240326110107012

  • 既然已经引入公用的部分了,那么两个模块之间公用的部分就可以删除了

  • 未标题-3

rg/xsd/maven-4.0.0.xsd">
4.0.0

com.atguigu.cloud
cloud2024
1.0-SNAPSHOT

  <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>
~~~
  • 将两个模块通用的部分添加进新模块

  • [外链图片转存中…(img-4MEDou8X-1711422961090)]

  • 使用 maven,将 cloud-api-commons 模块打成一个公用的 jar 包

  • [外链图片转存中…(img-ZhjxjmYb-1711422961090)]

1.8.3 对模块 8001 和 80 进行改造

  • 将模块 cloud-api-commons 打成 jar 包后,需要在 8001 和 80 两个模块之间进行引用

  • 在 pom 文件中添加此依赖进行引用

  • <!-- 引入自己定义的api通用包 -->
    <dependency><groupId>com.atguigu.cloud</groupId><artifactId>cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version>
    </dependency>
    
  • [外链图片转存中…(img-HllNT61C-1711422961091)]

  • 既然已经引入公用的部分了,那么两个模块之间公用的部分就可以删除了

  • [外链图片转存中…(img-Fqj8AVYG-1711422961091)]

  • 然后自行测试即可

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

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

相关文章

Hana数据库 No columns were bound prior to calling SQLFetch or SQLFetchScroll

在php调用hana数据库的一个sql时报错了&#xff0c;查表结构的sql&#xff1a; select * from sys.table_columns where table_name VBAP SQLSTATE[SL009]: <<Unknown error>>: 0 [unixODBC][Driver Manager]No columns were bound prior to calling SQLFetch …

基于SpringBoot和Leaflet的行政区划地图掩膜效果实战

目录 前言 一、掩膜小知识 1、GIS掩膜的实现原理 2、图层掩膜流程 二、使用插件 1、leaflet-mask介绍 2、核心代码解释 三、完整实例实现 1、后台逻辑实现 2、省级行政区划查询实现 3、行政区划定位及掩膜实现 4、成果展示 总结 前言 在之前的博客提过按空间矢量…

【STM32+HAL】I2C+DMA读取AS5600编码器

一、DMA的应用 有关更多DMA的应用&#xff0c;详见【STM32HAL】DMA应用 二、HAL库配置 1、开启I2C 开启对应DMA及中断 2、开启串口通信 至此&#xff0c;HAL库配置完毕 三、DMA版&#xff08;高效但不稳定&#xff09; 1、as5600.c #include "AS5600.h" #includ…

数据结构与算法 顺序表的基本运算

一、实验内容 编写一个程序实现&#xff0c;实现顺序表的各种基本运算&#xff08;假设顺序表的元素类型为char&#xff09;&#xff0c;并以此为基础设计一个程序完成下列功能&#xff1a; &#xff08;1&#xff09;初始化顺序表&#xff1b; &#xff08;2&#xff09;采…

用指针处理链表(二)

4建立动态链表 所谓建立动态链表是指在程序执行过程中从无到有地建立起一个链表&#xff0c;即一个一个地开辟结点和输入各结点数据,并建立起前后相链的关系。 例11.8 写一函数建立一个有3名学生数据的单向动态链表。 先考虑实现此要求的算法(见图11.12)。 设3个指针变量:he…

企业级快速开发框架 nbsaas-boot 1.1.8-2024 发布了

<parent><groupId>com.nbsaas.boot</groupId><artifactId>nbsaas-boot</artifactId><version>1.1.8-2024</version> </parent> 本次更新内容 1. 重构代码生成器&#xff0c;采用类提取和字段提取两种方式&#xff0c;提取功能…

HDFSRPC通信框架详解

本文主要对HDFSRPC通信框架解析。包括listener&#xff0c;reader&#xff0c;handler&#xff0c;responser等实现类的源码分析。注意hadoop版本为3.1.1。 写在前面 rpc肯定依赖于socket通信&#xff0c;并且使用的是java NIO。读者最好对nio有一定的了解&#xff0c;文章中…

古河云科技校园数字孪生解决方案

智慧校园需将环境信息、资源信息和应用信息全部转化为数字化信息&#xff0c;为管理决策和服务提供强有力的支持。智慧系统集智能化感知、智能化控制、智能化管理、智能化互动反馈、智能化数据分析、智能化视窗等功能于一体&#xff0c;旨在实现校园信息服务的全面提升。 行业…

《机器学习:引领数字化时代的技术革命》

随着科技的不断发展&#xff0c;机器学习作为人工智能的重要支柱之一&#xff0c;正迅速崛起并引领着数字化时代的技术革命。本文将从机器学习的技术进展、技术原理、行业应用案例、面临的挑战与机遇以及未来趋势预测和学习路线等方面展开探讨&#xff0c;为您揭示机器学习的神…

人工智能时代如何高效完成营销内容计划

智能对话升级&#xff01;【Kompas AI】AI对话助手&#xff0c;让沟通更高效 在人工智能时代&#xff0c;要高效完成营销计划&#xff0c;我们可以利用人工智能的多种能力来增强营销策略的精准度和执行效率。借助人工智能的力量&#xff0c;企业不仅可以提高营销计划的执行效率…

DMA知识

提示&#xff1a;文章 文章目录 前言一、背景二、 2.1 2.2 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 2024年3月26日23:32:43 今天看了DMA存储器到存储器的DMA传输和存储器到外设的DMA实验&#xff0c;在keil仿真可以看到效果。还没有在protues和开发…

使用Flask实现:基于midjourney-proxy的MJ绘画实现(开源)

文章目录 实现效果实现步骤完整源码 实现效果 运行mj.py&#xff0c;如下所示。输入中文&#xff0c;自动生成提示词&#xff0c;自动开始下载。用户选择是否需要变换图片&#xff0c;选择需要对哪个图片变换&#xff0c;自动保存。 之前想做一个网页版&#xff0c;只实现了…

新书速览|Django 5企业级Web应用开发实战:视频教学版

掌握Django框架开发技能&#xff0c;实战投票应用系统和内容管理系统 本书内容 《Django 5企业级Web应用开发实战&#xff1a;视频教学版》精选当前简单、实用和流行的Django实例代码&#xff0c;帮助读者学习和掌握Django 5框架及其相关技术栈的开发知识。本书系统全面、内容…

mysql如何存Emoji表情

如何存Emoji表情 背景解决方案一&#xff1a; 如果是自己搭建的数据库&#xff0c;参考如下。 1&#xff1a;先创建数据库&#xff0c;utf8编码2&#xff1a; 修改mysql 的配置文件 /etc/my.cnf 文件3&#xff1a;然后把你的表和字段也要支持utf8md4编码4&#xff1a;修改你连…

javaWeb教务查询系统

一、简介 在教育管理领域&#xff0c;教务管理系统是一个至关重要的工具&#xff0c;它能够有效地协调学校、教师和学生之间的各种活动。我设计了一个基于JavaWeb的教务管理系统&#xff0c;该系统包括三个角色&#xff1a;管理员、教师和学生。管理员拥有课程管理、学生管理、…

JWT(JSON Web Token)

JSON Web Token 是一种开放标准&#xff0c;用于在网络上安全传输信息的简洁、自包含的方式。它通常被用于身份验证和授权机制。 JWT 由三部分组成&#xff1a;头部&#xff08;Header&#xff09;、载荷&#xff08;Payload&#xff09;和签名&#xff08;Signature&#xff…

微软开源项目Garnet:Redis的竞争者还是替代者?

对于开源社区&#xff0c;最近的一大新闻就是Redis宣布从7.4版本开始&#xff0c;将采用Redis源代码可用许可证&#xff08;RSALv2&#xff09;和服务器端公共许可证&#xff08;SSPLv1&#xff09;的双重许可证&#xff0c;取代原有的BSD三条款许可证。这一变化引发了开发者社…

排序(冒泡/快速/归并)

冒泡排序 时间复杂度为 O(n^2) 原理 比较相邻的元素. 如果第一个比第二个大,就交换他们两个.依次比较每一对相邻的元素—>结果 : 最后的元素是这组数中最大的重复上述步骤 , 除了最后一个[]因为最后一个已经是排好序的了(这组数中最大的那个)]持续对越来越少的元素进行如上…

系列学习前端之第 7 章:一文掌握 AJAX

1、AJAX 简介 AJAX 全称为 Asynchronous JavaScript And XML&#xff08;中文名&#xff1a;阿贾克斯&#xff09;&#xff0c;就是异步的 JS 和 XML。AJAX 不是新的编程语言&#xff0c;而是一种将现有的标准组合在一起使用的新方式。AJAX 可以在浏览器中向服务器发送异步请求…

docker拉取镜像

docker 拉取镜像 命令格式 docker pull 仓库名称[:标签] 从下载过程可以看出&#xff1a; &#xff08;1&#xff09;镜像文件是由若干层组成&#xff0c;即&#xff1a;AUFS联合文件系统。这是实现增量保存与更新的基础 &#xff08;2&#xff09;下载过程会输出各层镜像的信…