1环境和项目结构搭建

# 【1 环境和项目搭建】

1675343965651

一、安装虚拟机(B站P6集)

1、本项目老师推荐使用(因为更加方便)Oracle VM VirtualBox 来安装和管理Linux虚拟机

官网https://www.virtualbox.org/ | 官方有现成的Linux等镜像仓库(vagrant),方便,体积小巧

https://app.vagrantup.com/boxes/search Vagrant官方镜像仓库

https://www.vagrantup.com/downloads.html Vagrant下载

打开window cmd窗口,运行Vagrant init centos/7 ,即可初始化一个centos系统运行vagrant up即可启动虚拟机。系统root用户的密码是vagrant

vagrant其他常用命令
vagrant ssh自动使用vagrant用户连接虚拟机
vagrant upload source [destination] [namelid]上传文件
https://www.vagrantup.com/docs/cli/init.html Vagrant命令行

2、 通过vagrant启动虚拟机、连接虚拟机

VMware的使用可以参考老版本的博学谷资料:第二阶段--01linux--视频/资料(D:\BaiduNetdiskDownload\2.阶段二-JavaWeb2020新版\01.linux\day01\资料\操作文档)

3、本次用vmware创建的虚拟机账密码为:账户itcast ***(去笔记搜索)

4、如果用Virtualbox软件的话,先在BIOS开启CPU虚拟化技术(如果未开启过的话)

现在我们可以使用vagrant快速连接官方镜像仓库,快速下载并安装linux镜像

只需要两步:

  1. 打开cmd窗口,输入vagrant init centos/7
  2. 输入vagrant up(此处是个下载linux镜像的过程,很慢)

1668600551419

Vargrant up相当于先从官方镜像仓库下载一个虚拟机并安装到本地启动。并且用户也会自动创建

vagrant up下载太慢的解决方案来自 https://blog.csdn.net/padawan75/article/details/107520914

也可以使用下载工具下载如下连接:

https://vagrantcloud.com/centos/boxes/7/versions/2004.01/providers/virtualbox.box

如果已经下载完成了镜像,而你不进行下一步操作的话,则在cmd命令行窗口界面会出现以下:

1668600959838

这个时候需要再次输入vagrant up即可再次启动虚拟机,启动完成之后会出现:

1668601113801

因为这个时候你看到在VirtualBox上已经启动了一个linux虚拟机,这个时候在命令行窗口按Ctrl+C就会停止,然后就用vagrant ssh连接虚拟机就可以了。然后如下图即为已经连接到了虚拟机,且可以输入Linux的命令使用了

1668601137171

二、环境-虚拟机网络设置(B站P7集)

1668601186537

1668601288633

这就是配置端口转发(即:访问本机端口3333的时候就会映射到Linux的3306的 端口,就等于访问Linux上的3306端口,但是这样太麻烦,每次在linux上安装一个软件就会设置一次,所以我们现在就希望设置虚拟机Linux的ip为固定IP,然后本机ping我们的Linux的IP就能ping通)

由于刚开始创建的虚拟机默认使用的是上图所示的:网络地址转换(NAT)和端口转发的方式,不方便我们后期开发,所有需要重新设置(PS:后期如果不理解或者忘记,具体详情可以再观看B站视频,原理讲解非强清晰)

1、修改虚拟机网卡/网址

方法有两个:

​ 一、连接上虚拟机,然后修改虚拟机的网卡设置

​ 二、(推荐方法)如下图:修改vagrantfile(在C:\Users\13***文件夹下)

1668601849065

1668601791340

因为ipv4的地址是192.168.56.1,所以我们这个地址就得写192.168.56.几,所以我们写192.168.56.10这个指定的子网地址

现在我们重新使用vagrant reload命令(此命令会用最新的配置文件重新启动虚拟机)。然后再vagrant ssh连接机器,然后使用ip addr 这个命令即可看到我们最新的ip地址已经变成192.168.56.10,而且我们再启动一个cmd命令行窗口,并可以ping得通我们的虚拟机,如下图:

1668602271383

2、修改配置允许ssh工具登录

默认只允许ssh登录方式,为了后来操作方便,文件上传等,我们可以配置允许账号密码登录

1668602338153

具体步骤如下:

1670592039124

三、在Linux下安装docker

1、进入docker官网引导文档 https://docs.docker.com/engine/install/centos/

1668602522494

复制上图内容到cmd命令行窗口(意思是先卸载之前安装的这些东西)

1668602546470

sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine

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

由于之前我们没有安装过docker所以没有匹配到需要卸载的东西

1.2 设置docker仓库

1668602689902

sudo yum install -y yum-utils

sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

1.3 安装docker引擎

1668602744813

sudo yum install docker-ce docker-ce-cli containerd.io

中间有需要选择y/n的,输入y即可

y1.3.0但是这里安装过程中报错: (有时候按Ctrl+C 停止后重新执行可能会OK)

1668602819159

1.4 启动docker

sudo systemctl start docker  // 开启docker

现在在命令行输入:docker -v查看docker版本

再输入docker images 则提示权限不足;我们在命令前面加上sudo提升权限命令即可:

sudo docker images

1.5 设置docker开机自启动

输入 sudo systemctl enable docker 设置为docker开机自启(以后虚拟机一启动则docker也会自动启动)

 sudo systemctl enable docker

1.6 为docker配置下载镜像的加速地址,这样就不用从国外下载镜像了

我们使用淘宝的镜像加速

1668603212864

1、支付宝扫描登录阿里云,找--容器镜像服务--镜像列表--镜像加速器:依次执行以下命令:

sudo mkdir -p /etc/docker

sudo tee /etc/docker/daemon.json <<-'EOF' { "registry-mirrors": ["https://x4zdelnw.mirror.aliyuncs.com"] } EOF

sudo systemctl daemon-reload sudo systemctl restart docker

执行完上面的命令之后就可以重启docker了

sudo systemctl restart docker

1670595010713

1.7 docker安装MySQL

1668603418335

输入sudo docker images就能查看虚拟机里面下载了哪些镜像

每次用sudo提升权限太麻烦,可以用如下设置为root用户: su root
然后这样就可以不用每次加sudu了

可以使用:whereis mysql 查看mysql安装到哪个文件夹里面了

创建MySQL实例并启动

可以使用如下命令启动MySQL:(以如下命令参数配置启动一个docker的容器:MySQL)

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

1668603701443

挂载就是将容器内部的文件夹和文件的快捷方式放到Linux里面,这样以后就就不用以docker exec -it 23d80 /bin/bash 这种命令进入mysql容器内部进行查看这些日志、log配置文件等文件了(然后还得使用exit命令来退出容器等)

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

