2026版商城项目(一)

1. 项目背景

1.1 电商模式

markup 复制代码
市面上有5种常见的电商模式 B2B、B2C、C2B、C2C、O2O

1.1.1 B2B模式

markup 复制代码
B2B(Business to Business),是指商家和商家建立的商业关系,如阿里巴巴

1.1.2 B2C模式

markup 复制代码
B2C(Business to Consumer) 就是我们经常看到的供应商直接把商品买个
用户,即 "商对客" 模式,也就是我们呢说的商业零售,直接面向消费销
售产品和服务,如苏宁易购,京东,天猫,小米商城

1.1.3 C2B模式

markup 复制代码
C2B (Customer to Business),即消费者对企业,先有消费者需求产生
而后有企业生产,即先有消费者提出需求,后又生产企业按需求组织生产

1.1.4 C2C模式

markup 复制代码
C2C (Customer to Consumer) 客户之间把自己的东西放到网上去卖 。
如淘宝、咸鱼

1.1.5 O2O模式

markup 复制代码
O2O 即 Online To Offline,也即将线下商务的机会与互联网
结合在一起,让互联网成为线上交易前台,线上快速支付,线上优质服务,
如:饿了么,美团,淘票票,京东到家

1.2 商城项目

markup 复制代码
谷粒商城是一个B2C模式的电商平台,销售自营商品给客户

1.3 项目架构图

1.3.1 项目微服务架构图

markup 复制代码
前后分离开发,分为内网部署和外网部署,外网是面向公众访问的。
访问前端项目,可以有手机APP,电脑网页;内网部署的是后端集群,
前端在页面上操作发送请求到后端,在这途中会经过Nginx集群,
Nginx把请求转交给API网关(springcloud gateway)(网关可以根据当
前请求动态地路由到指定的服务,看当前请求是想调用商品服务还是购
物车服务还是检索服务),从路由过来如果请求很多,可以负载均衡地调
用商品服务器中一台(商品服务复制了多份),当商品服务器出现问题也
可以在网关层面对服务进行熔断或降级(使用阿里的sentinel组件),网关
还有其他的功能如认证授权、限流(只放行部分到服务器)等。

到达服务器后进行处理(springboot为微服务),服务与服务可能会相互
调用(使用feign组件),有些请求可能经过登录才能进行(基于OAuth2.0的
认证中心。安全和权限使用springSecurity控制)

服务可能保存了一些数据或者需要使用缓存,我们使用redis集群(分片+哨兵集
群)。持久化使用mysql,读写分离和分库分表。

服务和服务之间会使用消息队列(RabbitMQ),来完成异步解耦,分布式事务
的一致性。有些服务可能需要全文检索,检索商品信息,使用ElaticSearch。

服务可能需要存取数据,使用阿里云的对象存储服务OSS。

项目上线后为了快速定位问题,使用ELK对日志进行处理,使用LogStash收
集业务里的各种日志,把日志存储到ES中,用Kibana可视化页面从ES中检
索出相关信息,帮助我们快速定位问题所在。

在分布式系统中,由于我们每个服务都可能部署在很多台机器,服务和服务
可能相互调用,就得知道彼此都在哪里,所以需要将所有服务都注册到注册
中心。服务从注册中心发现其他服务所在位置(使用阿里Nacos作为注册
中心)。

每个服务的配置众多,为了实现改一处配置相同配置就同步更改,就需要配
置中心,也使用阿里的Nacos,服务从配置中心中动态取配置。

服务追踪,追踪服务调用链哪里出现问题,使用springcloud提供的Sleuth、
Zipkin、Metrics,把每个服务的信息交给开源的Prometheus进行聚合分析,
再由Grafana进行可视化展示,提供Prometheus提供的AlterManager实时
得到服务的警告信息,以短信/邮件的方式告知服务开发人员。

还提供了持续集成和持续部署。项目发布起来后,因为微服务众多,每一个都打
包部署到服务器太麻烦,有了持续集成后开发人员可以将修改后的代码提交到
github,运维人员可以通过自动化工具Jenkins Pipeline将github中获取的代码打
包成docker镜像,最终是由k8s集成docker服务,将服务以docker容器的方式运行。

1.3.2 微服务划分图

markup 复制代码
反映了需要创建的微服务以及相关技术。

