谷粒商城项目学习笔记一

一、项目简介

1.1、项目背景

1.1.1、电商模式

市面上有5种常见的电商模式 B2B、B2C、C2B、C2C、O2O

1、B2B模式

B2B(Business to Business),是指商家与商家建立的商业关系。如:阿里巴巴

2、B2C模式

B2C(Business to Consumer),就是我们经常看到的供应商直接把商品卖给用户,即“商家对客户”模式,也就是通常说的商业零售,直接面向消费者销售产品和服务。如:苏宁易购、京东、天猫

3、C2B模式

C2B模式(Consumer to Business),即消费者对企业。先有消费者需求产生而后有企业生产,即先有消费者提出需求,后有生产企业按需求组织生产

4、C2C模式

C2C(Customer to Consumer),客户之间自己把东西放网上去卖,如:淘宝,咸鱼

5、O2O模式

O2O(Online to Offine),将线下商务的机会与互联网结合在一起,让互联网成为线下交易的前台。线上快速支付,线下优质服务。如:饿了么,美团。

1.1.2、谷粒商城

谷粒商城是一个B2C模式的电商平台,销售自营商品给客户。

1.2、项目架构图

1.2.1、项目微服务架构图

1.2.2、微服务划分图

1.3、项目技术&特色

  • 前后端分离开发,并开发基于vue的后台管理系统

  • SpringCloud全新的解决方案

  • 全方位涉及应用监控、限流、网关、熔断降级等分布式方案

  • 透彻讲解分布式事务、分布式锁等分布式系统的难点

  • 分析高并发场景的编码方式,线程池,异步编排等使用

  • 压力测试与性能优化

  • 各种集群技术的区别即使用

  • CI/CD使用

1.4、项目前置要求

学习项目前的前置知识:建议使用win10系统进行开发

  • 熟悉SpringBoot以及常见整合方案

  • 了解SpringCloud

  • 熟悉git、maven

  • 熟悉linux,redis,docker基本操作

  • 了解html,css,js,vue

  • 熟练使用idea开发项目

二、分布式基础概念

2.1、微服务

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

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

2.2、集群&分布式&节点

集群是个物理形态,分布式是个工作方式。

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

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

“分布式系统是若干个独立计算机的集合,这些计算机对于用户来说就像单个相关系统”

分布式系统 (distributed system) 是建立网络之上的软件系统。

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

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

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

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

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

2.3、远程调用

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

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

2.4、负载均衡

分布式系统中,A服务需要调用B服务,B服务在多台服务器中都存在,A调用任意一个服务器均可完成此功能。

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

常见的负载均衡算法:

轮询: 为第一个请求选择健康池中的第一个后端服务器,然后按顺序往后依次选择,直到最后一个,然后循环。

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

散列: 根据请求源的ip散列(hash)来选择要转发的服务器。这种方式可以一定程度上保证特定用户能连接到相同的服务器。如果你的应用需要处理状态而要求用户能连接到和之前相同的服务器,可以考虑采取这种方式。

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

A服务调用B服务,A服务并不知道B服务当前在哪几台服务器有,那些正常的,哪些服务以及下线。解决这个问题可以引入注册中心。

如果某些服务下线,我们其他人可以实时感知到其他服务的状态,从而避免调用不可用的服务。

2.6、配置中心

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

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

2.7、服务熔断&服务降级

在微服务架构中,微服务之间通过网络进行通信,存在相互依赖,当其中一个服务不可用时,有可能会造成雪崩效应。要防止这样的情况,必须要有容错机制来保护服务。

1、服务熔断

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

2、服务降级

在运维期间,当系统处于高峰期,系统资源紧张,我们可以让非核心业务降级运行。

降级:某些服务不处理,或者简单处理【抛异常、返回null、调用Mock数据、调用Fallback处理逻辑】。

2.8、API网关

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

三、环境搭建

3.1、安装Linux

  • 下载&安装VirtualBox

  • 下载&安装Vagrant

  • 虚拟机安装在D:\develop\Oracle,打开命令行窗户后需要切换到这个目录

  • 打开window cmd窗口,运行Vagrant init centos/7,即可初始化一个centos7系统

  • 运行vagrant up即可启动虚拟机。系统root用户的密码是vagrant

  • vagrant其他常用命令

  • vagrant ssh:自动使用vagrant用户连接虚拟机

  • vagrant upload source [destination] [name|id]:上传文件

  • 默认虚拟机的ip地址不是固定ip,开发不方便

  • 修改Vagrantfile

config.vm.network "private_network", ip: "192.168.56.10"

这里的ip需要在物理机下使用ipconfig命令找到

3.2、docker

虚拟化容器技术。 Docker 基于镜像,可以秒级启动各种容器。每一种容器都是一个完整的运行

环境,容器之间互相隔离。

docker容器文件挂载与端口映射

3.3、虚拟机安装docker

Install Docker Engine on CentOS:

https://docs.docker.com/engine/install/centos/

#安装前先更新yum,不然有可能出现本机无法连接虚拟机的mysql、redis等
sudo yum update
 
#卸载系统之前的docker 
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine
                  
# 安装docker需要依赖的包                  
sudo yum install -y yum-utils
 
# 配置镜像
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
 
# 安装docker    
sudo yum install docker-ce docker-ce-cli containerd.io
 
# 启动docker
sudo systemctl start docker
 
# 设置开机自启动
sudo systemctl enable docker
 
# 检查docker版本
docker -v
 
# 检查docker有没有下载镜像
sudo docker images

开机自启动

sudo systemctl enable docker