1670652022481

创建MySQL配置文件:

1668604203022

[client]
default.character-set=utf8

[mysql]
default-character-set=utf8

[mysqld]
init_connect='SET collation_connect
ion = ut8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve

在my.cnf文件中粘贴上述配置文件配置mysql

1668604314564

PS: cd命令进入文件的时候会提示没有,直接使用vi命令创建即可

1.8 docker安装redis==》(B站P11)

1668604383427

由于官方dockerHub上没有文件挂载启动容器的完整命令,所有需要自己编写如下命令启动docker
小坑:由于redis内部没有redis.conf这个文件,所以需要我们先创建

创建mydata文件夹
mkdir -p /mydata/redis/conf
touch /mydata/redis/conf/redis.conf

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

1668604433314

1668604463061

按Ctrl+c 之后按‘:wq ’保存文件 然后用命令:docker restart redis重启redis

四、开发环境统一

1、maven配置jdk1.8编译项目

1675339364506

maven使用阿里云镜像下载加速

这些配置好之后就开始用idea整合maven

1668604630379

1、然后就是在idea中安装插件: lombok、mybatisX

2、安装vscode,并安装很多插件,具体按看视频

3、安装配置git(具体查看其他笔记)
1设置git免密
2在码云上创建仓库

4、逆向工程的使用

5 重启电脑后启动命令总结:

下次关闭重启电脑之后启动上述这些的命令总结:

1、win+R》输入cmd》输入vagrant up(启动linux)》vagrant ssh(ssh连接上虚拟机)》su root》提示输入Password: 输入:vagrant(默认密码)切换root权限》docker ps 查看已经运行的容器》docker start mysql
启动mysql

其他命令总结:

设置redis等容器跟随启动docker的时候自动启动容器,命令如下:

sudo docker update redis或者mysql等 --restart=always

sudo docker update redis --restart=always

1668604827900

五、项目创建

1、在gitee上创建项目代码仓库

1668604928075

初始化仓库:
1、语言选择;2、git提交时忽略提交的文件(选择maven就行)3、开源许可证:不选/也可选一个
2、选择分支模型:图示即可(生产/开发模型==》支持两种分支master和dev)

2、克隆项目

​ 复制仓库地址==》然后打开idea:然后-> File -> new project -> project from Version Control -> Git 输入刚才复制的仓库地址,设置项目存的位置

3、创建项目微服务

​ 右击gulimall项目名--New Module--选择Spring Initializr--输入如下信息

1668604967803

然后点击next -> 先勾选 web依赖和openfeign 两个依赖,其他后期用到的时候再添加然后接着next -> finish

同样新建:商品服务、仓储服务、订单服务、优惠券服务、用户服务
共同的部分(本项目的规范):
1)、web、openfeign(先勾选两个微服务所必须的依赖)
2)、每一个服务,包名com.atuigu.gulimall.xxx(product/order/ware/coupon/member)(红色加粗部分为每一个模块的组织名)
3)、模块名: gulimall-coupon
4)、由于总模块gulimall下面没有pom文件,所以直接从下下边别的模块中随便复制一个pom文件改改就行了:
□ 改description==》聚合服务

1668605135275

5)、配置git版本控制忽略的文件

1668605157850

②安装gitee插件。

1668605196549

4、环境--数据库初始化

(B站p15)

​ 1、配置MySQL和redis在启动lunix虚拟机容器的时候自动启动

​ 1)、使用vagrant up在cmd命令行窗口启动虚拟机之后》》vagrant ssh连接上虚拟机》》使用sudu docker ps 提升权限查看所有的容器镜像》》使用 sudo docker update mysql[或者redis] --restart=always 这个命令》》以后就会在启动虚拟机容器的时候自动启动mysql和redis

​ 2、创建数据库gulimall_oms、gulimall_pms、gulimall_sms、gulimall_ums、gulimall_wms,然后打开相对应的.sql文件》》复制其中内容(一定要复制,不要丢进sqlyang,避免不必要的字符错误等等)》》在sqlyang软件中选中对应的数据库》》新建查询窗口---》》把复制的sql命令粘贴后执行。所有的5个数据库及其内的表就建好了

5、快速开发--人人开源搭建后台管理系统

(B站p16)

使用半成品人人开源后台管理系统进行改造

1668605766386

1、下载renren-fast项目到本地桌面》》打开文件夹删掉其内自带的git文件夹》》粘贴到项目

<modules>  com.atguigu.gulimall
	<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>
	<module>gulimall-common</module>
</modules>

1668605819571

2、打开navicat,为renren-fast单独创建一个数据库gulimall-admin》用上边同样的创建数据库和表的方法 从db文件夹中复制的sql命令粘贴到此 然后执行,则renren-fast项目的配套数据库创建完成

3、修改renren-fast项目的配置文件》连接上刚才我们创建的数据库
url:jdbc:mysql://192.168.56.10:3306/gulimall-admin?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username和password

1668605957367

4、启动renren-fast项目

在vscode上打卡项目并下载好依赖,然后使用 npm run dev 命令启动项目

六、搭建配套前端环境

1、前端内容笔记

前端内容未整理,可以看别的:

1、(134条消息) 【谷粒商城】vue简要笔记_hancoder的博客-CSDN博客

2、其他前端软件和环境

1)、VSCode的安装和使用(B站第12集--最后几分钟)

解决报错

  1. 报错:npm WARN sass-loader@6.0.6 requires a peer of node-sass@^4.0.0 but none is installed. You must install peer dependencies yourself.

    1. 解决办法:参考网站:(多试几次)https://blog.csdn.net/hancoder/article/details/113821646

2)、ES6