前后分离开发。前端项目分为admin-vue(工作人员使用的后台管理系统)、
shop-vue(面向公众访问的web网站)、app(公众)、小程序(公众)

商品服务:商品的增删改查、商品的上下架、商品详情
支付服务
优惠服务
用户服务:用户的个人中心、收货地址
仓储服务:商品的库存
秒杀服务
订单服务:订单增删改查
检索服务:商品的检索ES
中央认证服务:登录、注册、单点登录、社交登录
购物车服务
后台管理系统:添加优惠信息等

1.4 项目技术&特色

markup 复制代码
前后分离开发,并开发基于vue的后台管理系统
SpringCloud全新的解决方案
应用监控、限流、网关、熔断降级等分布式方案,全方位涉及
透彻讲解分布式事务,分布式锁等分布式系统的难点
压力测试与性能优化
各种集群技术的区别以及使用
CI/CD 使用

1.5 项目前置要求

1.5.1 学习项目的前置知识:

markup 复制代码
熟悉SpringBoot以及常见整合方案
了解SpringCloud
熟悉 git  maven
熟悉 linux redis docker 基本操作
了解 html,css,js,vue
熟练使用idea开发项目

2. 分布式基础概念

2.1 微服务

markup 复制代码
微服务架构风格,就像是把一个单独的应用程序开发成一套小服务,每个小
服务运行在自己的进程中,并使用轻量级机制通信,通常是 HTTP API 这些
服务围绕业务能力来构建,	并通过完全自动化部署机制来独立部署,这些服
务使用不同的编程语言书写,以及不同数据存储技术,并保持最低限度的集中式管理

简而言之,拒绝大型单体应用,基于业务边界进行服务微化拆分,每个服务独
立部署运行。

2.2 集群&分布式&节点

markup 复制代码
集群是个物理状态,分布式是个工作方式

只要是一堆机器,也可以叫做集群,他们是不是一起协作干活,
这谁也不知道。

《分布式系统原理与范型》定义:

分布式系统是若干独立计算机的集合,这些计算机对于用户来说像单个系统
分布式系统 (distributed system) 是建立网络之上的软件系统

分布式是指根据不同的业务分布在不同的地方

集群指的是将几台服务器集中在一起,实现同一业务

例如:京东是一个分布式系统,众多业务运行在不同的机器上,所有业务构成
一个大型的分布式业务集群,每一个小的业务,比如用户系统,访问压力大的
时候一台服务器是不够的,我们就应该将用户系统部署到多个服务器,也就是
每一个业务系统也可以做集群化

分布式中的每一个节点,都可以做集群,而集群并不一定就是分布式的

节点:集群中的一个服务器

2.3 远程调用

markup 复制代码
在分布式系统中,各个服务可能处于不同主机,但是服务之间不可避免的需要
互相调用,我们称之为远程调用

SpringCloud中使用HTTP+JSON的方式来完成远程调用

2.4 负载均衡

markup 复制代码
分布式系统中,A 服务需要调用B服务,B服务在多台机器中都存在, 
A调用任意一个服务器均可完成功能

为了使每一个服务器都不要太或者太闲,我们可以负载均衡调用每一个服务器,
提升网站的健壮性

常见的负载均衡算法:
轮询:为第一个请求选择健康池中的每一个后端服务器,然后按顺序往后依
次选择,直到最后一个,然后循环

最小连接:优先选择链接数最少,也就是压力最小的后端服务器,在会话较
长的情况下可以考虑采取这种方式

2.5 服务注册/发现&注册中心

markup 复制代码
A服务调用B服务,A服务不知道B服务当前在哪几台服务器上有,哪些正常
的,哪些服务已经下线,解决这个问题可以引入注册中心
markup 复制代码
如果某些服务下线,我们其他人可以实时的感知到其他服务的状态,
从而避免调用不可用的服务

2.6 配置中心

markup 复制代码
每一个服务最终都有大量配置,并且每个服务都可能部署在多个服务
器上,我们经常需要变更配置,我们可以让每个服务在配置中心获取
自己的配置。

配置中心用来集中管理微服务的配置信息

2.7 服务熔断&服务降级

markup 复制代码
在微服务架构中,微服务之间通过网络来进行通信,存在相互依赖,
当其中一个服务不可用时,有可能会造成雪崩效应,要防止这种情
况,必须要有容错机制来保护服务
markup 复制代码
rpc
情景:
订单服务 --> 商品服务 --> 库存服务