配置docker阿里云镜像加速

https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "registry-mirrors": ["https://6epjgmxw.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

3.4、docker安装mysql

用docker安装上mysql,去docker仓库里搜索mysql

sudo docker pull mysql:5.7
 
# --name指定容器名字 -v目录挂载 -p指定端口映射  -e设置mysql参数 -d后台运行
sudo docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7
[root@localhost vagrant]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                               NAMES
6a685a33103f        mysql:5.7           "docker-entrypoint.s…"   32 seconds ago      Up 30 seconds       0.0.0.0:3306->3306/tcp, 33060/tcp   mysql
# 进入mysql容器
docker exec -it mysql bin/bash
exit;
 
# 进入mysql配置文件,修改mysql字符编码
vi /mydata/mysql/conf/my.conf 
 
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve
 
# 重新启动mysql
docker restart mysql

3.5、docker安装Redis

如果直接挂载的话docker会以为挂载的是一个目录,所以我们先创建一个文件然后再挂载,在虚拟机中。

# 在虚拟机中
mkdir -p /mydata/redis/conf
touch /mydata/redis/conf/redis.conf
 
docker pull redis
 
docker run -p 6379:6379 --name redis \
-v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
 
# 直接进去redis客户端。
docker exec -it redis redis-cli

如果是不持久化的。在配置文件中输入appendonly yes,就可以aof持久化了。修改完docker restart redis,docker -it redis redis-cli

vi /mydata/redis/conf/redis.conf
# 插入下面内容
appendonly yes
保存
 
docker restart redis

最新版本默认是持久化的,所以就不需要上面的操作了

redis官方配置文件:

https://redis.io/docs/management/config/

3.6、数据库初始化

注意重启虚拟机和docker后里面的容器就关了

sudo docker ps
sudo docker ps -a
# 这两个命令的差别就是后者会显示  【已创建但没有启动的容器】
 
# 我们接下来设置我们要用的容器每次都是自动启动
sudo docker update redis --restart=always
sudo docker update mysql --restart=always
# 如果不配置上面的内容的话,我们也可以选择手动启动
sudo docker start mysql
sudo docker start redis
# 如果要进入已启动的容器
sudo docker exec -it mysql /bin/bash

3.7、开发环境统一

1、Java

配置Java版本,要求java在1.8以上

2、Maven

安装并配置Maven版本,视频中Maven版本3.6.1,我这里是3.8.1

在maven的settings.xml中配置阿里云镜像,并配置用jdk1.8编译项目

  <mirrors>
    <mirror>
      <id>alimaven</id>
      <mirrorOf>central</mirrorOf>
      <name>aliyun maven</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
  </mirrors>
  <profiles>
    <profile>
      <id>jdk-1.8</id>

      <activation>
        <activeByDefault>true</activeByDefault>
        <jdk>1.8</jdk>
      </activation>

      <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
      </properties>
    </profile>
  </profiles>

3、IDEA

让Idea使用我们配置的Maven

安装插件Lombok和MyBatisX

4、VSCODE

Vscode是前端开发工具,下载安装。在vsCode里安装插件。

  • Auto Close Tag

  • Auto Rename Tag

  • Chinese

  • ESlint

  • HTML CSS Support

  • HTML Snippets

  • JavaScript ES6

  • Live Server

  • open in brower

  • Vetur

5、配置git-ssh

可以使用gitHub或者码云(gitee.com)作为代码托管,我这里使用码云,注册一个码云账号

下载git客户端,右键桌面Git GUI/bash Here

# 配置用户名
git config --global user.name "username"  //(名字,随意写)
 
# 配置邮箱
git config --global user.email "123456@qq.com" // 注册账号时使用的邮箱
 
# 配置ssh免密登录
ssh-keygen -t rsa -C "码云账号邮箱@qq.com" // 注册码云账号时使用的邮箱
三次回车后生成了密钥
 
# 查看秘钥
cat ~/.ssh/id_rsa.pub //也可以查看密钥

浏览器登录码云后,个人头像上点设置、然后点ssh公钥、随便填个标题,然后赋值
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC6MWhGXSKdRxr1mGPZysDrcwABMTrxc8Va2IWZyIMMRHH9Qn/wy3PN2I9144UUqg65W0CDE/thxbOdn78MygFFsIG4j0wdT9sdjmSfzQikLHFsJ02yr58V6J2zwXcW9AhIlaGr+XIlGKDUy5mXb4OF+6UMXM6HKF7rY9FYh9wL6bun9f1jV4Ydlxftb/xtV8oQXXNJbI6OoqkogPKBYcNdWzMbjJdmbq2bSQugGaPVnHEqAD74Qgkw1G7SIDTXnY55gBlFPVzjLWUu74OWFCx4pFHH6LRZOCLlMaJ9haTwT2DB/sFzOG/Js+cEExx/arJ2rvvdmTMwlv/T+6xhrMS3 553736044@qq.com
 
# 测试
ssh -T git@gitee.com
测试成功

6、项目结构创建&提交到码云

在码云新建仓库,仓库名gulimall,选择语言java,在.gitignore选中maven,许可证选Apache-2.0,开发模型选生成/开发模型,开发时在dev分支,发布时在master分支,创建。

在IDEA中New–>Project from version control–>git–复制刚才项目的地址,如https://gitee.com/xinzhouf/gulimall.git

然后New Module–Spring Initializer–com.atguigu.gulimall , Artifact填 gulimall-product。Next—选择web,springcloud routin里选中openFeign。

依次创建出以下服务

商品服务product存储服务ware订单服务order优惠券服务coupon用户服务member共同点:

导入web和openFeigngroup:com.atguigu.gulimallArtifact:gulimall-XXX每一个服务,包名com.atguigu.gulimall.XXX{product/order/ware/coupon/member}模块名:gulimall-XXX

然后右下角显示了springboot的service选项,选择他

从某个项目粘贴个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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall</name>
    <description>聚合服务</description>
    <packaging>pom</packaging>

    <modules>
        <module>gulimall-coupon</module>
        <module>gulimall-member</module>
        <module>gulimall-order</module>
        <module>gulimall-product</module>
        <module>gulimall-ware</module>
        <module>renren-fast</module>
    </modules>
</project>

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

修改总项目的.gitignore,把小项目里的垃圾文件在提交的时候忽略掉,比如HTLP.md。。。

target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
# https://github.com/takari/maven-wrapper#usage-without-binary-jar
.mvn/wrapper/maven-wrapper.jar

**/mvnw
**/mvnw.cmd

**/.mvn
**/target/

.idea

**/.gitignore

在git/local Changes,点击刷新看Unversioned Files,可以看到变化。

全选最后剩下21个文件,选择右键、Add to VCS。

在IDEA中安装插件:gitee,重启IDEA。

在Default changelist右键点击commit,去掉右面的勾选Perform code analysis、CHECK TODO,然后点击COMMIT,有个下拉列表,点击commit and push才会提交到云端。此时就可以在浏览器中看到了。

7、数据库初始化

数据库表设计

安装powerDesigner软件。

所有的数据库数据再复杂也不建立外键,因为在电商系统里,数据量大,做外键关联很耗性能。

name是给我们看的,code才是数据库里真正的信息。

选择primary和identity作为主键。然后点preview就可以看到生成这张表的语句。

点击菜单栏database–generate database—点击确定生成各个微服务的数据库表sql文件

使用mysql客户端SQLyog连接数据库,右键创建数据库,字符集选utf8mb4,他能兼容utf8且能解决一些乱码的问题。分别建立了下面数据库:

  • gulimall-oms

  • gulimall-pms

  • gulimall-sms

  • gulimall-ums

  • gulimall-wms

然后使用之前创建的sql文件为每个数据库创建表。(注意sql文件里没有建库语句)

四、快速开发


1、人人开源搭建后台管理系统

人人开源:https://gitee.com/renrenio

克隆到本地:

git clone https://gitee.com/renrenio/renren-fast-vue.git
 
git clone https://gitee.com/renrenio/renren-fast.git

将拷贝下来的“renren-fast”删除“.git”后,拷贝到“gulimall”工程根目录下,然后将它作为gulimall的一个module。

使用SQLyog在mysql中创建“gulimall_admin”的数据库,然后执行“renren-fast/db/mysql.sql”中的SQl脚本

修改“application-dev.yml”文件,默认为dev环境,修改IP和数据库名和连接mysql的url和用户名密码。

IDEA编译错误遇到下面2个问题:

1、lombok版本错误
2、IDEA设置properties文件编码格式

yml和properties文件中文乱码,需要设置为utf-8,并勾选Transparent native-to-ascii conversion。

步骤: File -> Settings -> Editor -> File encodings --> 设置编码

IntelliJ IDEA 可以对 Properties 文件进行专门的编码设置,也建议改为 UTF-8,其中有一个重点就是属性 Transparent native-to-ascii conversion,一般都要勾选,不然 Properties 文件中的注释显示的都不会是中文。

使用VSCode打开renren-fast-vue

启动“gulimall_admin”模块

然后访问“http://localhost:8080/renren-fast/

Node.js

Node.js是一个基于Chrome V8引擎的JavaScript运行环境。

http://nodejs.cn/api/

1、官网下载安装node.js:http://nodejs.cn/download/ 选择windows下载。下载完安装。

NPM是随同NodeJS一起安装的包管理工具,如JavaScript-NPM,java-Maven。

命令行输入node -v 检查配置好了,

2、配置npm的镜像仓库地址:

npm config set registry http://registry.npm.taobao.org/

执行npm config list可以检查配置

node -v
npm config set registry http://registry.npm.taobao.org/
npm config list

启动

然后再Vscode终端执行

npm install
npm run dev

执行npm install会报错

常见错误参考https://blog.csdn.net/wts563540/article/details/108818766

我的解决方法是,用管理员身份打开Vscode或者打开终端,切换到renren -fast-vue目录,执行npm install --force。

运行完成后自动打开http://localhost:8001,输入管理员账号密码:admin:admin登录。

2、逆向工程搭建&使用


下载renren-generator,桌面右键Git Bash Here,打开git bash。

git clone https://gitee.com/renrenio/renren-generator.git

下载到桌面后,同样把里面的.git文件删除,然后移动到我们IDEA项目目录中,同样配置好pom.xml

    <modules>
        <module>gulimall-coupon</module>
        <module>gulimall-member</module>
        <module>gulimall-order</module>
        <module>gulimall-product</module>
        <module>gulimall-ware</module>
        <module>renren-fast</module>
        <module>renren-generator</module>
    </modules>

在maven中刷新一下,让项目名变粗体,稍等下面进度条完成。

修改application.yml,ip地址,数据库,用户名和密码。

    url: jdbc:mysql://192.168.56.10:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: root

然后修改generator.properties

#代码生成器,配置信息

mainPath=com.atguigu
#包名
package=com.atguigu.gulimall
moduleName=product
#作者
author=zuozhe
#Email
email=zuozhe@sohu.com
#表前缀(类名不会包含表前缀)
#我们的pms数据库中的表的前缀都pms,如果写了表前缀,每一张表对于的javaBean就不会添加前缀了
tablePrefix=pms_

修改编译错误,renren-generator模块的pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.6.RELEASE</version>
    </parent>

运行renren-generator模块的RenrenApplication。

在网页上下方点击每页显示50个(pms库中的表),以让全部都显示,然后点击全部,点击生成代码。下载了压缩包

解压压缩包,把main放到gulimall-product的同级目录下。

然后在项目上右击(在项目上右击很重要)new modules— maven—然后在name上输入gulimall-common。

在pom.xml中也自动添加了<module>gulimall-common</module>

在common项目的pom.xml中添加

    <description>每一个微服务公共的依赖,bean,工具类等</description>

    <dependencies>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
        </dependency>
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpcore</artifactId>
            <version>4.4.13</version>
        </dependency>
        <dependency>
            <groupId>commons-lang</groupId>
            <artifactId>commons-lang</artifactId>
            <version>2.6</version>
        </dependency>
    </dependencies>

把每个微服务里公共的类和依赖放到common里。

然后在product项目中的pom.xml中加入下面内容

        <dependency>
            <groupId>com.atguigu.gulimall</groupId>
            <artifactId>gulimall-common</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

并将springboot版本和springcloud版本统一到跟视频相同的版本

    <!-- springboot:2.1.8.RELEASE -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-product</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall-product</name>
    <description>gulimall-product</description>
    <properties>
        <java.version>1.8</java.version>
        <!-- springcloud:Greenwich.SR3和springboot对应 -->
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
    </properties>

复制

renren-fast----utils包下的Query和PageUtils、R、Constant复制到common项目的java/com.atguigu.common.utils下

把@RequiresPermissions这些注解掉,因为是shiro的

复制renren-fast中的xss包粘贴到common的com.atguigu.common目录下。

还复制了exception文件夹,对应的位置关系自己观察一下就行

注释掉product项目下类中的//import org.apache.shiro.authz.annotation.RequiresPermissions;,他是shiro的东西

注释renren-generator\src\main\resources\template/Controller中所有的@RequiresPermissions。## import org.apache.shiro.authz.annotation.RequiresPermissions;

总之什么报错就去fast里面找。重启逆向工程。重新在页面上得到压缩包。重新解压出来,不过只把里面的controller复制粘贴到product项目对应的目录就行。

测试

测试与整合商品服务里的mybatisplus

https://mp.baomidou.com/guide/quick-start.html#配置

在common的pom.xml中导入

        <!--导入mysql驱动-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

删掉common里xss/xssfiler和XssHttpServletRequestWrapper

在product项目的resources目录下新建application.yml

spring:
  datasource:
    username: root
    password: root
    #然而执行后能通过,但是数据库中文显示乱码,所以我模仿逆向工程,把上面的配置url改为
    url: jdbc:mysql://192.168.56.10:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver

# MapperScan
# sql映射文件位置
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config: # 配置每个表的主键自增长
    db-config:
      id-type: auto

classpath 和 classpath* 区别:classpath:只会到你的class路径中查找找文件;classpath*:不仅包含class路径,还包括jar文件中(class路径)进行查找

classpath*的使用:当项目中有多个classpath路径,并同时加载多个classpath路径下(此种情况多数不会遇到)的文件,

就发挥了作用,如果不加*,则表示仅仅加载第一个classpath路径。

然后在主启动类上加上注解@MapperScan()

@MapperScan("com.atguigu.gulimall.product.dao")
@SpringBootApplication
public class GulimallProductApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallProductApplication.class, args);
    }

}

