安装docker

  • 安装一台虚拟机(这里就不过多说了)

  • 修改linuxIP相关配置

要求:将ip地址配置成静态的。这里把IP地址配置成192.168.200.11

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#打开网络相关配置文件
vim /etc/sysconfig/network-scripts/ifcfg-ens33

#修改该配置文件
#IP的配置方法[none|static|bootp|dhcp](引导时不适用协议|静态分配IP|BOOTP协议|DHCP协议)
BOOTPROTO="static"
#IP地址
IPADDR=192.168.200.11
#网关
GATEWAY=192.168.200.2
#域名解析器
DNS1=192.168.200.2

#重启网络服务让配置生效(重启网络或者重启机器都可以)
#重启网络
service network restart
#重启系统
shutdown -r now
#或者
reboot

网络配置文件说明
TYPE=”Ethernet”                # 网络类型(通常是Ethernet)
UUID=”48888f85-4f38-4400-adf1-aab4bf2420cb” #随机id
DEVICE=”ens33”        # 接口名(设备,网卡)
ONBOOT=”yes”        # 系统启动的时候网络接口是否有效(yes/no)

  • 卸载旧版本

较旧的 Docker 版本称为 docker 或 docker-engine 。如果已安装这些程序,请卸载它们以及相关的依赖项。

1
2
3
4
5
6
7
8
$ sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
  • 设置仓库

安装所需的软件包。yum-utils 提供了 yum-config-manager ,并且 device mapper 存储驱动程序需要 device-mapper-persistent-data 和 lvm2。

1
2
3
$ sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
  • 设置源地址,可以使用官方的,也可以使用阿里的镜像源【推荐】

使用官方源地址(比较慢)

1
2
3
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

阿里云【推荐】

1
2
3
$ sudo yum-config-manager \
--add-repo \
http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  • 安装 Docker Engine-Community
1
$ sudo yum install docker-ce docker-ce-cli containerd.io
  • 启动 Docker
1
$ sudo systemctl start docker
  • 验证docker是否安装成功
1
$ sudo docker --version


安装成功

  • 卸载docker
1
2
3
4
#删除安装包
yum remove docker-ce
#删除镜像、容器、配置文件等内容
rm -rf /var/lib/docker
  • 配置镜像加速器

配置阿里云的镜像加速器提高下载速度
分步执行(我使用#分割开了)

1
2
3
4
5
6
7
8
9
10
11
12
#
sudo mkdir -p /etc/docker
#
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://mlyx1bcv.mirror.aliyuncs.com"]
}
EOF
#
sudo systemctl daemon-reload
#
sudo systemctl restart docker
  • 设置开机自启
1
sudo systemctl enable docker

docker容器安装

登录https://hub.docker.com/ 直接搜索要下载的软件

mysql5.7

1
sudo docker pull mysql:5.7
  • 查看下载的容器
1
sudo docker images


可以看到我们已经下载好的mysql

  • 创建实例并启动
1
2
3
4
5
6
7
8
# --name指定容器名字 -v目录挂载 -p指定端口映射  -e设置mysql参数 -d后台运行
# 端口映射 linux端口:容器端口
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
  • 查看doker运行中的容器
1
docker ps


这时,我们就可以ip:3306连接我们的mysql了

  • 进入mysql容器(可以理解就是一个完整的linux)
1
docker exec -it mysql bin/bash
  • mysql容器中查看mysql装在了哪
1
whereis mysql
  • 退出容器
1
exit;
  • 修改mysql的配置文件,编码改为utf8

因为有目录映射,所以我们可以直接在镜像外执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
vim /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

redis

1
docker pull redis

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

  • 启动redis
1
2
3
4
5
6
7
8
9
# 在虚拟机中
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
  • 连接redis客户端
1
2
# 直接进去redis客户端。
docker exec -it redis redis-cli

这样默认是没有持久化的。我们需要在配置容器中appendonly yes,就可以aof持久化了。修改完记得重启服务

  • 开启redis的aof持久化