库存服务出现故障导致响应慢,导致商品服务需要等待,可能等到10s后库存服
务才能响应。库存服务的不可用导致商品服务阻塞,商品服务等的期间,订单服
务也处于阻塞。一个服务不可用导致整个服务链都阻塞。如果是高并发,第一个
请求调用后阻塞10s得不到结果,第二个请求直接阻塞10s。更多的请求进来导致
请求积压,全部阻塞,最终服务器的资源耗尽。导致雪崩

1、服务熔断
设置服务的超时,当被调用的服务经常失败到达某个阈值,我们可以开启断路保
护机制,后来的请求不再去调用这个服务,本地直接返回默认的数据

2、服务降级
在运维期间,当系统处于高峰期,系统资源紧张,我们可以让非核心业务降级
运行,降级:某些服务不处理,或者简单处理【抛异常,返回NULL,调用 
Mock数据,调用 FallBack 处理逻辑】

2.8 API 网关

markup 复制代码
在微服务架构中,API Gateway 作为整体架构的重要组件,抽象服务中
需要的公共功能,同时它提供了客户端负载均衡,服务自动熔断,灰度发布,统
一认证,限流监控,日志统计等丰富功能,帮助我们解决很多API管理的难题

3. 环境搭建

3.1 jdk选择jdk21

markup 复制代码
因为springboot3最低版本是jdk21,所以这里使用jdk21;
直接在创建module的时候在idea中选择jdk21即可,如果没有直接选择一个进行下载

3.2 安装docker

markup 复制代码
安装docker和安装docker相关的mysql、redis、项目等都
直接看docker篇,这里不多介绍。

3.3 maven安装

不多介绍

3.4 安装git

不多介绍

3.5 gitee中创建项目仓库

markup 复制代码
在码云新建仓库,仓库名gulimall,选择语言java,在.gitignore选中maven,
许可证选Apache-2.0,开发模型选生产/开发模型,开发时在dev分支,
发布时在master分支,创建如图所示

3.6新建项目并创建相关基础模块

注意注意注意,我这里用的springboot3,一定要配置好对应的版本关系,我自己第一次配的时候,没有系统学过springboot3,花了1天才找对版本对饮关系!!!

3.6.1创建相关模块

markup 复制代码
创建以下模块
商品服务product
存储服务ware
订单服务order
优惠券服务coupon
用户服务member
每个模块导入web和openFeign


3.6.2 配置全局pom文件

markup 复制代码
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.2.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.messi.mall</groupId>
    <artifactId>study_mall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>study_mall</name>
    <description>study_mall</description>
    <packaging>pom</packaging>

    <properties>
        <java.version>21</java.version>
        <maven.compiler.source>21</maven.compiler.source>
        <maven.compiler.target>21</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-cloud.version>2023.0.6</spring-cloud.version>
    </properties>

    <modules>
        <module>mall_ware</module>
        <module>mall_coupon</module>
        <module>mall_member</module>
        <module>mall_order</module>
        <module>mall_product</module>
        <module>mall_common</module>

        <module>renren-generator</module>
    </modules>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

3.6.3 配置git提交排除项

markup 复制代码
在maven窗口刷新,并点击+号,找到刚才的pom.xml添加进来,发现多了个root。这样比如运行root的clean命令,其他项目也一起clean了。

修改总项目的.gitignore,把小项目里的垃圾文件在提交的时候忽略掉
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar

**/mvnw
**/mvnw.cmd

**/.mvn
**/target

.idea


**/.gitignore

**/README.md

3.6.4 最终效果:

3.7 数据库配置

见项目中的init_table文件夹

3.8 人人管理端

3.8 基于数据库的逆向工程

这里的逆向工程有很多可选项包括:

  1. mybatis-plus
  2. 让ai直接生成
  3. 人人开源

这里我们为了跟老师代码结构、接口请求方法、入參出參等保持一致,简化接下来的代码编写或者说bug出现的概率,使用人人开源生成crud代码。

3.8.1 拉取renren-generator到本地

markup 复制代码
在gitee中找到renren-generator项目url,拉取项目到本地,然后放到mall项目中去