然后去测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class GulimallProductApplicationTests {

    @Autowired
    BrandService brandService;
    @Test
    public void contextLoads() {
        //先通过下面方法给数据库添加内容
//        BrandEntity brandEntity = new BrandEntity();
//        brandEntity.setName("华为");
//        brandService.save(brandEntity);
//        System.out.println("保存成功...");
        //修改数据
//        BrandEntity brandEntity = new BrandEntity();
//        brandEntity.setBrandId(1L);
//        brandEntity.setDescript("华为");
//        brandService.updateById(brandEntity);
        //查询数据
        List<BrandEntity> list = brandService.list(new QueryWrapper<BrandEntity>().eq("brand_id", 1L));
        list.forEach((item) -> {
            System.out.println(item);
        });
    }

}

用同样的方法生成其他几个微服务模块coupon、member、order、ware的CRUD代码。

coupon

重新打开generator逆向工程,修改generator.properties

# 主目录
mainPath=com.atguigu
#包名
package=com.atguigu.gulimall
#模块名
moduleName=coupon
#作者
autho=zuozhe
#email
email=zuozhe@sohu.com
#表前缀(类名不会包含表前缀) # 我们的pms数据库中的表的前缀都pms
# 如果写了表前缀,每一张表对于的javaBean就不会添加前缀了
tablePrefix=sms_