3)、Node.js(这6步 教程视频是从这里先讲的

  • 1、官网下载安装node.js,并使用node-v检查版本(使用和视频教程中一样的10.16.3)

  • 2、配置使用淘宝镜像

  • 前端项目第一次运行,使用npm install(下载相关依赖,类似于后端的maven下载依赖)

    • 1 下载完的依赖都在node_modules文件夹下
    • 2 使用npm run dev 命令运行这个前端项目,同时后端配套的renren-fast项目也需要运行起来,进行联调

    • 3 下载renren-generator代码生成器源码,在桌面右击git bash here》git clone 加网址(码云上的下载地址)》下载完成之后,打开文件夹, 把git文件夹删掉》打开我们谷粒商城项目的文件夹,复制到工程同级项目》在总工程下的聚合pom文件中添加<module>renren-generator</module>进行聚合》修改renren-generator的yml配置文件,连接到我们需要逆向生成的数据库》修改generator.properties文件,如下

    • 1668606711192

      • 4 登录http://localhost/使用renren-generator生成代码(具体看视频P17)。新建common模块,把公共的类都放在这里即每一个微服务公共的依赖,bean,工具类等;其他需要这些的模块的直接依赖此模块就行了
      • 5 启动renre-generator生成代码,然后复制到product模块下(resources文件夹下的src整个文件夹是前端的view文件 用不到,删掉就行);并解决爆红问题(依赖和工具类从renren-fast模块中复制即可)
    • 6 测试

七、测试微服务基本CRUD功能

快速开发-配置&测试微服务基本CRUD功能

1、 整合mybaties-plus

  • 1 配置数据源

    • 导入数据的驱动,从maven Repository网址中搜索MySQL connector ,找到我们数据库版本对应的
    • 导入servlet依赖(设置)

      <**groupId**>javax.servlet</**groupId**>
      
      <**artifactId**>servlet-api</**artifactId**>
      
      <**version**>2.5</**version**>
      
      <**scope**>provided</**scope**>
      
  • 在application.yml配置数据源相关信息

spring:
  datasource:
#    driver-class-name: com.mysql.jdbc.Driver
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: localMysql
#    url: jdbc:mysql://192.168.56.10:3306/gulimall_pms
    url: jdbc:mysql://localhost:3306/gulimall_pms?serverTimezone=UTC
  • 配置mybatisPlus

    1. 在启动类上使用@MapperScan(作用:告诉mybatisPlus我们的mapper文件都是在哪里?)
    2. @MapperScan("com.atguigu.gulimall.product.dao")
mybatis-plus:
#  mapper-locations: classpath* # 这里classpath后面带*和不带*区别:带* 会扫描所有的,不带就只会扫描自己的
  mapper-locations: classpath*:/mapper/**/*.xml   # 告诉MybatisPlus 我们的SQL文件在哪里(这个如果不写也是这个默认值,可以点进去看一下是不是
  
  global-config: # 全局的主键策略
    db-config:
      id-type: auto 
      # 配置逻辑删除(1 已经删除, 0 未删除)
      logic-delete-value: 1
      logic-not-delete-value: 0
  configuration:
    # 运行的时候输出mybatis日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

如果不想一个一个手动修改entity实体类中的@TableId属性修改为自增id的话,可以在yml文件中配置全局的主键策略: 如上

测试:

  1. 需要在@SpringBootTest注解上加@RunWith(SpringRunner.class)
  2. 报错:

解决java.lang.IllegalStateException: Unable to find a @Sp解决java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration, you need to useringBootConfiguration, you need to use

来自 https://blog.csdn.net/qq_25406669/article/details/87966497

启动类所在的包和单元测试的包不在同一级根目录下

其他前端环境报错:略

【项目环境报错】:

一、Linux相关报错:

1、Linux虚拟机硬盘满了

Error number 28 means 'No space left on device'

参考文章如下:

使用vagrant管理虚拟机导致内存占满,docker的mysql、redis自动启动失败。

https://blog.csdn.net/qq_41082640/article/details/117912680

https://blog.csdn.net/xtb666666/article/details/115290050

二、搭建环境问题:bug和报错

  1. 用IDE用IDEA创建springboot项目时main方法无法运行A创建springboot项目时main方法无法运行,注解字体颜色和普通一样 无法按住Crtl点进去,且在在如下图示中的模块名称为灰色,

1668606448828

  1. 创建好此工程之后,启动会报错:

1668606488792

1668606492927

解决办法:

​ 原因:这是因为:
​ spring boot 2.2之前使用的是 Junit4
​ spring boot 2.2之后使用的是 Junit5
​ 而我们使用spring Initializr创建的项目是使用的springboot版本比较新是2.5.3的,在我们改成2.1.8的时候就会使用Junit4,使用的依赖jar包不同 导致报错

https://www.jianshu.com/p/bdd22240fe4b https://www.cnblogs.com/suhaha/p/12050040.html 这两个文章讲的很清楚
如果@Test测试类还是报错的话,有可能是@RunWith(SpringRunner.class)不能加 @RunWith(SpringRunner.class)//****不使用此注解会导致@Autowired**注入失败,报错空指针异常*

3.解决上述问题之后又会报错:NoClassDefFoundError(总结在下边)

看到NoClassDefFoundError 想到的就是缺架包或者架包有问题

因为我的做的是一个spirng + springmvc的测试

之所以报这个错误是因为dependency依赖中的spring-webmvc版本过高了,spring-webmvc的版本比spring-web还要高,我把spring-webmvc 版本改低之后重启就成功了!!

参考文章: https://blog.csdn.net/qq_42651904/article/details/87940354

总结:可能就是我们使用spring Initializr创建的项目勾选的OpenFeign的版本过高,导致和我们修改后的springboot 2.1.8版本不兼容

上述bug总结原因:大部分是因为按照视频中使用spring Initializr创建的项目会使用最新的版本,然后我们又改成和视频教程中一样的2.1.8的版本,但是其他像junit text 和openFeign的依赖还是最新的版本,所以导致因为版本过高和2.1.8的springBoot依赖冲突了,所以导致问题较多。

==》最省事的解决办法:创建项目的时候什么依赖都不要勾选,后期添加

三、跨域问题P47

报错问题描述:已拦截跨源请求:同源策略禁止8001端口页面读取位于 http://localhost:88/api/sys/login 的远程资源。(原因:CORS 头缺少 ‘Access-Control-Allow-Origin’)。

问题分析:这是一种跨域问题。访问的域名或端口和原来请求的域名端口一旦不同,请求就会被限制

  • 跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对js施加的安全限制。(ajax可以)

  • 同源策略:是指协议,域名,端囗都要相同,其中有一个不同都会产生跨域;

URL 说明 是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下 允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不同文件夹 允许
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不同端口 不允许
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不同协议 不允许
http://www.a.com/a.js
http://70.32.92.74/b.js
域名和域名对应ip 不允许
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不同 不允许
http://www.a.com/a.js
http://a.com/b.js
同一域名,不同二级域名(同上) 不允许(cookie这种情况也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js
不同域名 不允许

跨域流程:

这个跨域请求的实现是通过预检请求实现的,先发送一个OPSTIONS探路,收到响应允许跨域后再发送真实请求

什么意思呢?跨域是要请求的、新的端口那个服务器限制的,不是浏览器限制的。

1675341779380

跨域的解决方案

  • 方法1:设置nginx包含admin和gateway。都先请求nginx,这样端口就统一了
  • 方法2:让服务器告诉预检请求能跨域
解决方案1:

1675341436886

我们在开发期间采用第二种方案:如下(在网关中配置)

解决方案2:

为在服务端2配置允许跨域

在响应头中添加:参考:https://blog.csdn.net/qq_38128179/article/details/84956552

  • Access-Control-Allow-Origin : 支持哪些来源的请求跨域

  • Access-Control-Allow-Method : 支持那些方法跨域

  • Access-Control-Allow-Credentials :跨域请求默认不包含cookie,设置为true可以包含cookie

  • Access-Control-Expose-Headers : 跨域请求暴露的字段

    • CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:
      Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma
      如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
  • Access-Control-Max-Age :表明该响应的有效时间为多少秒。在有效时间内,浏览器无须为同一请求再次发起预检请求。请注意,浏览器自身维护了一个最大有效时间,如果该首部字段的值超过了最大有效时间,将失效
    解决方法:在网关中定义“GulimallCorsConfiguration”类,该类用来做过滤,允许所有的请求跨域。

    package com.atguigu.gulimall.gateway.config;
    
    @Configuration // gateway
    public class GulimallCorsConfiguration {
    
        //现在我们只需要把spring提供的CorsWebFilter类放到容器中即可生效
        @Bean // 在容器中添加过滤器 忘记写这个注解会无效    
        public CorsWebFilter corsWebFilter(){
            // 基于url跨域,选择reactive包下的
            UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
            // 跨域配置信息
            CorsConfiguration corsConfiguration = new CorsConfiguration();
            // 允许跨域的头
            corsConfiguration.addAllowedHeader("*");
            // 允许跨域的请求方式
            corsConfiguration.addAllowedMethod("*");
            // 允许跨域的请求来源
            corsConfiguration.addAllowedOrigin("*");
            // 是否允许携带cookie跨域
            corsConfiguration.setAllowCredentials(true);
            
           // 任意url都要进行跨域配置
            source.registerCorsConfiguration("/**",corsConfiguration);
            return new CorsWebFilter(source);
        }
    }
    

    再次访问:http://localhost:8001/#/login

1675341581048

http://localhost:8001/renren

已拦截跨源请求:同源策略禁止读取位于 http://localhost:88/api/sys/login 的远程资源。

(原因:不允许有多个 ‘Access-Control-Allow-Origin’ CORS 头)

renren-fast/captcha.jpg?uuid=69c79f02-d15b-478a-8465-a07fd09001e6

出现了多个请求,并且也存在多个跨源请求。

为了解决这个问题,需要修改renren-fast项目,注释掉“io.renren.config.CorsConfig”类。然后再次进行访问。

四、 product请求路径重写

(B站P48集)

登录进入后台之后》》点击商品系统》》商品分类,会有如下报错:

1675341987343

五、使用最新2022.3版本idea报错:

使用2022.3最新版idea报错:

https://blog.csdn.net/spjhandsomeman/article/details/125112733

使用最新版Lombok,解决报错,

参考如下:

https://blog.csdn.net/weixin_46133147/article/details/128458763

idea社区版,更改UTF-8编码

修改前

1675603463233

【2 分布式系统环境搭建】

1、SpringCloud Alibaba简介

简介(略)技术选型原因:

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,即分布式事务解决方案

3)、版本选择
由于 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

4)、项目中的依赖