1
2
3
4
5
6
7
vim /mydata/redis/conf/redis.conf
# 插入内容
appendonly yes
#保存

# 重启服务
docker restart redis

注意:最新版的redis默认是aof持久化的,即使不执行上述修改,也是默认aof持久化的

开发环境

开发工具

  • 前端:VSCode
    • 插件:
      • Auto Close Tag
      • Auto Rename Tag
      • Chinese
      • ESlint
      • HTML CSS Support
      • HTML Snippets
      • JavaScript ES6
      • Live Server
      • open in brower
      • Vetur
  • 后端:Idea
    • 插件:
      • lombok
      • mybatisX
    • maven:配置阿里云镜像
1
2
3
4
5
6
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>

环境版本

  • Java:1.8

  • Maven:我用的3.5.2

代码版本控制

Git

  • 下载git:一路next就行
  • 右键 –> Git Bash
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 配置用户名
git config --global user.name "caicai" //(名字,随意写)

# 配置邮箱
git config --global user.email "1732804469@qq.com" // 注册账号时使用的邮箱

# 配置ssh免密登录
ssh-keygen -t rsa -C "1732804469@qq.com"
三次回车后生成了密钥:公钥私钥
cat ~/.ssh/id_rsa.pub

也可以查看密钥

浏览器登录码云后,个人头像上点设置--ssh公钥---随便填个标题---复制
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC83LbqGf+eA0YAMfbLPxQRsxaroaV6rWBGWsdcNxXBdTEV3eS6JaYdjRLdht38zIjXq8+jfuMA9Wgiy90eIWi9IEz0abEyHntlldzlW7L9szRGJbPgGfgVU5y0pCZYJ/5+fRU90ZVFrCNPmubK8tBHo45CPaEEDLhETBWUA6wG5Lp1knpf33kYpI95P0FIV6a2c2rnLcFTY3Q3LkXhNSxa3dU9Fj0zaPGPABUV44HTFtlCCeEaREgh0UYizxCGW+ixSN+UXZmpqlutRrzDm1kSIrUcpeh+k8vWpAvF/JcbPATC8gguhhZhOVYRLamzJqVsmGklkskZPmQLDNvB/hIfzD4eu5dQN+F2KQt6hWzfZ1L6hiX/oKOWMpkYjnZJSHEFFYBFslDTKWvCdVmX5RDpr680fqbj3v1P8FF/l2H6ZoBtBFU4N2//az/9+kZNzoqEzbaHfkMkZWTzycdz1ME2MEhnB3QdDan1rHYWYLQaY4AL3pHlEPExpt2K9RprDGE= 1732804469@qq.com

# 测试
ssh -T git@gitee.com
测试成功,就可以无密给码云推送仓库了

项目搭建

经上述的操作,我们已经把ssh配置好了,接下来,我们创建仓库。

  • 在码云新建仓库,仓库名gulimall,选择语言java,在.gitignore选中maven(就会忽略掉maven一些个人无需上传的配置文件),许可证选Apache-2.0,开发模型选生成/开发模型,开发时在dev分支,发布时在master分支,创建。

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

  • IDEA然后New Module –> Spring Initializer –> wang.cai2.gulimall , Artifact填 gulimall-product。Next—选择web(web开发),springcloud routing里选中openFeign(rpc调用)。

  • 依次创建出以下服务

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

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

配置好之后,点击右下角的显示的springboot的service选项

  • 随便从一个项目复制一个pom文件粘贴到gulimall总项目目录,修改成下方这样
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?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>wang.cai2.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>
</modules>
</project>

  • 点击项目右侧的maven,然后点击加号,将该pom文件添加的项目中

添加进来之后,就会发现多了一个root。这样比如运行root的clean命令,其他项目也一起clean了。

  • 在总项目的.gitignore文件中添加如下配置,把我们项目中不需要提交的文件忽略掉。