修改yml数据库信息

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.10:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
 
 
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0
 
server:
  port: 7000

端口号后面会设置,这里提前设置好了

启动生成RenrenApplication.java,运行后去浏览器80端口查看,同样让他一页全显示后选择全部后生成。生成后解压复制到coupon项目对应目录下。

让coupon也依赖于common,修改pom.xml

<dependency>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

resources下src包先删除

添加application.yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.10:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
 
 
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0

运行gulimallCouponApplication.java

http://localhost:8080/coupon/coupon/list

{"msg":"success","code":0,"page":{"totalCount":0,"pageSize":10,"totalPage":0,"currPage":1,"list":[]}}

member

重新使用代码生成器生成ums

模仿上面修改下面两个配置

代码生成器里:

    url: jdbc:mysql://192.168.56.10:3306/gulimall_ums?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
# 主目录
mainPath=com.atguigu
#包名
package=com.atguigu.gulimall
#模块名
moduleName=member
#作者
author=zuozhe
#email
email=zuozhe@qq.com
#表前缀(类名不会包含表前缀) # 我们的pms数据库中的表的前缀都pms
# 如果写了表前缀,每一张表对于的javaBean就不会添加前缀了
tablePrefix=ums_

重启RenrenApplication.java,然后同样去浏览器获取压缩包解压到对应member项目目录