3.8.2 修改相关配置

  1. 修改application.yml中的数据库配置为自己的数据库
  2. 修改generator中的相关配置为自己的包名、表前缀、数据对应数据类型
markup 复制代码
#\u4EE3\u7801\u751F\u6210\u5668\uFF0C\u914D\u7F6E\u4FE1\u606F

mainPath=com.messi
#\u5305\u540D
package=com.messi.mall
moduleName=product
#\u4F5C\u8005
author=yhx
#Email
email=sunlightcs@gmail.com
#\u8868\u524D\u7F00(\u7C7B\u540D\u4E0D\u4F1A\u5305\u542B\u8868\u524D\u7F00)
tablePrefix=pms_

#\u7C7B\u578B\u8F6C\u6362\uFF0C\u914D\u7F6E\u4FE1\u606F
tinyint=Integer
smallint=Integer
mediumint=Integer
int=Integer
integer=Integer
bigint=Long
float=Float
double=Double
decimal=BigDecimal
bit=Boolean

char=String
varchar=String
tinytext=String
text=String
mediumtext=String
longtext=String


date=LocalDateTime
datetime=LocalDateTime
timestamp=LocalDateTime

NUMBER=Integer
INT=Integer
INTEGER=Integer
BINARY_INTEGER=Integer
LONG=String
FLOAT=Float
BINARY_FLOAT=Float
DOUBLE=Double
BINARY_DOUBLE=Double
DECIMAL=BigDecimal
CHAR=String
VARCHAR=String
VARCHAR2=String
NVARCHAR=String
NVARCHAR2=String
CLOB=String
BLOB=String
DATE=LocalDateTime
DATETIME=LocalDateTime
TIMESTAMP=LocalDateTime
TIMESTAMP(6)=LocalDate

int8=Long
int4=Integer
int2=Integer
numeric=BigDecimal

nvarchar=String
  1. 删除模版中的controller中的这一行注解:
java 复制代码
@RequiresPermissions("${moduleName}:${pathName}:delete")

3.8.3 生成模块代码

  1. 运行main方法

  2. 打开配置页面:http://127.0.0.1/#generator.html

  3. 全选表名,点击生成代码

  4. 生成后代码下载、解压、将main的包复制到项目中替换原来的main

3.8.4 新建common包

新建common包作为公共配置(bean、utils等)

3.8.5 导入相关配置

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.messi.mall</groupId>
        <artifactId>study_mall</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>mall_common</artifactId>
    <name>mall_common</name>
    <description>每个微服务公共的依赖,bean、工具类等</description>

    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.6</version>
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis-spring</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>3.0.3</version>
        </dependency>
        <!--  数据库驱动   -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
        </dependency>
        <!-- 数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.2.21</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.16</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
        <!--tomcat里一般都带-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <!-- 部署产物 -->
                <artifactId>maven-deploy-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                    <skip>false</skip>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.8.5 从renren-generator中复制相关utils代码

3.8.6 整合mybatis-plus配置

  1. 在common的pom.xml中导入相关maven包(上面已配置)
  2. 在product项目的resources目录下新建application.yml
yaml 复制代码
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.1.103:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root
  1. 配置@MapperScan注解:在启动类中添加注解:@MapperScan("com.messi.mall.product.dao")
  2. 配置sql映射文件位置:
yaml 复制代码
# sql映射文件位置
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
  1. 通过test进行测试:可以看到数据已经插入到数据库中去了
java 复制代码
@MapperScan("com.messi.mall.product.dao")
@SpringBootTest
class ProductApplicationTests {

	@Autowired
	private BrandService brandService;

	@Test
	void contextLoads() {
		BrandEntity brandEntity = new BrandEntity();
		brandEntity.setDescript("hello");
		brandEntity.setName("华为");
		brandService.save(brandEntity);
		System.out.println("保存成功");
	}
}
  1. 按照product项目,配置一下其他几个项目
  2. 启动项目,在浏览器调用接口:http://localhost:11000/ware/purchase/list
    返回如下代表成功

4. Springcloud 配置

关于springcloud的介绍,这里就不多说了,可以去看springcloud章节的文章

本项目使用的springcloud相关组件如下:

关于springcloud和springcloudalibaba的版本对应关系可看这篇文章:对应关系

4.1 配置springcloudalibaba通用版本:

在总的pom.xml文件中添加springcloudalibaba版本配置,以后其他地方引入相关组件就不需要配置具体版本了(版本如上图所示)

xml 复制代码
<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>

4.2 添加nacos的服务注册发现功能

  1. 首先,修改 common中的pom.xml 文件,引入 Nacos Discovery Starter。
java 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  1. 在应用的common中的application.yml 配置文件中配置 Nacos Server 地址和微服务名称
java 复制代码
spring:
  application:
      name: mall_product
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
        connect-timeout: 10000
        timeout: 10000
        heartbeat-interval: 5000
        group: DEFAULT_GROUP
  1. 我们要配置nacos服务器的地址,也就是注册中心地址,但是我们还没有nacos服务器,所以我们需要启动nacos server创建nacos服务器,这里使用docker安装的方式,详见:docker安装nacos
java 复制代码
注意: 1
这里我有个no datasource set的问题,搞了我10个小时,
最后发现是nacos的数据库表少创建了。。。注意注意注意!!!!!
java 复制代码
注意:2
Nacos 2.x 使用 gRPC 通信,需要确保端口开放(主端口 + 偏移量 1000)
如果主端口是 8848,gRPC 端口是 9848
还需要开放 9849 端口(客户端同步请求)
  1. 使用 @EnableDiscoveryClient 注解开启服务注册与发现功能
java 复制代码
@MapperScan("com.messi.mall.product.dao")
@SpringBootApplication
@EnableDiscoveryClient
public class ProductApplication {
	public static void main(String[] args) {
		SpringApplication.run(ProductApplication.class, args);
	}
}
  1. 访问http://127.0.0.1:8848/nacos/ 账号密码nacos,出现如下页面,则表示访问成功

4.3 配置openfeign

  1. 确保pom文件中添加了openfeign的配置(2.0之后负载均衡不再feign包中了,这里也需要添加负载均衡的配置)
java 复制代码
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
    <exclusions>
        <exclusion>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
  1. 在被调用方coupon中添加如下被调用接口:
java 复制代码
@RequestMapping("/member/list")
public R membercoupons(){    //全系统的所有返回都返回R
    // 应该去数据库查用户对于的优惠券,但这个我们简化了,不去数据库查了,构造了一个优惠券给他返回
    CouponEntity couponEntity = new CouponEntity();
    couponEntity.setCouponName("满100减10");//优惠券的名字
    return R.ok().put("coupons",Arrays.asList(couponEntity));
}
  1. 在调用方member中添加服务发现注解:
java 复制代码
@EnableDiscoveryClient
@SpringBootApplication
@EnableFeignClients(basePackages="com.messi.mall.member.feign")
public class MemberApplication {
	public static void main(String[] args) {
		SpringApplication.run(MemberApplication.class, args);
	}
}
  1. 编写feign调用接口
java 复制代码
//告诉spring cloud这个接口是一个远程客户端,要调用coupon服务,再去调用coupon服务/coupon/coupon/member/list对应的方法
@FeignClient("mall_coupon") 
public interface CouponFeignService {
	@RequestMapping("/coupon/coupon/member/list")
	public R membercoupons();//得到一个R对象
}
  1. 在controller中编写调用方法
java 复制代码
@RequestMapping("/coupons")
public R test(){
    MemberEntity memberEntity = new MemberEntity();
    memberEntity.setNickname("张三");
    R membercoupons = couponFeignService.membercoupons(); //假设张三去数据库查了后返回了张三的优惠券信息

    // 打印会员和优惠券信息
    return R.ok().put("member",memberEntity).put("coupons",membercoupons.get("coupons"));
}
  1. 启动member和coupon并调用:http://localhost:8000/member/member/coupons,可以看到返回值:

4.4 nacos作为配置中心

我们还可以用nacos作为配置中心。配置中心的意思是不在application.properties等文件中配置了,而是放到nacos的配置中心公用,这样无需每台机器都改,只需修改一处就能全部使用。

  1. 引入依赖:注意:在springboot3对应的springcloud中,已经不支持bootstrap,所以要手动配置
java 复制代码
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- 由于springboot3关联的springcloud以上不支持先加载bootstrap文件,所以这里需要手动进行配置 -->
<!-- Spring Cloud 版本需与 Spring Boot 3 匹配,如 2022.0.x 及以上 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
  1. 在项目中添加bootstrap文件:注意:nacos2.X开始默认开启权限验证(默认 Nacos 1.2.0+ 支持权限,2.x 版本默认开启),所以要添加用户名密码