1
2
3
4
5
6
**/mvnw
**/mvnw.cmd
**/.mvn
**/target/
.idea
**/.gitignore

在idea左侧的commit一栏中,点击刷新按钮,观察Unversioned Files中文件数量的变化。全选最后剩下21个文件,选择右键、Add to VCS(添加到版本控制)。

  • 将初版项目提交到gitee。
    • 在idea的插件中心下载gitee,重启idea
    • 项目commit,push(也可以点击图中commit右边的 commit and push


数据库配置

启动docker的mysql

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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
# /bin/bash就是进入一般的命令行,如果改成redis就是进入了redis

建立数据库

  • 连接docker的mysql

建立对应的数据库:

  • gulimall_oms
  • gulimall_pms
  • gulimall_sms
  • gulimall_ums
  • gulimall_wms

数据库名如上,注意:**字符集编码选用utf8mb4**,他能兼容utf8且能解决一些乱码的问题

导入对应的sql语句

人人项目搭建

clone项目

  • 在码云上搜索人人开源
  • renren-fast(后端项目) 和 renren-fast-vue(前端项目)clone下来

  • 贴心的博主把clone命令贴下面了:

    • renren-fastgit clone git@gitee.com:renrenio/renren-fast.git
    • renren-fast-vuegit clone git@gitee.com:renrenio/renren-fast-vue.git
  • 将clone下来的项目的.git文件删除

注意:.git文件是隐藏文件

后端搭建

集成到谷粒商城

  • renren-fast移动到我们的gulimall所在的目录

  • 在idea中将renren-fast设置成maven项目

  • renren-fast模块添加到我们的gulimallpom

  • 刷新maven,让idea导入renren-fast需要的文件

博主觉得,配置环境要比写代码难。各种环境,真的让人头大。

刷新maven后,如果renren-fastpom文件没有出现任何问题,那么恭喜你,你可以跳过下面这一段的错误排查了。

博主在pom文件导入资源的过程中,插件爆红,project标签也是红的

图上的解释也说了

renren-fast的parent里写的并不是renren-fast的上一级,而是继承了springboot:

1
2
3
4
5
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
</parent>

加上

1
<relativePath />

修改为:

1
2
3
4
5
6
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.4.RELEASE</version>
<relativePath />
</parent>

再次刷新maven即可。

小细节:如果spring-boot-maven-plugin,我们可以给他加一个版本,让其能正确的导入进来。导入成功后,我们再把版本去掉也不会报错了(去不去都可以)

1
2
3
4
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- 加上版本 -->
<version>2.2.13.RELEASE</version>

添加renren-fast的数据库

打开renren-fast/db/mysql.sql,将sql语句复制

连接我们的mysql,创建名为gulimall_admin的数据库,字符集选择utf8mb4

执行完成后,我们就得到了renren-fast所需的表

修改配置文件

修改该项目的application-dev.yml数据源配置为我们刚刚配置的数据库

application.yml我们可以看到,项目的端口为8080,路径为/renren-fast

启动项目,访问相应的url:localhost:8080/renren-fast

有数据返回即为项目搭建成功。

喝杯java歇息一下吧,接下来是前端项目搭建。

前端搭建

准备工作

下载LTS版本(稳定版)

  • 安装node,一路next就行

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

打开命令行:

1
2
3
4
#查看node版本
node -v
#配置npm的镜像仓库地址--》淘宝
npm config set registry http://registry.npm.taobao.org/
  • 下载并安装python,并配置全局变量。(一路next就行,就不贴图了)

项目的相关设置

  • 使用vscode打开renren-fast-vue

  • 下载node-sass,版本需要和我们下载的node的版本对应

对应关系如下:

NodeJS Supported node-sass version Node Module
Node 16 6.0+ 93
Node 15 5.0+ 88
Node 14 4.14+ 83
Node 13 4.13+, <5.0 79
Node 12 4.12+ 72
Node 11 4.10+, <5.0 67
Node 10 4.9+, <6.0 64
Node 8 4.5.3+, <5.0 57
Node <8 <5.0 <57

这是在官网看的,你也可以访问官网查询:https://github.com/sass/node-sass

我使用的是node14,所以将node-sass版本设置为4.14

在项目终端下执行:

1
2
3
4
5
6
7
8
9
10
11
12
13
# 指定node-sass版本,这句等价于修改package.json文件了。
# 安装node-sass,一定要和node的版本对应
npm install node-sass@4.14
# 安装chromedriver(按理来说不用装这个的,我没装这个,在执行npm install 的时候报错了,所以就写上了)
npm install chromedriver --chromedriver_cdnurl=http://cdn.npm.taobao.org/dist/chromedriver
#安装其他依赖:
npm install

#如果觉得上面的步骤太麻烦,还可以使用下面这个命令:并且它自动更新package的包版本(最新的和你node兼容)
npm install --save node-sass

# 启动项目:
npm run dev

然后直接就可以执行起来了。如果没验证码什么的,是因为java项目没有启动

  • 卸载残留问题

如果之前执行npm install失败了,执行上面代码时要先清依赖残留,否则安装不上

1
2
npm rebuild node-sass
npm uninstall node-sass

上面步骤等价于直接删除node_modules,只不过node_modules是删了全部下载的依赖包

启动没有问题后,浏览器输入localhost:8081就可以看到前端页面了

初始的账号和密码都是admin

逆向工程生成CRUD

搭建product工程

逆向工程搭建

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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>


<!-- 进入renren-generator的pom文件,在parent标签中添加<relativePath/>标签 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.6.RELEASE</version>
<relativePath/>
</parent>

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

修改application.yml

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

然后修改generator.properties

1
2
3
4
5
6
7
8
9
10
11
12
#代码生成器,配置信息
#主目录
mainPath=wang.cai2
#包名
package=wang.cai2.gulimall
moduleName=product
#作者
author=caicai
#Email
email=cryc8924@gmail.com
#表前缀(类名不会包含表前缀)
tablePrefix=pms_

运行RenrenApplication。访问http://localhost:80

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

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

我们需要一个common模块用来放置我们公共的代码文件

在项目上右击new modules—> maven,然后在name上输入gulimall-common

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

在common项目的pom.xml中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!-- mybatisPLUS-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--简化实体类,用@Data代替getset方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
<!-- httpcomponent包。发送http请求 -->
<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>

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

tips: shift+F6修改项目名

此外,说下maven依赖的问题。

  • <dependency>代表本项目依赖,子项目也依赖
  • 如果有个<optional>标签,代表本项目依赖,但是子项目不依赖

然后在product项目中的pom.xml中加入下面内容,作为common的子项目

1
2
3
4
5
<dependency>
<groupId>wang.cai2.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

复制renren-fastcommon.utils包下的QueryPageUtilsRConstant到到common项目的java/wang.cai2.common.utils下;将renren-fastcommon.exception包下的RRException也复制到我们common项目下的java/wang.cai2.common.utils中;将renren-fastcommon.xss目录复制到我们common项目下的java/wang.cai2.common包下面,并把xss包下面的XssFilterXssHttpServletRequestWrapper删除。最后,common项目的结构目录如下图

进入renren-generator,注释src/main/resources/template/Controller.java.vm中所有的@RequiresPermissions删除该注解的引用import org.apache.shiro.authz.annotation.RequiresPermissions;,他是shiro的东西

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

在common的pom.xml中导入

1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- 数据库驱动 https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<!--tomcat里一般都带-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>

这里附上common项目pom.xml的完整配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>gulimall</artifactId>
<groupId>wang.cai2.gulimall</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>gulimall-common</artifactId>
<description>每一个微服务公共的依赖</description>

<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>

<dependencies>
<!-- mybatisPLUS-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<!--简化实体类,用@Data代替getset方法-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.20</version>
</dependency>
<!-- httpcomponent包。发送http请求 -->
<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>
<!-- 数据库驱动 https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.17</version>
</dependency>
<!--tomcat里一般都带-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>

</project>

逆向工程使用的是mybatisplus,这里贴上mybatis-plus的地址,不熟悉的小伙伴可以看一下快速开始

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

1
2
3
4
5
6
7
8
9
10
11
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.200.11:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&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

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

classpath*的使用:当项目中有多个classpath路径,并同时加载多个classpath路径下(此种情况多数不会遇到)的文件,*就发挥了作用,如果不加*,则表示仅仅加载第一个classpath路径。

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

1
2
3
4
5
6
7
8
9
@MapperScan("wang.cai2.gulimall.product.dao")
@SpringBootApplication
public class GulimallProductApplication {

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

}

测试一下:

给数据库添加内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootTest
class GulimallProductApplicationTests {

@Autowired
BrandService brandService;
@Test
void contextLoads() {
BrandEntity brandEntity = new BrandEntity();
brandEntity.setName("华为");
brandService.save(brandEntity);
System.out.println("保存成功....");
}

}

查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@SpringBootTest
class GulimallProductApplicationTests {

@Autowired
BrandService brandService;
@Test
void contextLoads() {
for (BrandEntity brandEntity : brandService.list(new QueryWrapper<BrandEntity>().eq("brand_id", 1))) {
System.out.println(brandEntity);
}

}

}

测试成功

搭建其他项目

coupon

优惠券服务。

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

1
2
3
4
5
<dependency>
<groupId>wang.cai2.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

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

1
2
3
4
5
6
7
8
9
10
11
12
#代码生成器,配置信息
#主目录
mainPath=wang.cai2
#包名
package=wang.cai2.gulimall
moduleName=coupon
#作者
author=caicai
#Email
email=1732804469@qq.com
#表前缀(类名不会包含表前缀)
tablePrefix=sms_

application.yml设置好要连接的数据源,启动逆向工程生成代码。将main粘贴到coupon中。

productapplication.yml复制一份,粘贴到我们的coupon项目中,将数据源修改成coupon对应的库:gulimall_sms

1
2
3
4
5
6
7
8
9
10
11
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.200.11:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&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

启动项目,访问http://localhost:8080/coupon/smscoupon/list测试一下

成功

member

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

1
2
3
4
5
<dependency>
<groupId>wang.cai2.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

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

1
2
3
4
5
6
7
8
9
10
11
12
#代码生成器,配置信息
#主目录
mainPath=wang.cai2
#包名
package=wang.cai2.gulimall
moduleName=member
#作者
author=caicai
#Email
email=1732804469@qq.com
#表前缀(类名不会包含表前缀)
tablePrefix=ums_

application.yml设置好要连接的数据源,启动逆向工程生成代码。将main粘贴到member中。

productapplication.yml复制一份,粘贴到我们的member项目中,将数据源修改成member对应的库:gulimall_ums

1
2
3
4
5
6
7
8
9
10
11
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.200.11:3306/gulimall_ums?useUnicode=true&characterEncoding=UTF-8&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

启动项目,访问http://localhost:8080/member/growthchangehistory/list测试一下

order

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

1
2
3
4
5
<dependency>
<groupId>wang.cai2.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

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

1
2
3
4
5
6
7
8
9
10
11
12
#代码生成器,配置信息
#主目录
mainPath=wang.cai2
#包名
package=wang.cai2.gulimall
moduleName=order
#作者
author=caicai
#Email
email=1732804469@qq.com
#表前缀(类名不会包含表前缀)
tablePrefix=oms_

application.yml设置好要连接的数据源,启动逆向工程生成代码。将main粘贴到order中。

productapplication.yml复制一份,粘贴到我们的order项目中,将数据源修改成order对应的库:gulimall_oms

1
2
3
4
5
6
7
8
9
10
11
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.200.11:3306/gulimall_oms?useUnicode=true&characterEncoding=UTF-8&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

启动项目,访问http://localhost:8080/order/order/list测试一下

ware

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

1
2
3
4
5
<dependency>
<groupId>wang.cai2.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

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

1
2
3
4
5
6
7
8
9
10
11
12
#代码生成器,配置信息
#主目录
mainPath=wang.cai2
#包名
package=wang.cai2.gulimall
moduleName=ware
#作者
author=caicai
#Email
email=1732804469@qq.com
#表前缀(类名不会包含表前缀)
tablePrefix=wms_

application.yml设置好要连接的数据源,启动逆向工程生成代码。将main粘贴到ware中。

productapplication.yml复制一份,粘贴到我们的ware项目中,将数据源修改成ware对应的库:gulimall_wms

1
2
3
4
5
6
7
8
9
10
11
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.200.11:3306/gulimall_wms?useUnicode=true&characterEncoding=UTF-8&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

启动项目,访问http://localhost:8080/ware/wareinfo/list测试一下

配置端口号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# coupon
server:
port: 7001

# member
server:
port: 8001

# order
server:
port: 9001

# product
server:
port: 10001

# ware
server:
port: 11001

当我们配置完所有信息后,我们的项目都能够完美运行,但是很不幸,我的renren-fast运行报错了,原因是lombok罢工了,get/set方法不能生成了,修改下列包下面的类,手动给其中的类加上get/set方法即可运行。

1
2
3
4
5
6
io/renren/modules/app/form
io/renren/modules/job/entity
io/renren/modules/sys/entity
io/renren/modules/oss/cloud
io/renren/modules/oss/entity
io/renren/modules/sys/form

set MODE=”cluster”

修改为单机

member 报错 在common中加如 spring-cloud-loadbalancer 依赖即可

SpringCloud-Alibaba

阿里18年开发的微服务一站式解决方案。https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

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

在common的pom.xml中加入

1
2
3
4
5
6
7
8
9
10
11
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

上面是依赖管理,相当于以后再dependencies里引spring cloud alibaba就不用写版本号, 全用dependencyManagement进行管理。注意他和普通依赖的区别,他只是备注一下,并没有加入依赖

Nacos-8848

一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。

nacos作为我们的注册中心和配置中心。

注册中心文档:https://github.com/alibaba/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example

其他文档在该项目上层即可找到,下面读一读官网给的介绍就会用了。

安装启动nacos:下载–解压–双击bin/startup.cmd。http://127.0.0.1:8848/nacos/ 账号密码nacos

我下载的nacos是2.0.3的版本,在启动的时候报错了:org.springframework.context.ApplicationContextException: Unable to start web server; nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat

这是因为nacos是默认的集群模式所以我们在startup.cmd里面第26行改成单机模式就好了

修改为图中所示的即可成功启动

使用nacos:

  • 在某个项目里properties里写spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848(yaml同理,指定nacos的地址)。再指定applicatin.name告诉注册到nacos中以什么命名

  • 依赖:放到common里,不写版本是因为里面有了版本管理

1
2
3
4
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  • 最后application.yml内容,配置了服务中心名和当前模块名字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server:
port: 8001

spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.200.11:3306/gulimall_ums?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848
application:
name: gulimall-member
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto

然后依次给其他项目、配置上面的yaml,改下name就行。

测试:

启动项目,登录nacos:127.0.0.1:8848/nacos,可以看到我们的服务上线了。

Feign(远程调用)与注册中心

声明式远程调用

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

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

pom.xml

1
2
3
4
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>

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

在coupon中修改如下的内容

1
2
3
4
5
6
7
8
9
10
11
@RequestMapping("coupon/smscoupon")
public class SmsCouponController {
@Autowired
private SmsCouponService smsCouponService;

@RequestMapping("/coupon")
public R coupon(){
SmsCouponEntity smsCouponEntity = new SmsCouponEntity();
smsCouponEntity.setCouponName("满100减0.1元");
return R.ok().put("coupon",smsCouponEntity);
}

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/*
* 想要远程调用的步骤:
* 1 引入openfeign
* 2 编写一个接口,接口告诉springcloud这个接口需要调用远程服务
* 2.1 在接口里声明@FeignClient("gulimall-coupon")他是一个远程调用客户端且要调用coupon服务
* 2.2 要调用coupon服务的/coupon/coupon/member/list方法
* 3 开启远程调用功能 @EnableFeignClients,要指定远程调用功能放的基础包
* */
@EnableFeignClients(basePackages="wang.cai2.gulimall.member.feign")//扫描接口方法注解
@EnableDiscoveryClient
@SpringBootApplication
public class gulimallMemberApplication {

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

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

1
2
3
4
5
6
@FeignClient("gulimall-coupon") //告诉spring cloud这个接口是一个远程客户端,要调用coupon服务(nacos中找到),具体是调用coupon服务的/coupon/smscoupon/coupon对应的方法
public interface CouponFeignService {
// 远程服务的url
@RequestMapping("/coupon/smscoupon/coupon")//注意写全优惠券类上还有映射//注意我们这个地方不是控制层,所以这个请求映射请求的不是我们服务器上的东西,而是nacos注册中心的
public R coupon();//得到一个R对象
}

@FeignClient+@RequestMapping构成远程调用的坐标

其他类中看似只是调用了CouponFeignService.coupon(),而实际上该方法跑去nacos里和rpc里调用了才拿到东西返回

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
@RequestMapping("member/member")
public class MemberController {
@Autowired
private MemberService memberService;
@Autowired
private CouponFeignService couponFeignService;

@RequestMapping("/compon")
public R getCompon(){
MemberEntity memberEntity = new MemberEntity();
memberEntity.setNickname("张三");
R coupon = couponFeignService.coupon();
return R.ok().put("member",memberEntity).put("coupon",coupon.get("coupon"));
}

重新启动服务

http://localhost:8001/member/member/coupon

然后就报错了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberController': Unsatisfied dependency expressed through field 'couponFeignService'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wang.cai2.gulimall.member.feign.CouponFeignService': Unexpected exception during bean creation; nested exception is java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:660) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1413) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:944) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:917) ~[spring-context-5.3.4.jar:5.3.4]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:582) ~[spring-context-5.3.4.jar:5.3.4]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:326) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311) [spring-boot-2.4.3.jar:2.4.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300) [spring-boot-2.4.3.jar:2.4.3]
at com.jane.shop.member.MemberApplication.main(MemberApplication.java:23) [classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'wang.cai2.gulimall.member.feign.CouponFeignService': Unexpected exception during bean creation; nested exception is java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:537) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:276) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1380) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657) ~[spring-beans-5.3.4.jar:5.3.4]
... 21 common frames omitted
Caused by: java.lang.IllegalStateException: No Feign Client for loadBalancing defined. Did you forget to include spring-cloud-starter-loadbalancer?
at org.springframework.cloud.openfeign.FeignClientFactoryBean.loadBalance(FeignClientFactoryBean.java:316) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:343) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:322) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
at org.springframework.cloud.openfeign.FeignClientsRegistrar.lambda$registerFeignClient$0(FeignClientsRegistrar.java:224) ~[spring-cloud-openfeign-core-3.0.1.jar:3.0.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1231) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1173) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:564) ~[spring-beans-5.3.4.jar:5.3.4]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.4.jar:5.3.4]
... 29 common frames omitted