在common组件中加入如下版本依赖管理,以后其他组件依赖的common组件后,如果使用spring-cloud-alibaba相关starter就不需要再写版本号了

    <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>
  1. 参考官方文档spring.io网址
  2. 参考GitHub的springCloud Alibaba项目组件(可下载(有中文文档))

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

Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理
平台。他是使用 java 编写。需要依赖 java 环境
Nacos 文档地址: https://nacos.io/zh-cn/docs/quick-start.html

1)、下载 nacos-server
https://github.com/alibaba/nacos/releases

2)、启动 nacos-server
 双击 bin 中的 startup.cmd 文件
 访问 http://localhost:8848/nacos/
 使用默认的 nacos/nacos 进行登录

3)、将微服务注册到 nacos 中
1、首先,修改common模块的 pom.xml 文件,引入 Nacos Discovery Starter。

  <!--        服务注册/发现-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

2、在应用的 /src/main/resources/application.properties 配置文件中配置 Nacos Server 地址

spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848

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

@SpringBootApplication
@EnableDiscoveryClient
public class ProviderApplication {
    
    public static void main(String[] args) {

        SpringApplication.run(Application.class, args);
        }
}

4、启动应用,观察 nacos 服务列表是否已经注册上服

注意:每一个应用都应该有名字,这样才能注册上去。修改 application.properties 文件

spring.application.name=service-provider
server.port=8000

或者在yml文件中写:

1668608721702

5、注册其他所有的服务上去,测试使用 feign 远程调用

总结

Nacos 使用三步:
1、导包 nacos-discovery
2、写配置,指定 nacos 地址,指定应用的名字
3、开启服务注册发现功能@EnableDiscoveryClient

Feign 使用三步
1、导包 openfeign
2、开启@EnableFeignClients 功能
3、编写接口,进行远程调用

@FeignClient("stores")
public interface StoreClient {
    
	@RequestMapping(method = RequestMethod.GET, value = "/stores")
	List getStores();

	@RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
	Store update(@PathVariable("storeId") Long storeId, Store store);
}

6、更多配置
https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md#more

3、SpringCloud Alibaba-Nacos[作为配置中心]

1、pom.xml 引入 Nacos Config Starter。

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

2、在应用的 /src/main/resources/bootstrap.properties 配置文件中配置 Nacos Config 元数据

pring.application.name=nacos-config-example
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

# 主要配置应用名和配置中心地址

3、在 nacos 中添加配置

在 nacos 中创建一个 应用名.properties 配置文件并编写配置

Nacos Config 数据结构
Nacos Config 主要通过 dataId 和 group 来唯一确定一条配置。
Nacos Client 从 Nacos Server 端获取数据时,调用的是此接口 ConfigService.getConfig(String dataId, String group, long timeoutMs)。

Spring Cloud 应用获取数据
dataID:
在 Nacos Config Starter 中,dataId 的拼接格式如下

  • ${prefix} - ${spring.profiles.active} . ${file-extension} prefix 默认为 spring.application.name
    的值,也可以通过配置项 spring.cloud.nacos.config.pref ix 来配置。
  • spring.profiles.active 即为当前环境对应的 profile

