1环境和项目结构搭建
# 【1 环境和项目搭建】
一、安装虚拟机(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镜像
只需要两步:
- 打开cmd窗口,输入vagrant init centos/7
- 输入vagrant up(此处是个下载linux镜像的过程,很慢)
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命令行窗口界面会出现以下:
这个时候需要再次输入vagrant up即可再次启动虚拟机,启动完成之后会出现:
因为这个时候你看到在VirtualBox上已经启动了一个linux虚拟机,这个时候在命令行窗口按Ctrl+C就会停止,然后就用vagrant ssh连接虚拟机就可以了。然后如下图即为已经连接到了虚拟机,且可以输入Linux的命令使用了
二、环境-虚拟机网络设置(B站P7集)
这就是配置端口转发(即:访问本机端口3333的时候就会映射到Linux的3306的 端口,就等于访问Linux上的3306端口,但是这样太麻烦,每次在linux上安装一个软件就会设置一次,所以我们现在就希望设置虚拟机Linux的ip为固定IP,然后本机ping我们的Linux的IP就能ping通)
由于刚开始创建的虚拟机默认使用的是上图所示的:网络地址转换(NAT)和端口转发的方式,不方便我们后期开发,所有需要重新设置(PS:后期如果不理解或者忘记,具体详情可以再观看B站视频,原理讲解非强清晰)
1、修改虚拟机网卡/网址
方法有两个:
一、连接上虚拟机,然后修改虚拟机的网卡设置
二、(推荐方法)如下图:修改vagrantfile(在C:\Users\13***文件夹下)
因为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得通我们的虚拟机,如下图:
2、修改配置允许ssh工具登录
默认只允许ssh登录方式,为了后来操作方便,文件上传等,我们可以配置允许账号密码登录
具体步骤如下:
三、在Linux下安装docker
1、进入docker官网引导文档 https://docs.docker.com/engine/install/centos/
复制上图内容到cmd命令行窗口(意思是先卸载之前安装的这些东西)
sudo yum remove docker \docker-client \docker-client-latest \docker-common \docker-latest \docker-latest-logrotate \docker-logrotate \docker-engine
由于之前我们没有安装过docker所以没有匹配到需要卸载的东西
1.2 设置docker仓库
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
1.3 安装docker引擎
sudo yum install docker-ce docker-ce-cli containerd.io
中间有需要选择y/n的,输入y即可
y1.3.0但是这里安装过程中报错: (有时候按Ctrl+C 停止后重新执行可能会OK)
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配置下载镜像的加速地址,这样就不用从国外下载镜像了
我们使用淘宝的镜像加速
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
1.7 docker安装MySQL
输入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
挂载就是将容器内部的文件夹和文件的快捷方式放到Linux里面,这样以后就就不用以docker exec -it 23d80 /bin/bash
这种命令进入mysql容器内部进行查看这些日志、log配置文件等文件了(然后还得使用exit
命令来退出容器等)
docker容器文件挂载与端口映射
创建MySQL配置文件:
[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
PS: cd命令进入文件的时候会提示没有,直接使用vi命令创建即可
1.8 docker安装redis==》(B站P11)
由于官方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
按Ctrl+c 之后按‘:wq ’保存文件 然后用命令:docker restart redis重启redis
四、开发环境统一
1、maven配置jdk1.8编译项目
maven使用阿里云镜像下载加速
这些配置好之后就开始用idea整合maven
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
五、项目创建
1、在gitee上创建项目代码仓库
初始化仓库:
1、语言选择;2、git提交时忽略提交的文件(选择maven就行)3、开源许可证:不选/也可选一个
2、选择分支模型:图示即可(生产/开发模型==》支持两种分支master和dev)
2、克隆项目
复制仓库地址==》然后打开idea:然后-> File -> new project -> project from Version Control -> Git 输入刚才复制的仓库地址,设置项目存的位置
3、创建项目微服务
右击gulimall项目名--New Module--选择Spring Initializr--输入如下信息
然后点击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==》聚合服务
5)、配置git版本控制忽略的文件
②安装gitee插件。
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)
使用半成品人人开源后台管理系统进行改造
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>
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
4、启动renren-fast项目
在vscode上打卡项目并下载好依赖,然后使用 npm run dev 命令启动项目
六、搭建配套前端环境
1、前端内容笔记
前端内容未整理,可以看别的:
1、(134条消息) 【谷粒商城】vue简要笔记_hancoder的博客-CSDN博客
2、其他前端软件和环境
1)、VSCode的安装和使用(B站第12集--最后几分钟)
解决报错:
-
报错: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.
-
- 解决办法:参考网站:(多试几次)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文件,如下
-
- 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
-
- 在启动类上使用@MapperScan(作用:告诉mybatisPlus我们的mapper文件都是在哪里?)
- @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文件中配置全局的主键策略: 如上
测试:
- 需要在@SpringBootTest注解上加@RunWith(SpringRunner.class)
- 报错:
解决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和报错
- 用IDE用IDEA创建springboot项目时main方法无法运行A创建springboot项目时main方法无法运行,注解字体颜色和普通一样 无法按住Crtl点进去,且在在如下图示中的模块名称为灰色,
- 创建好此工程之后,启动会报错:
解决办法:
原因:这是因为:
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探路,收到响应允许跨域后再发送真实请求
什么意思呢?跨域是要请求的、新的端口那个服务器限制的,不是浏览器限制的。
跨域的解决方案
- 方法1:设置nginx包含admin和gateway。都先请求nginx,这样端口就统一了
- 方法2:让服务器告诉预检请求能跨域
解决方案1:
我们在开发期间采用第二种方案:如下(在网关中配置)
解决方案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里面指定。
- CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:
-
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: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集)
登录进入后台之后》》点击商品系统》》商品分类,会有如下报错:
五、使用最新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编码
修改前
【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>
- 参考官方文档spring.io网址
- 参考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文件中写:
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);
}
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、原理
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 将会对请求和响应进行修改处理
工作原理:
客户端发送请求给网关,弯管 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)
例:主机路由:
# 配置nginx到网关后再转到商品服务的配置(P140 6:30处)
- id: gulimall_host_route
uri: lb://gulimall-product
predicates:
- Host=**.gulimall.com,gulimall.com # 注意这里是以主机配置的断言路由规则
例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
2、GlobalFilter
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、然后在浏览器中重新访问即可看到
查看nginx报错日志:
docker logs nginx
没有的话设置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
配置如下:
# 在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,在以后的项目中经常使用它的反向代理,和负载均衡
正向与方向相对于自己这台电脑来说,帮我们去上网的就是正向代理,帮助对方服务器了就是反向代理。
正向代理:我们想要访问谷歌,搭建一台代理服务器,为电脑配置上代理服务器的地址,电脑想访问任何网址,都由代理服务器帮我们去访问,访问拿到内容后帮我们返回,所以看到的是搭建的这台服务器是帮我们进行上网。
反向代理:搭建集群环境的时候非常需要,比如任何人去访问谷粒商城,谷粒商城有我们的后台服务集群,这些服务集群,每一个服务器,都可能都要在内网部署,这是一个内网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地址,
es和kibana都可以访问成功
以后每个系统都有对应的域名,都是访问虚拟机的ip地址,
直接访问gulimall.com也可看到nginx正常启动(能访问的欢迎页html)
现在已经根据域名访问到nginx,接下来还要访问到项目,可以让nginx把所有的请求转给我们的网关,由网关再代转给每一个项目。当然也可以让nginx直接转给指定的项目,比如一看是访问的是gulimall.com,想要展示首页,相当于gulimall.com来到的所有请求,都给我转发到localhost:10000端口,也就是商品项目,拥有页面首页的内容,但是这样做不好,未来product项目部署多台的时候,有可能端口不一样,ip地址也不一样,每次都要修改nginx,让gulimall.com来的请求都转到10000端口。
我们先来这个最快的配置但是有局限性的配置-将gulimall请求直接转到10000端口
解决nginx丢Host报错
现在我们在window本机宿主机的hosts文件中更改域名解析配置:如下:
127.0.0.1 gulimall.com
然后我们在浏览器中输入gulimall.com 后敲回车想由网关转到商品服务访问的时候发现还是报错,不能访问:
这是因为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 直接访问接口也是可以的