member也导入依赖

<dependency>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

同样新建application.yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.10:3306/gulimall_ums?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
 
 
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0
 
server:
  port: 8000

order端口是9000,product是10000,ware是11000。

以后比如order系统要复制多份,他的端口计算9001、9002。。。

重启web后,http://localhost:8000/member/growthchangehistory/list

{"msg":"success","code":0,"page":{"totalCount":0,"pageSize":10,"totalPage":0,"currPage":1,"list":[]}}

order

修改代码生成器

    url: jdbc:mysql://192.168.56.10:3306/gulimall_oms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
#代码生成器,配置信息
 
# 主目录
mainPath=com.atguigu
#包名
package=com.atguigu.gulimall
#模块名
moduleName=order
#作者
author=zuozhe
#email
email=zuozhe@qq.com
#表前缀(类名不会包含表前缀) # 我们的pms数据库中的表的前缀都pms
# 如果写了表前缀,每一张表对于的javaBean就不会添加前缀了
tablePrefix=oms_

运行RenrenApplication.java重新生成后去下载解压放置。

application.yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.10:3306/gulimall_oms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
 
 
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0
      
server:
  port: 9000

POM.xml

<dependency>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

启动gulimallOrderApplication.java

http://localhost:9000/order/order/list

{"msg":"success","code":0,"page":{"totalCount":0,"pageSize":10,"totalPage":0,"currPage":1,"list":[]}}

ware

修改代码生成器

    url: jdbc:mysql://192.168.56.10:3306/gulimall_wms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
#代码生成器,配置信息
 
# 主目录
mainPath=com.atguigu
#包名
package=com.atguigu.gulimall
#模块名
moduleName=ware
#作者
author=zuozhe
#email
email=zuozhe@qq.com
#表前缀(类名不会包含表前缀) # 我们的pms数据库中的表的前缀都pms
# 如果写了表前缀,每一张表对于的javaBean就不会添加前缀了
tablePrefix=wms_

运行RenrenApplication.java重新生成后去下载解压放置。

application.yml

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.10:3306/gulimall_wms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
 
 
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0
      
server:
  port: 11000

POM.xml

<dependency>
    <groupId>com.atguigu.gulimall</groupId>
    <artifactId>gulimall-common</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

启动gulimallWareApplication.java

http://localhost:11000/ware/wareinfo/list

{"msg":"success","code":0,"page":{"totalCount":0,"pageSize":10,"totalPage":0,"currPage":1,"list":[]}}

五、SpringCloud Alibaba


5.1、SpringCloud Alibaba 简介


1、简介

  • 注册中心:

  • 配置中心:

  • 网关:

Spring Cloud Alibaba 致力于提供微服务开发的一站式解决方案。此项目包含开发分布式应用微服务的必需组件,

方便开发者通过 Spring Cloud 编程模型轻松使用这些组件来开发分布式应用服务。

依托 Spring Cloud Alibaba,您只需要添加一些注解和少量配置,就可以将 Spring Cloud 应用

接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。

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

2、为什么使用

SpringCloud 的几大痛点**

SpringCloud 部分组件停止维护和更新,给开发带来不便;

SpringCloud 部分环境搭建复杂,没有完善的可视化界面,我们需要大量的二次开发和定制

SpringCloud 配置复杂,难以上手,部分配置差别难以区分和合理应用

SpringCloud Alibaba 的优势:

阿里使用过的组件经历了考验,性能强悍,设计合理,现在开源出来大家用

成套的产品搭配完善的可视化界面给开发运维带来极大的便利

搭建简单,学习曲线低。

结合 SpringCloud Alibaba 我们最终的技术搭配方案:

SpringCloud Alibaba - Nacos:注册中心(服务发现/注册)

SpringCloud Alibaba - Nacos:配置中心(动态配置管理)

SpringCloud - Ribbon:负载均衡

SpringCloud - Feign:声明式 HTTP 客户端(调用远程服务)

SpringCloud Alibaba - Sentinel:服务容错(限流、降级、熔断)

SpringCloud - Gateway:API 网关(webflux 编程模式)

SpringCloud - Sleuth:调用链监控

SpringCloud Alibaba - Seata:原 Fescar,即分布式事务解决方案

netflix把feign闭源了,spring cloud开了个open feign

3、版本选择

项目中引入SpringCloud Alibaba依赖

注意:版本号要与SpringBoot版本号对应,具体看官方文档

项目的版本号格式为 x.x.x 的形式,其中 x 的数值类型为数字,从 0 开始取值,且不限于 0~9 这个范围。项目处于孵化器阶段时,第一位版本号固定使用 0,即版本号为 0.x.x 的格式。