注意,当 activeprofile 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成${prefix}.${file-extension}
file-extension 为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension 来配置。 目前只支持 properties 类型。

Group:
Group 默认为 DEFAULT_GROUP,可以通过 spring.cloud.nacos.config.group 配置。

4、在应用中使用@Value 和@RefreshScope

完成上述两步后,应用会从 Nacos Config 中获取相应的配置,并添加在 Spring Environment的 PropertySources 中 。 这 里 我 们 使 用 @Value 注 解 来 将 对 应 的 配 置 注 入 到SampleController 的 userName 和 age 字段,并添加 @RefreshScope 打开动态刷新功能

@RefreshScope
class SampleController {
    
    @Value("${user.name}")
    String userName;
    @Value("${user.age}")
    int age;
}

5、进阶

1、核心概念

命名空间:
用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

配置集:
一组相关或者不相关的配置项的集合称为配置集。在系统中,一个配置文件通常就是一个配置集,包含了系统各个方面的配置。例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。

配置集 ID:
Nacos 中的某个配置集的 ID。配置集 ID 是组织划分配置的维度之一。Data ID 通常用于组织划分系统的配置集。一个系统或者应用可以包含多个配置集,每个配置集都可以被一个有意义的名称标识。Data ID 通常采用类 Java 包(如 com.taobao.tc.refund.log.level)的命名规则保证全局唯一性。此命名规则非强制。

配置分组:
Nacos 中的一组配置集,是组织配置的维度之一。通过一个有意义的字符串(如 Buy 或Trade )对配置集进行分组,从而区分 Data ID 相同的配置集。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:不同的应用或组件使用了相同的配置类型,如 database_url 配置和MQ_topic 配置。

2、原理

自动注入:
NacosConfigStarter 实现了 org.springframework.cloud.bootstrap.config.PropertySourceLocator
接口,并将优先级设置成了最高。

在 Spring Cloud 应用启动阶段,会主动从 Nacos Server 端获取对应的数据,并将获取到的数据转换成 PropertySource 且注入到 Environment 的 PropertySources 属性中,所以使用@Value 注解也能直接获取 Nacos Server 端配置的内容

动态刷新:
Nacos Config Starter 默认为所有获取数据成功的 Nacos 的配置项添加了监听功能,在监听到服务端配置发生变化时会实时触发org.springframework.cloud.context.refresh.ContextRefresher 的 refresh 方法 。如果需要对 Bean 进行动态刷新,请参照 Spring 和 Spring Cloud 规范。推荐给类添加@RefreshScope 或 @ConfigurationProperties 注解

3、同时加载多配置文件

spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=31098de9-fa28-41c9-b0bd-c754ce319ed4

# 下面是数组形式的,可以添加多个配置文件
spring.cloud.nacos.config.ext-config[0].data-id=gulimall-datasource.yml
spring.cloud.nacos.config.ext-config[0].refresh=false
spring.cloud.nacos.config.ext-config[0].group=dev

1)、微服务任何配置信息,任何配置文件都可以放在配置中心中

2)、只需要在bootstrap.properties说明加载配置中心中哪些配置文件即可

3)、@Value,@ConfigurationProperties。。。

以前SpringBoot任何方法从配置文件中获取值,都能使用。

配置中心有的优先使用配置中心中的,

4、namespace 与 group 最佳实践
每个微服务创建自己的 namespace 进行隔离,group 来区分 dev,beta,prod 等环境

SpringCloud

1、Feign 声明式远程调用

1、简介

Feign 是一个声明式的 HTTP 客户端,它的目的就是让远程调用更加简单。Feign 提供了 HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好 HTTP 请求的参数、格式、地址等信息。

Feign 整合了 Ribbon(负载均衡)和 Hystrix(服务熔断),可以让我们不再需要显式地使用这两个组件。

SpringCloudFeign 在 NetflixFeign 的基础上扩展了对 SpringMVC 注解的支持,在其实现下,我们只需创建一个接口并用注解的方式来配置它,即可完成对服务提供方的接口绑定。简化了SpringCloudRibbon 自行封装服务调用客户端的开发量。

2、使用

1、引入依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-openfeign </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、原理

1668611324126

4、Feign源码分析

参考文章:

1、(134条消息) 谷粒商城高级篇上(未完待续)_唐尧同学的博客-CSDN博客

2、Gateway

1、简介

网关作为流量的入口,常用功能包括路由转发、权限校验、限流控制等。而 springcloud gateway
作为 SpringCloud 官方推出的第二代网关框架,取代了 Zuul

网关提供 API 全托管服务,丰富的 API 管理功能,辅助企业管理大规模的 API,以降低管理成本和安全风险,包括协议适配、协议转发、安全策略、防刷、流量、监控日志等功能。

Spring Cloud Gateway 旨在提供一种简单而有效的方式来对 API 进行路由,并为他们提供切
面,例如:安全性,监控/指标 和弹性等。
官方文档地址:
https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.3.RELEASE/single/spring-cloud-gateway.html

Spring Cloud Gateway 特点:

  •  基于 Spring5,支持响应式编程和 SpringBoot2.0
  •  支持使用任何请求属性进行路由匹配
  •  特定于路由的断言和过滤器
  •  集成 Hystrix 进行断路保护
  •  集成服务发现功能
  •  易于编写 Predicates 和 Filters
  •  支持请求速率限制
  •  支持路径重写

思考:

为什么使用 API 网关?

API 网关出现的原因是微服务架构的出现,不同的微服务一般会有不同的网络地址,而外部
客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服
务通信,会有以下的问题:

  •  客户端会多次请求不同的微服务,增加了客户端的复杂性。
  •  存在跨域请求,在一定场景下处理相对复杂。
  •  认证复杂,每个服务都需要独立认证。
  •  难以重构,随着项目的迭代,可能需要重新划分微服务。例如,可能将多个服务合并成一个或者将一个服务拆分成多个。如果客户端直接与微服务通信,那么重构将会很难实施。
  •  某些微服务可能使用了防火墙 / 浏览器不友好的协议,直接访问会有一定的困难。

以上这些问题可以借助 API 网关解决。API 网关是介于客户端和服务器端之间的中间层,所有的外部请求都会先经过 API 网关这一层。也就是说,API 的实现方面更多的考虑业务逻辑,而安全、性能、监控可以交由 API 网关来做,这样既提高业务灵活性又不缺安全性:
使用 API 网关后的优点如下:

  • 易于监控。可以在网关收集监控数据并将其推送到外部系统进行分析。
  • 易于认证。可以在网关上进行认证,然后再将请求转发到后端的微服务,而无须在每个微服务中进行认证。
  • 减少了客户端与各个微服务之间的交互次数。