yaml 复制代码
spring:
  application:
    name: mall-coupon  # 你的服务名,用于匹配 Nacos 配置
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848  # Nacos 服务地址
        file-extension: properties  # 配置文件格式
        namespace: ""  # 可选:命名空间
        group: DEFAULT_GROUP  # 可选:配置分组
        # 核心新增:Nacos 认证信息(必填)
        username: nacos  # Nacos 默认用户名(若修改过则填实际值)
        password: nacos  # Nacos 默认密码(若修改过则填实际值)
  # 核心配置:声明导入 Nacos 配置
  config:
    import: nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}?server-addr=${spring.cloud.nacos.config.server-addr}
    # 若想配置为可选(Nacos 不可用时不报错),则改为:
    # import: optional:nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}?serverAddr=${spring.cloud.nacos.config.server-addr}
  1. 在nacos中添加配置文件

  2. 测试代码:

java 复制代码
@Value("${projectName}")
private String name;
@RequestMapping("/test")
public R test(){
    return R.ok().put("name",name);
}
  1. 配置自动刷新:
    • 方式一:在controller类上添加@RefreshScope注解,进行实时刷新
    • 方式二:在配置文件中添加:轮询刷新
yaml 复制代码
spring:
  cloud:
    nacos:
      config:
        # 轮询间隔(毫秒),生产不建议太小(避免频繁请求 Nacos)
        refresh-interval: 5000  # 5 秒
  1. 注意:如果nacos和本地的application.ymal都有配置文件,优先加载nacos中的

4.5 naocs配置中心进阶

4.5.1 配置命名空间

用作配置隔离。(一般每个微服务或者每个项目一个命名空间)

4.5.2 配置集ID

类似于配置文件名,即Data ID

4.5.3 配置分组

默认所有的配置集都属于DEFAULT_GROUP。自己可以创建分组,比如双十一,618,双十二

最终方案:每个微服务创建自己的命名空间,然后使用配置分组区分环境(dev/test/prod)

在bootstrap中可以配置分组:

yaml 复制代码
spring:
  application:
    name: mall-coupon  # 你的服务名,用于匹配 Nacos 配置
  cloud:
    nacos:
      config:
        server-addr: 127.0;0.1:8848  # Nacos 服务地址
        file-extension: properties  # 配置文件格式
        namespace: ""  # 可选:命名空间
        group: DEFAULT_GROUP  # 可选:配置分组

4.5.4 配置多配置源

在spirngboot3之前是通过shared-configs来进行配置的,springboot3之后通过spring.config.import来进行配置,shared-configs的配置可能不生效,AI的解释是:

yaml 复制代码
加载时机完全错过「占位符解析窗口」
Spring Boot 解析 ${center_org_code} 这类占位符的核心阶段是
「Environment 环境初始化」(启动最早期),而 shared-configs 的加载时机是
「ApplicationContext 初始化后」------解析占位符时,shared-configs 里的 
issue-manager.properties 还没加载,自然找不到 center_org_code。

bootstrap配置:

yaml 复制代码
spring:
  application:
    name: mall-coupon  # 你的服务名,用于匹配 Nacos 配置
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848  # Nacos 服务地址
        file-extension: properties  # 配置文件格式
        namespace: coupon  # 可选:命名空间
        group: dev  # 可选:配置分组
        # 核心新增:Nacos 认证信息(必填)
        username: nacos  # Nacos 默认用户名(若修改过则填实际值)
        password: nacos  # Nacos 默认密码(若修改过则填实际值)
  # 核心配置:声明导入 Nacos 配置
  config:
    import:
        #注意:这里的data-source和mall-coupon都是dataId
        #但是:data-source加上.properties会报错,读取不到,因为dataId本来就没有后缀
        #但是:nall-coupon的dataId是mall-coupon也没有后缀,加上不加上都不会报错,理解可能是因为服务名是这个
       - "nacos:data-source?group=dev&namespace=coupon"
       - "nacos:mall-coupon?group=dev&namespace=coupon"
    # 若想配置为可选(Nacos 不可用时不报错),则改为:
    # import: optional:nacos:${spring.application.name}.${spring.cloud.nacos.config.file-extension}?serverAddr=${spring.cloud.nacos.config.server-addr}