由于 Spring Boot 1 和 Spring Boot 2 在 Actuator 模块的接口和注解有很大的变更,且 spring-cloud-commons 从 1.x.x 版本升级到 2.0.0 版本也有较大的变更,因此我们采取跟 SpringBoot 版本号一致的版本:

  • 1.5.x 版本适用于 Spring Boot 1.5.x

  • 2.0.x 版本适用于 Spring Boot 2.0.x

  • 2.1.x 版本适用于 Spring Boot 2.1.x

  • 2.2.x 版本适用于 Spring Boot 2.2.x

  • 2020.x 版本适用于 Spring Boot 2.4.x

  • 2021.x 版本适用于 Spring Boot 2.6.x

  • 2022.x 版本适用于 Spring Boot 3.0.x

4、项目中的依赖

在common的pom.xml中加入

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

5.2、SpringCloud Alibaba-Nacos[作为注册中心]


注册中心文档:https://github.com/alibaba/spring-cloud-alibaba/blob/2022.x/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md

如果是在docker安装的nacos可以参考https://blog.csdn.net/wts563540/article/details/123151034

如何接入:

1、首先,修改 pom.xml 文件,引入 Nacos Discovery Starter。

 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
 </dependency>

放到common的pom.xml文件里

2、在应用的 /src/main/resources/application.yml内容,配置了服务中心名和当前模块名字

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.10:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
  application:
    name: gulimall-coupon
 
mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto
      logic-delete-value: 1
      logic-not-delete-value: 0
 
server:
  port: 7000

我们要配置nacos服务器的地址,也就是注册中心地址,但是我们还没有nacos服务器,所以我们先在下面按照"启动nacos server"创建nacos服务器。

启动 Nacos Server

  1. 首先需要获取 Nacos Server,支持直接下载和源码构建两种方式。

  1. 直接下载:Nacos Server 下载页

  1. 源码构建:进入 Nacos Github 项目页面,将代码 git clone 到本地自行编译打包,参考此文档推荐使用源码构建方式以获取最新版本

  1. 启动 Server,进入解压后文件夹或编译打包好的文件夹,找到如下相对文件夹 nacos/bin,并对照操作系统实际情况之下如下命令。

  1. Linux/Unix/Mac 操作系统,执行命令 sh startup.sh -m standalone

  1. Windows 操作系统,执行命令 startup.cmd -m standalone

3、使用 @EnableDiscoveryClient 注解开启服务注册与发现功能,在coupon的gulimallCouponApplication.java加上@EnableDiscoveryClient,导入包,然后重开项目。

 @SpringBootApplication
 @EnableDiscoveryClient
 public class ProviderApplication {

     public static void main(String[] args) {
         SpringApplication.run(ProviderApplication.class, args);
     }

     @RestController
     class EchoController {
         @GetMapping(value = "/echo/{string}")
         public String echo(@PathVariable String string) {
                 return string;
         }
     }
 }

4、编译启动应用

浏览器中输入:http://127.0.0.1:8848/nacos/

账号密码:nacos/nacos,服务列表就可以看到我们加入的服务了

然后依次给member配置上面的yaml,改下name就行。再给每个项目配置类上加上注解@EnableDiscoveryClient

流程:

1、启动注册中心

2、修改配置文件,添加服务中心名和当前模块名字

3、使用 @EnableDiscoveryClient 注解开启服务注册与发现功能

4、编译启动应用

5.3、Feign与注册中心


1、SpringCloud feign 声明式远程调用简介

Feign 是一个声明式的 HTTP 客户端,它的目的就是让远程调用更加简单。Feign 提供了 HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。Feign 整合了 Ribbon(负载均衡)和 Hystrix(服务熔断),可以让我们不再需要显式地使用这两个组件。SpringCloudFeign 在 NetflixFeign 的基础上扩展了对 SpringMVC 注解的支持,在其实现下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定。简化了SpringCloudRibbon 自行封装服务调用客户端的开发量。

2、使用

1、引入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId> </artifactId>
</dependency>

2、开启 feign 功能
@EnableFeignClients(basePackages = "com.atguigu.gulimall.pms.feign")

3、声明远程接口
@FeignClient("gulimall-ware")
public interface WareFeignService {
@PostMapping("/ware/waresku/skus")
public Resp<List<SkuStockVo>> skuWareInfos(@RequestBody List<Long> skuIds);
}

3、测试

feign是一个声明式的HTTP客户端,他的目的就是让远程调用更加简单。给远程服务发的是HTTP请求。

会员服务想要远程调用优惠券服务,只需要给会员服务里引入openfeign依赖,他就有了远程调用其他服务的能力。

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

我们之前在member的pom.xml已经引用过了(微服务)。

在coupon中修改如下的内容

@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;
 
    @RequestMapping("/member/list")
    public R membercoupons(){    
        // 全系统的所有返回都返回R
        // 应该去数据库查用户对于的优惠券,但这个我们简化了,不去数据库查了,构造了一个优惠券给他返回
        CouponEntity couponEntity = new CouponEntity();
        couponEntity.setCouponName("满100-10");//优惠券的名字
        return R.ok().put("coupons",Arrays.asList(couponEntity));
    }

这样我们准备好了优惠券的调用内容

在member的配置类上加注解@EnableDiscoveryClient,告诉member是一个远程调用客户端,member要调用东西的

package com.atguigu.gulimall.member;
 
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
 