2、核心概念

  • 路由。路由是网关最基础的部分,路由信息有一个 ID、一个目的 URL、一组断言和一组Filter 组成。如果断言路由为真,则说明请求的 URL 和配置匹配
  • 断言。Java8 中的断言函数。Spring Cloud Gateway 中的断言函数输入类型是 Spring5.0 框架中的 ServerWebExchange。Spring Cloud Gateway 中的断言函数允许开发者去定义匹配来自于 http request 中的任何信息,比如请求头和参数等。
  • 过滤器。一个标准的 Spring webFilter。Spring cloud gateway 中的 filter 分为两种类型的Filter,分别是 Gateway Filter 和 Global Filter。过滤器 Filter 将会对请求和响应进行修改处理

工作原理:

1668611596071

客户端发送请求给网关,弯管 HandlerMapping 判断是否请求满足某个路由,满足就发给网关的 WebHandler。这个 WebHandler 将请求交给一个过滤器链,请求到达目标服务之前,会执行所有过滤器的 pre 方法。请求到达目标服务处理之后再依次执行所有过滤器的 post 方法。

一句话:满足某些断言(predicates)就路由到指定的地址(uri),使用指定的过滤器(filter)

3、使用

1、HelloWorld

1、创建网关项目,引入网关依赖

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