添加spring-cloud-starter-loadbalancer,排除 Nacos 的 Ribbon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>

再次启动服务

http://localhost:8001/member/member/coupon

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
{
"msg":"success",
"code":0,
"coupon":{
"id":null,
"couponType":null,
"couponImg":null,
"couponName":"满100减0.1元",
"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
}
}

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中添加依赖 nacos配置中心

1
2
3
4
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

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

1
2
3
# nacos作为配置中心
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

还是原来我们使用配置的方式,只不过优先级变了,所以匹配到了nacos的配置

还是配合@Value注解使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RefreshScope //这个注解的作用是每次的@value都从配置文件中读取,这样才能做到动态获取配置
@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,配置

1
2
3
# gulimall-coupon.properties
coupon.user.name=配置中心
coupon.user.age=12

然后点击发布。重启coupon

这里可能会报错,博主就报错了,报错信息如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.smsCouponController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'coupon.user.name' in value "${coupon.user.name}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:405) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1413) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:601) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:524) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$1(AbstractBeanFactory.java:374) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.cloud.context.scope.GenericScope$BeanLifecycleWrapper.getBean(GenericScope.java:376) ~[spring-cloud-context-3.0.3.jar:3.0.3]
at org.springframework.cloud.context.scope.GenericScope.get(GenericScope.java:179) ~[spring-cloud-context-3.0.3.jar:3.0.3]
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:371) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1154) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.cloud.context.scope.refresh.RefreshScope.eagerlyInitialize(RefreshScope.java:125) ~[spring-cloud-context-3.0.3.jar:3.0.3]
at org.springframework.cloud.context.scope.refresh.RefreshScope.start(RefreshScope.java:117) ~[spring-cloud-context-3.0.3.jar:3.0.3]
at org.springframework.cloud.context.scope.refresh.RefreshScope.onApplicationEvent(RefreshScope.java:112) ~[spring-cloud-context-3.0.3.jar:3.0.3]
at org.springframework.cloud.context.scope.refresh.RefreshScope.onApplicationEvent(RefreshScope.java:67) ~[spring-cloud-context-3.0.3.jar:3.0.3]
at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:938) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:145) ~[spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) [spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:434) [spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:338) [spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1343) [spring-boot-2.5.3.jar:2.5.3]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1332) [spring-boot-2.5.3.jar:2.5.3]
at wang.cai2.gulimall.coupon.GulimallCouponApplication.main(GulimallCouponApplication.java:12) [classes/:na]
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'coupon.user.name' in value "${coupon.user.name}"
at org.springframework.util.PropertyPlaceholderHelper.parseStringValue(PropertyPlaceholderHelper.java:180) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.util.PropertyPlaceholderHelper.replacePlaceholders(PropertyPlaceholderHelper.java:126) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.core.env.AbstractPropertyResolver.doResolvePlaceholders(AbstractPropertyResolver.java:239) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.core.env.AbstractPropertyResolver.resolveRequiredPlaceholders(AbstractPropertyResolver.java:210) ~[spring-core-5.3.9.jar:5.3.9]
at org.springframework.context.support.PropertySourcesPlaceholderConfigurer.lambda$processProperties$0(PropertySourcesPlaceholderConfigurer.java:175) ~[spring-context-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.AbstractBeanFactory.resolveEmbeddedValue(AbstractBeanFactory.java:936) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1321) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.resolveFieldValue(AutowiredAnnotationBeanPostProcessor.java:657) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:640) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:119) ~[spring-beans-5.3.9.jar:5.3.9]
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessProperties(AutowiredAnnotationBeanPostProcessor.java:399) ~[spring-beans-5.3.9.jar:5.3.9]
... 27 common frames omitted

原因是高版本的springboot需要我们手动引入bootstrap的包才能读取bootstrap配置

在common的pom文件添加

1
2
3
4
5
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.0.3</version>
</dependency>

再次启动,访问:http://localhost:7001/coupon/smscoupon/test

但是修改怎么办?实际生产中不能重启应用。在coupon的控制层上加@RefreshScope,这个注解在前面的java代码的注释中说过,忘记添加的小伙伴添加之后重启让注解生效,在nacos浏览器里修改配置,修改就可以观察到能动态修改了。

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