/*
* 想要远程调用的步骤:
* 1 引入openfeign
* 2 编写一个接口,接口告诉springcloud这个接口需要调用远程服务
*     2.1 在接口里声明@FeignClient("gulimall-coupon")他是一个远程调用客户端且要调用coupon服务
*     2.2 要调用coupon服务的/coupon/coupon/member/list方法
* 3 开启远程调用功能 @EnableFeignClients,要指定远程调用功能放的基础包
* */
@EnableFeignClients(basePackages="com.atguigu.gulimall.member.feign")
@EnableDiscoveryClient
@SpringBootApplication
public class gulimallMemberApplication {
 
    public static void main(String[] args) {
        SpringApplication.run(gulimallMemberApplication.class, args);
    }
}

那么要调用什么东西呢?就是我们刚才写的优惠券的功能,复制函数部分,在member的com.atguigu.gulimall.member.feign包下新建类:

package com.atguigu.gulimall.member.feign;
 
import com.atguigu.common.utils.R;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
 
@FeignClient("gulimall-coupon") //告诉spring cloud这个接口是一个远程客户端,要调用coupon服务,再去调用coupon服务/coupon/coupon/member/list对应的方法
public interface CouponFeignService {
    @RequestMapping("/coupon/coupon/member/list")//注意写全优惠券类上还有映射//注意我们这个地方不熟控制层,所以这个请求映射请求的不是我们服务器上的东西,而是nacos注册中心的
    public R membercoupons();//得到一个R对象
}

然后我们在member的控制层写一个测试请求

@RestController
@RequestMapping("member/member")
public class MemberController {
    @Autowired
    private MemberService memberService;
 
    @Autowired
    CouponFeignService couponFeignService;
 
    @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"));
    }

重新启动服务

http://localhost:8000/member/member/coupons

{"msg":"success","code":0,"coupons":[{"id":null,"couponType":null,"couponImg":null,"couponName":"满100-10","num":null,"amount":null,"perLimit":null,"minPoint":null,"startTime":null,"endTime":null,"useType":null,"note":null,"publishCount":null,"useCount":null,"receiveCount":null,"enableStartTime":null,"enableEndTime":null,"code":null,"memberLevel":null,"publish":null}],"member":{"id":null,"levelId":null,"username":null,"password":null,"nickname":"会员昵称张三","mobile":null,"email":null,"header":null,"gender":null,"birth":null,"city":null,"job":null,"sign":null,"sourceType":null,"integration":null,"growth":null,"status":null,"createTime":null}}

coupon里的R.ok()是什么

public class R extends HashMap<String, Object> {//R继承了HashMap
    // ok是个静态方法,new了一个R对象,并且
    public static R ok(String msg) {
        R r = new R();
        r.put("msg", msg);//调用了super.put(key, value);,即hashmap的put
        return r;
    }
}

coupon里的控制层就是new了个couponEntity然后放到hashmap(R)里。

5.4、Nacos配置中心


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

官方教程:https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-config-example/readme-zh.md

引入配置中心依赖,放到common中

 <dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
 </dependency>

在coupons项目中创建/src/main/resources/bootstrap.properties ,这个文件是springboot里规定的,他优先级别application.properties高

# 改名字,对应nacos里的配置文件名
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

原来的方式:

@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;
 
    @Value("${coupon.user.name}")//从application.properties中获取//不要写user.name,他是环境里的变量
    private String name;
    @Value("${coupon.user.age}")
    private Integer age;
    @RequestMapping("/test")
    public R test(){
 
        return R.ok().put("name",name).put("age",age);
    }

浏览器去nacos里的配置列表,点击+号,data ID:gulimall-coupon.properties,配置

# gulimall-coupon.properties
coupon.user.name="zhangsan-配置中心"      
coupon.user.age=18

然后点击发布。重启coupon,http://localhost:7000/coupon/coupon/test

{"msg":"success","code":0,"name":"zhangsan-配置中心","age":18}

但是修改怎么办?实际生产中不能重启应用。在coupon的控制层上加@RefreshScope

@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;
 
    @Value("${coupon.user.name}")//从application.properties中获取//不要写user.name,他是环境里的变量
    private String name;
    @Value("${coupon.user.age}")
    private Integer age;
    @RequestMapping("/test")
    public R test(){
 
        return R.ok().put("name",name).put("age",age);
    }

重启后,在nacos浏览器里修改配置,修改就可以观察到能动态修改了

nacos的配置内容优先于项目本地的配置内容。

配置中心进阶

在nacos浏览器中还可以配置:

  • 命名空间:用作配置隔离。(一般每个微服务一个命名空间)

  • 默认public。默认新增的配置都在public空间下

  • 开发、测试、开发可以用命名空间分割。properties每个空间有一份。

  • 在bootstrap.properties里配置(测试完去掉,学习不需要)

  • 也可以为每个微服务配置一个命名空间,微服务互相隔离

# 可以选择对应的命名空间 # 写上对应环境的命名空间ID
spring.cloud.nacos.config.namespace=6c860440-eba5-4b52-a32f-ac272bb62ab7
  • 配置集:一组相关或不相关配置项的集合。

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

  • 配置分组:默认所有的配置集都属于DEFAULT_GROUP。双十一,618,双十二

# 更改配置分组
spring.cloud.nacos.config.group=DEFAULT_GROUP

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

加载多配置集

我们要把原来application.yml里的内容都分文件抽离出去。我们在nacos里创建好后,在coupons里指定要导入的配置即可。

bootstrap.properties

# 该名字,对应nacos里的配置文件名
spring.application.name=gulimall-coupon
 
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
# 可以选择对应的命名空间 # 写上对应环境的命名空间ID
spring.cloud.nacos.config.namespace=6c860440-eba5-4b52-a32f-ac272bb62ab7
# 更改配置分组
spring.cloud.nacos.config.group=dev
 