2、编写网关配置文件

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


        # 配置到商品服务的路由
        #现在想看Gateway加简单服务的压测,gateway除了映射/api/product 以外,还来映射/hello请求,因为不是api请求,也不用截串
        - id: product_route
          uri: lb://gulimall-product
          predicates:
            - Path=/api/product/**,/hello
          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  # lb表示负载均衡,后边直接写//+服务名
          predicates:
            - Path=/api/**  # 路由规则:路径断言--前端项目都带/api(为了区分前端项目)
          filters:
            - RewritePath=/api/(?<segment>.*),/renren-fast/$\{segment}  # 参考文档,重写路径:如果符合前面的路径规则,则用后面的替代,效果如下:
            ### http://localhost:88/api/captcha.jpg  路径重写成==>  http://localhost:8080/renren-fast/captcha.jpg 会把前面的api去掉 ,然后组装成后边的url

3、注意

  •  各种 Predicates 同时存在于同一个路由时,请求必须同时满足所有的条件才被这个路由匹配。
  •  一个请求满足多个路由的谓词条件时,请求只会被首个成功匹配的路由转发

4、测试
可以使用 postman 进行测试网关的路由功能

2、断言(Predicates)

1668611883123

例:主机路由:
#   配置nginx到网关后再转到商品服务的配置(P140  6:30处)
        - id: gulimall_host_route
          uri: lb://gulimall-product
          predicates:
            - Host=**.gulimall.com,gulimall.com # 注意这里是以主机配置的断言路由规则

1675430765593

例2:输入 http://gulimall.com/api/product/brand/list 则可以使用如下配置经网关路由到商品服务

      - id: product_route
        uri: lb://gulimall-product
        predicates:
          - Path=/api/product/**,/hello # 以/api/product/开头的和/hello路径都会转到商品服务
        filters:
          - RewritePath=/api/(?<segment>.*),/$\{segment}
3、过滤器(filters)

1、GatewayFilter

1668611899656

2、GlobalFilter

1668611936737

ES环境搭建

P123

nginx环境搭建

P124

方式一:本机linux环境安装

安装并启动nginx(如果本机还没有安装则会下载)

docker run -p 80:80 --name nginx  -d nginx:1.10
# 本次我们安装的nginx主要是为了获取其配置文件,将其copy出来

下面是具体连接命令执行步骤

连接成功 // 刚连接成功我们的虚拟机
Last login: Fri Dec  9 14:41:42 2022 from 192.168.56.1
    
[root@localhost ~]# ls
anaconda-ks.cfg  original-ks.cfg

[root@localhost ~]# cd /home/	
[root@localhost home]# ls
vagrant

[root@localhost home]# cd vagrant/
[root@localhost vagrant]# ls
[root@localhost vagrant]# ls -a
.  ..  .bash_history  .bash_logout  .bash_profile  .bashrc  .ssh

[root@localhost vagrant]# docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                                        NAMES
2cd4b2b077d2   redis        "docker-entrypoint.s…"   2 minutes ago    Up 2 minutes    0.0.0.0:6379->6379/tcp, :::6379->6379/tcp    redis
0eee5b901c80   nginx:1.10   "nginx -g 'daemon of…"   34 minutes ago   Up 34 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp   nginx

[root@localhost vagrant]# cd /mydata/   	// 注意:此文件夹在根目录下
[root@localhost mydata]# ll 
total 0
drwxr-xr-x. 4 root root 30 Dec  9 14:44 redis
[root@localhost mydata]# pwd
/mydata


// 进入mydata文件夹后,执行下面的命令将nginx容器里面的/etc/nginx文件夹下所有的文件都复制到当前文件夹下
[root@localhost mydata]# docker container cp nginx:/etc/nginx . //别忘了此处这个点和空格
[root@localhost mydata]# ls
nginx  redis
// 可以看到多了一个nginx文件夹,下面进入nginx文件夹即可看到我们从nginx容器里复制过来的文件

[root@localhost mydata]# cd nginx/
[root@localhost nginx]# ls
conf.d  fastcgi_params  koi-utf  koi-win  mime.types  modules  nginx.conf  scgi_params  uwsgi_params  win-utf


// 下面nginx就没有用了,我们停止并删掉即可
[root@localhost nginx]# docker stop nginx 
nginx
[root@localhost nginx]# docker rm nginx 
nginx


// 为了目录清晰,我们将从nginx容器复制过来的nginx文件夹改名为conf,然后再新建一个nginx文件夹并将conf文件夹放进去
[root@localhost nginx]# cd ../
[root@localhost mydata]# ls
nginx  redis
[root@localhost mydata]# mv nginx conf
[root@localhost mydata]# ls
conf  redis
[root@localhost mydata]# mkdir nginx
[root@localhost mydata]# ls
conf  nginx  redis
[root@localhost mydata]# mv conf nginx/
[root@localhost mydata]# ls
nginx  redis
[root@localhost mydata]# cd nginx/
[root@localhost nginx]# ls
conf
[root@localhost nginx]# pwd
/mydata/nginx

// 现在我们再创建一个新的nginx容器
[root@localhost nginx]# docker run -p 80:80 --name nginx \
> -v /mydata/nginx/html:/usr/share/nginx/html \
> -v /mydata/nginx/logs:/var/log/nginx \	// 将日志信息映射到logs文件下
> -v /mydata/nginx/conf:/etc/nginx \
> -d nginx:1.10
ed6fc7bcdd24704687d65d964576c57122ebd1ec1d98298493c37a9d6d855743
[root@localhost nginx]# docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS                                        NAMES
ed6fc7bcdd24   nginx:1.10   "nginx -g 'daemon of…"   7 seconds ago   Up 6 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp   nginx
2cd4b2b077d2   redis        "docker-entrypoint.s…"   8 minutes ago   Up 8 minutes   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp    redis
[root@localhost nginx]# 

下次启动的时候如果nginx容器没有启动,则可以使用docker start nginx启动nginx
 

下面是无注释的命令备份(用于复制命令)

连接成功 // 刚连接成功
Last login: Fri Dec  9 14:41:42 2022 from 192.168.56.1
[root@localhost ~]# ls
anaconda-ks.cfg  original-ks.cfg
[root@localhost ~]# cd /home/
[root@localhost home]# ls
vagrant
[root@localhost home]# cd vagrant/
[root@localhost vagrant]# ls
[root@localhost vagrant]# ls -a
.  ..  .bash_history  .bash_logout  .bash_profile  .bashrc  .ssh
[root@localhost vagrant]# docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED          STATUS          PORTS                                        NAMES
2cd4b2b077d2   redis        "docker-entrypoint.s…"   2 minutes ago    Up 2 minutes    0.0.0.0:6379->6379/tcp, :::6379->6379/tcp    redis
0eee5b901c80   nginx:1.10   "nginx -g 'daemon of…"   34 minutes ago   Up 34 minutes   0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp   nginx
[root@localhost vagrant]# cd /mydata/
[root@localhost mydata]# ll 
total 0
drwxr-xr-x. 4 root root 30 Dec  9 14:44 redis
[root@localhost mydata]# pwd
/mydata
[root@localhost mydata]# docker container cp nginx:/etc/nginx .
[root@localhost mydata]# ls
nginx  redis
[root@localhost mydata]# cd nginx/
[root@localhost nginx]# ls
conf.d  fastcgi_params  koi-utf  koi-win  mime.types  modules  nginx.conf  scgi_params  uwsgi_params  win-utf
[root@localhost nginx]# docker stop nginx 
nginx
[root@localhost nginx]# docker rm nginx 
nginx
[root@localhost nginx]# cd ../
[root@localhost mydata]# ls
nginx  redis
[root@localhost mydata]# mv nginx conf
[root@localhost mydata]# ls
conf  redis
[root@localhost mydata]# mkdir nginx
[root@localhost mydata]# ls
conf  nginx  redis
[root@localhost mydata]# mv conf nginx/
[root@localhost mydata]# ls
nginx  redis
[root@localhost mydata]# cd nginx/
[root@localhost nginx]# ls
conf
[root@localhost nginx]# pwd
/mydata/nginx
[root@localhost nginx]# docker run -p 80:80 --name nginx \
> -v /mydata/nginx/html:/usr/share/nginx/html \
> -v /mydata/nginx/logs:/var/log/nginx \
> -v /mydata/nginx/conf:/etc/nginx \
> -d nginx:1.10
ed6fc7bcdd24704687d65d964576c57122ebd1ec1d98298493c37a9d6d855743
[root@localhost nginx]# docker ps
CONTAINER ID   IMAGE        COMMAND                  CREATED         STATUS         PORTS                                        NAMES
ed6fc7bcdd24   nginx:1.10   "nginx -g 'daemon of…"   7 seconds ago   Up 6 seconds   0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp   nginx
2cd4b2b077d2   redis        "docker-entrypoint.s…"   8 minutes ago   Up 8 minutes   0.0.0.0:6379->6379/tcp, :::6379->6379/tcp    redis
[root@localhost nginx]# 

现在在浏览器中输入http://192.168.56.10/即可访问我们刚才在虚拟机中搭建的nginx

但是此时nginx中并没有欢迎页面,而是出乎意料的出现403...我们下面简单写个欢迎页面,防止nginx文件夹下的html文件夹中即可(会默认访问)

root@localhost nginx]# ls
conf  html  logs
[root@localhost nginx]# cd html/ 
[root@localhost html]# vi index.html 
1、然后按键i
2、接着输入测试欢迎页代码,如下:
<h1>192.168.56.10---Linux---Gulimall<h1/>
3、然后按ESC键,再按  :wq
4、然后在浏览器中重新访问即可看到

1675345369706

查看nginx报错日志:

docker logs nginx

1675346057724

没有的话设置nginx容器自动启动: sudo docker update nginx --restart=always

方式二:本机Windows环境

1、安装并测试nginx

下载nginx,然后进行如下配置:

1)、找到host文件

位置在:C:\WINDOWS\system32\drivers\etc

在最下面增加如下一行:

127.0.0.1		gulimall.com
2)、nginx配置文件

在D:\workSpace\nginx-1.18.0\conf下有个nginx.conf文件,用记事本打卡,修改配置如下:

	#在server块的配置如下
	
	#配置谷粒商城gulimall.com访问P139
	server {
		listen       80;	# 配置监听的端口
		server_name  gulimall.com;	# 配置监听的域名

		#charset koi8-r;

		#access_log  logs/host.access.log  main;

		location / {
			proxy_pass  http://127.0.0.1:10001;	# 配置监听到请求后转发到的地方
		}
	}

2、配置nginx的负载均衡:

p140 nginx官网:https://nginx.org/en/docs/http/load_balancing.html

1670508778962

配置如下:

# 在http块配置如下:

	# 配置谷粒商城负载均衡的上游服务器 (20221208先注释掉)
	upstream gulimall{
		# 如果我们启动了多个网关的话,这个server可以写多个
		server 127.0.0.1:88; # server后面跟服务器的地址,可以写多个
		# 也可写server 192.168.56.1:88 (因为192.168.56.1也是我们本机网卡的地址,也表示本机)
	}

	server {# 这里是server块
		listen       80;
		server_name  gulimall.com;
    
		#charset koi8-r;
    
		#access_log  logs/host.access.log  main;
    
		location / {
			# proxy_pass  http://127.0.0.1:10001; # 这里就不直接代理给我们的商品服务了
			# ,现在代理给我们之前配置的上游服务器
			proxy_pass  http://gulimall; # 这里写的是上面第4行upstream后面的gulimall
		}
	}

商城业务-nginx-搭建域名访问环境(反向代理配置)

P139

结合以前的nginx搭建出域名访问环境,nginx现在安装在虚拟机里面,讲es的时候安装了nginx做了分词器,将分词器的内容放在了里面,远程请求nginx返回分词器的数据,nginx,在以后的项目中经常使用它的反向代理,和负载均衡

1675346298725

正向与方向相对于自己这台电脑来说,帮我们去上网的就是正向代理,帮助对方服务器了就是反向代理。

正向代理:我们想要访问谷歌,搭建一台代理服务器,为电脑配置上代理服务器的地址,电脑想访问任何网址,都由代理服务器帮我们去访问,访问拿到内容后帮我们返回,所以看到的是搭建的这台服务器是帮我们进行上网。

反向代理:搭建集群环境的时候非常需要,比如任何人去访问谷粒商城,谷粒商城有我们的后台服务集群,这些服务集群,每一个服务器,都可能都要在内网部署,这是一个内网ip,不可能把服务器的外网ip暴露给外界,这样容易引起攻击。这样做的话,整个服务器内网服务器集群,为了能找到他们,在他们前面前置一个服务器,把这个服务器叫做反向代理,比如前置一个nginx,nginx是拥有公网ip,大家都可以进行访问的。但是访问公网服务器,真正的项目是在内网集群部署的,所以由nginx代转给我们的服务集群,而这个nginx也是和我们的服务集群搭建在一个服务环境里面的。nginx可以帮我们找到服务集群在哪里。nginx相当于对外界屏蔽了我们整个内网服务集群的信息。比如商品服务在哪个ip地址,订单服务在哪个ip地址,我们现在都不知道。

正向代理就不是屏蔽了互联网信息,google的ip地址大家都知道,就是访问不了,所以反向代理是代价项目环境的时候,是一定要用到的。

利用这个功能,用nginx作为反向代理,请求gulimall的时候,先来到nginx,由nginx转交给我们的后台服务集群,这台nginx就拥有一个外网ip,这个外网ip就是大家公众都能访问的,每一个内网服务集群都只有内网ip地址,192.168这个地址仅限于局域网内部,出了这个局域网,大家都访问不到,所以就用nginx作为反向代理服务器,来完成整个的域名功能,但是想完成整个域名环境,先分析一下流程。

首先机器来访问gulimall,以本机环境为例,本机想访问gulimall.com 默认的访问流程,比如我们想访问www.baidu.com. 这个请求先会被网络的dns进行解析,解析出百度的ip地址到底在哪里,然后我们的浏览器就会访问到ip地址对应的内容,正是这个域名解析,没有购买gulimall的这个域名,但是可以在windows的host文件里面配置对应域名对应哪个ip地址,比如在浏览器敲gulimall.com,windows怎么知道,对应哪个ip地址?第一个先查看自己系统内部的域名映射规则,如果这个域名已经有映射了,浏览器就可以直接去这个地址,这是网卡带我们直接转过去的,接下来第二个,系统内部没有说gulimall在哪个地址,想要访问,先去网络上的dns,之前配linux系统的时候,配的备用dns 114.114.114.114还有8.8.8.8,解析出我们的域名,dns保存了哪一个域名对应哪一个ip地址,这只不过是在公网保存的。解析到ip地址后,然后转到对应的ip地址,所以基于这个原理,可以直接配置,gulimall.com域名在哪,直接来到指定的ip地址。那指定的ip地址在哪里呢,由于我们把nginx安装在了虚拟机上,所以可以让域名指定虚拟机的ip地址,

1675346328855

es和kibana都可以访问成功

1675346344472

以后每个系统都有对应的域名,都是访问虚拟机的ip地址,

直接访问gulimall.com也可看到nginx正常启动(能访问的欢迎页html)

现在已经根据域名访问到nginx,接下来还要访问到项目,可以让nginx把所有的请求转给我们的网关,由网关再代转给每一个项目。当然也可以让nginx直接转给指定的项目,比如一看是访问的是gulimall.com,想要展示首页,相当于gulimall.com来到的所有请求,都给我转发到localhost:10000端口,也就是商品项目,拥有页面首页的内容,但是这样做不好,未来product项目部署多台的时候,有可能端口不一样,ip地址也不一样,每次都要修改nginx,让gulimall.com来的请求都转到10000端口。

我们先来这个最快的配置但是有局限性的配置-将gulimall请求直接转到10000端口

1675346403224

解决nginx丢Host报错

现在我们在window本机宿主机的hosts文件中更改域名解析配置:如下:

127.0.0.1		gulimall.com 

然后我们在浏览器中输入gulimall.com 后敲回车想由网关转到商品服务访问的时候发现还是报错,不能访问:

1675432007639

这是因为nginx默认在转发给网关的时候会丢失Host信息,所以我们需要在nginx配置文件中配置再加上proxy_set_header Host $host;,如下:(加上后会发现通过http://gulimall.com/可以访问到主页了)

	# 配置谷粒商城负载均衡的上游服务器 (20221208先注释掉,20230203又放开注释)
	upstream gulimall{
		# 如果我们启动了多个网关的话,这个server可以写多个
		# server 127.0.0.1:88;
		server 192.168.110.1:88;
	}

	server {
		listen       80;
		server_name  gulimall.com;
    
		#charset koi8-r;
    
		#access_log  logs/host.access.log  main;
    
		location / {
			proxy_set_header  Host $host; # 因为nginx默认在转发给网关的时候会丢失Host信息,所以我们需要在此加上
			# proxy_pass  http://127.0.0.1:10001; # 这里就不直接代理给我们的商品服务了
			# ,现在代理给我们之前配置的上游服务器
			proxy_pass  http://gulimall;
		}
	}

其实nginx不知会丢失Host信息,还有其他想cookie等信息也会丢失,后面用到再说

此处还需要注意在gateway网关中的配置顺序,因为网关在匹配的时候会由上往下匹配(否则http://gulimall.com/api/开头的路径则匹配不到了,因为会先匹配Host信息而不会轮到匹配- Path=/api/product/**,/hello这个规则了)

#   配置nginx到网关后再转到商品服务的配置(P140  6:30处)注意配置顺序,此处应该放到最下方
        - id: gulimall_host_route
          uri: lb://gulimall-product
          predicates:
            - Host=**.gulimall.com,gulimall.com # 注意这里是以主机配置的断言路由规则

此时通过 http://gulimall.com/api/product/brand/list 直接访问接口也是可以的

posted @ 2023-11-23 23:38  起跑线小言  阅读(52)  评论(0编辑  收藏  举报