在data-source中配置age,在mall-coupon中配置name,测试可以看到都读取到了:

java 复制代码
@Value("${nameå}")
private String projectName;
@Value("${age}")
private String age;
@RequestMapping("/test")
public R test(){
    return R.ok().put("age",age);
}

4.6 gateway网关

4.6.1 介绍

网关是请求浏览的入口,常用功能包括路由转发,权限校验,限流控制等。springcloud gateway取代了zuul网关。

  • 发送请求需要知道商品服务的地址,如果商品服务器有100服务器,1号掉线后, 还得改所以需要网关动态地管理,他能从注册中心中实时地感知某个服务上 线还是下线。
  • 请求也要加上询问权限,看用户有没有权限访问这个请求,也需要网关。
  • 三大核心概念:
    • Route:路由规则:发一个请求给网关,网关要将请求路由到指定的服务。路由有
      • id
      • 目的地uri
      • 断言的集合,断言匹配成功了,才能路由到指定的地址,
    • Predicate:java里的断言函数,匹配请求里的任何信息,包括请求头、请求参数。断言类型查看
    • Filter:过滤器:对请求和响应进行处理(包括对请求进行请求头的添加等功能)。过滤器类型查看
  • 断言示例:After 路由断言
yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: after_route
        uri: https://example.org
        predicates:
        # After 路由断言工厂接收一个参数 ------ 日期时间(类型为 Java 的 ZonedDateTime)。
        # 该断言会匹配在指定日期时间之后发生的请求。
        - After=2017-01-20T17:42:47.789-07:00[America/Denver]
  • 过滤器示例:
yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
      - id: add_request_header_route
        uri: https://example.org
        filters:
        # AddRequestHeader 网关过滤器工厂接收两个参数:一个名称(name)和一个值(value)
        - AddRequestHeader=X-Request-red, blue
  • 流程图

4.6.2 项目配置

  1. 创建gateway项目
  2. pom中引入:
xml 复制代码
<dependency>
    <groupId>com.messi.mall</groupId>
    <artifactId>mall-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway-server-webmvc</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
  1. 项目开启注册服务发现:在启动类上添加:@EnableDiscoveryClient
  2. 在bootstrap中配置:
yaml 复制代码
spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
        username: nacos
        password: nacos
      config:
        server-addr: 127.0.0.1:8848
        namespace: gateway
        group: dev
        username: nacos
        password: nacos
  config:
    import: nacos:mall-gateway.yaml
server:
  port: 88
  1. 在nacos中创建命名空间gateway,然后在命名空间里创建文件mall-gateway.yml
yaml 复制代码
spring:
  cloud:
    gateway:
      routes:
        - id: baidu_route
          uri: http://www.baidu.com
          predicates:
            - Query=url,baidu

        - id: test_route
          uri: http://www.qq.com
          predicates:
            - Query=url,qq
相关推荐
美味蛋炒饭.2 小时前
Tomcat 超详细入门教程(安装 + 目录 + 配置 + 部署 + 排错)
java·tomcat
dreamxian2 小时前
苍穹外卖day11
java·spring boot·后端·spring·mybatis
Veggie262 小时前
【Java深度学习】PyTorch On Java 系列课程 第八章 17 :模型评估【AI Infra 3.0】[PyTorch Java 硕士研一课程]
java·人工智能·深度学习
weisian1512 小时前
Java并发编程--19-ThreadPoolExecutor七参数详解:拒绝Executors,手动掌控线程池
java·线程池·threadpool·七大参数
csdn5659738502 小时前
Java打包时,本地仓库有jar 包,Maven打包却还去远程拉取
java·maven·jar
Demon_Hao3 小时前
JAVA通过Redis实现Key分区分片聚合点赞、收藏等计数同步数据库,并且通过布隆过滤器防重复点赞
java·数据库·redis
华科易迅3 小时前
Spring装配对象方法-注解
java·后端·spring
庄周的大鱼4 小时前
分析@TransactionalEventListener注解失效
java·spring·springboot·事务监听器·spring 事件机制·事务注解失效解决
史蒂芬_丁4 小时前
C++深度拷贝例子
java·开发语言·c++