#新版本不建议用下面的了
#spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
#spring.cloud.nacos.config.ext-config[0].group=dev
#spring.cloud.nacos.config.ext-config[0].refresh=true
#spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
#spring.cloud.nacos.config.ext-config[1].group=dev
#spring.cloud.nacos.config.ext-config[1].refresh=true
#spring.cloud.nacos.config.ext-config[2].data-id=other.yml
#spring.cloud.nacos.config.ext-config[2].group=dev
#spring.cloud.nacos.config.ext-config[2].refresh=true
 
spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
spring.cloud.nacos.config.extension-configs[0].refresh=true
 
spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true
 
spring.cloud.nacos.config.extension-configs[2].data-id=other.yml
spring.cloud.nacos.config.extension-configs[2].group=dev
spring.cloud.nacos.config.extension-configs[2].refresh=true

输出内容有

[main] c.a.c.n.c.NacosPropertySourceBuilder     : Loading nacos data, dataId: 'datasource.yml', group: 'dev'
[main] c.a.c.n.c.NacosPropertySourceBuilder     : Loading nacos data, dataId: 'mybatis.yml', group: 'dev'
[main] c.a.c.n.c.NacosPropertySourceBuilder     : Loading nacos data, dataId: 'other.yml', group: 'dev'
[main] c.a.c.n.c.NacosPropertySourceBuilder     : Loading nacos data, dataId: 'gulimall-coupon.properties', group: 'dev'
[main] b.c.PropertySourceBootstrapConfiguration : Located property source: CompositePropertySource {name='NACOS', propertySources=[NacosPropertySource {name='gulimall-coupon.properties'}, NacosPropertySource {name='other.yml'}, NacosPropertySource {name='mybatis.yml'}, NacosPropertySource {name='datasource.yml'}]}

5.5、SpringCloud-Gateway网关


发送请求需要知道商品服务的地址,如果商品服务器有123服务器,1号掉线后,还得改,所以需要网关动态地管理,他能从注册中心中实时地感知某个服务上线还是下线。

请求也要加上询问权限,看用户有没有权限访问这个请求,也需要网关。

所以我们使用spring cloud的gateway组件做网关功能。

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

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

参考手册:https://cloud.spring.io/spring-cloud-gateway/2.2.x/reference/html/

三大核心概念:

Route: The basic building block of the gateway. It is defined by an ID, a destination URI, a collection of predicates断言, and a collection of filters. A route is matched if the aggregate predicate is true.发一个请求给网关,网关要将请求路由到指定的服务。路由有id,目的地uri,断言的集合,匹配了断言就能到达指定位置,

Predicate断言: This is a Java 8 Function Predicate. The input type is a Spring Framework ServerWebExchange. This lets you match on anything from the HTTP request, such as headers or parameters.就是java里的断言函数,匹配请求里的任何信息,包括请求头等

Filter: These are instances of Spring Framework GatewayFilter that have been constructed with a specific factory. Here, you can modify requests and responses before or after sending the downstream request.过滤器请求和响应都可以被修改。客户端发请求给服务端。中间有网关。先交给映射器,如果能处理就交给handler处理,然后交给一系列filer,然后给指定的服务,再返回回来给客户端。

创建,使用initilizer,Group:com.atguigu.gulimall,Artifact: gulimall-gateway,package:com.atguigu.gulimall.gateway。 搜索gateway选中。

pom.xml里加上common依赖, 修改jdk版本,

开启注册服务发现@EnableDiscoveryClient配置nacos注册中心地址applicaion.properties

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
spring.application.name=gulimall-gateway
server.port=88

bootstrap.properties 填写配置中心地址

spring.application.name=gulimall-gateway
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=481d804a-0375-480c-952f-9a4acef171a0

nacos里创建命名空间gateway,然后在命名空间里创建文件guilmall-gateway.yml

spring:
    application:
        name: gulimall-gateway

在项目里创建application.yml

spring:
  cloud:
    gateway:
      routes:
        - id: test_route
          uri: https://www.baidu.com
          predicates:
            - Query=url,baidu
 
        - id: qq_route
          uri: https://www.qq.com
          predicates:
            - Query=url,qq
 
        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
 
        - id: third_party_route
          uri: lb://gulimall-third-party
          predicates:
            - Path=/api/thirdparty/**
          filters:
            - RewritePath=/api/thirdparty/(?<segment>.*),/$\{segment}
 
        - id: member_route
          uri: lb://gulimall-member
          predicates:
            - Path=/api/member/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
 
        - id: ware_route
          uri: lb://gulimall-ware
          predicates:
            - Path=/api/ware/**
          filters:
            - RewritePath=/api/(?<segment>.*),/$\{segment}
 
        - id: admin_route
          uri: lb://renren-fast
          predicates:
            - Path=/api/**
          filters:
            - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}

测试 localhost:8080/hello?url=baidu

出现编译错误:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'routeDefinitionRouteLocator' defined in class path resource [org/springframework/cloud/gateway/config/GatewayAutoConfiguration.class]: Unsatisfied dependency expressed through method 'routeDefinitionRouteLocator' parameter 4; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.core.convert.ConversionService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=webFluxConversionService)}

修改方案:

pom.xml中添加排除依赖:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <!-- Maven整个生命周期内排除内置容器,排除内置容器导出成war包可以让外部容器运行spring-boot项目-->
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-tomcat</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

同时应用启动排除(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class}):

@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DruidDataSourceAutoConfigure.class})
public class GulimallGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(GulimallGatewayApplication.class, args);
    }

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值