商城项目-开发环境搭建

688 阅读20分钟

linux环境搭建

首先下载并安装VirtualBox,要开启CPU虚拟化。即virtualBox进行安装需要cpu开启虚拟化,在开机启动的时候设置主板,CPU configuration,然后点击Intel Vitualization Technology。重启电脑。

image.png

vagrant安装

普通安装linux虚拟机太麻烦,可以利用vagrant可以帮助我们快速地创建一个虚拟机。主要装了virtualboxvagrant可以帮助我们快速创建出一个虚拟机。他有一个镜像仓库。去www.vagrantup.com/ 下载vagrant安装,安装后重启电脑。cmd中输入vagrant有版本代表成功了。

image.png

打开window cmd窗口,输入vagrant init centos/7,即可初始化一个centos7系统(注意这个命令在哪个目录下执行的,他的Vagrantfile就生成在哪里),当然命令后面的centos/7vagrant仓库中名字

image.png

image.png

image.png

运行vagrant up即可启动虚拟机环境,系统root用户的密码是vagrant,启动后出现default folder:/cygdrive/c/User/… =>/vagrant。就表示启动成功,接着ctrl+c退出。

image.png vagrant ssh 自动使用vagrant用户会连上虚拟机。可以使用exit退出。

image.png

image.png

如果想要关闭虚拟机的话,直接点virtualbox退出->正常关机即可

image.png

下次想要启动虚拟机时,可以直接打开virtualbox,右键启动

image.png

当然也可以使用cmd命令行,输入vagrant up(需要保证当前所在目录下有Vagrantfile文件),然后使用vagrant ssh连接虚拟机

image.png

虚拟机网络设置

一开始的网络是网络地址转换+端口转发的方式。

image.png

image.png

当我们在virtualbox上安装redis之后,需要跟windows主机做端口映射,即当windows主机上访问6666端口时,就会映射访问到virtualbox中的6379端口,访问到redis,当我们windows主机上访问3333端口时,就会映射访问到virtualbox中的3306端口,这种方式都需要我们在virtualbox中进行设置端口映射,比较繁琐。

image.png 我们希望windows中访问固定的virtualbox中虚拟机的ip地址,直接访问6379就能访问到redis,直接访问3306就能访问到mysql!并且由于默认虚拟机的ip地址不是固定ip,开发不方便,需要修改Vagrantfile我们想要给虚拟机一个固定的ip地址,windows和虚拟机可以互相ping通。 可以更改Vagrantfile更改虚拟机ip,修改其中的config.vm.network "private_network",ip:"192.168.56.10" ,这个ip需要在windows的ipconfig中查到vitualbox的虚拟网卡ip,然后更改下最后一个数字就行(不能是1,1是我们的主机)。

image.png

image.png

image.png 接着需要重启一下vagrant,使用vagrant reload命令

image.png

虚拟机安装docker

docker可以启动一个容器,每一个容器相当于一个完整的Linux环境,在Docker中安装不同的软件,例如MySQLRedis,启动两个容器分别安装,两个软件实现相互隔离的效果。

image.png

安装docker参照官方文档: docs.docker.com/engine/inst…,安装docker之前首先卸载之前的版本。

#卸载系统之前的docker 
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

接着执行以下命令,下载一些配置

sudo yum install -y yum-utils

# 配置镜像
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
    
sudo yum install docker-ce docker-ce-cli containerd.io

#启动docker
sudo systemctl start docker

#查看docker是否安装成功
docker -v

#查看docker镜像仓库
sudo docker images

设置docker开机自启动,只要linux启动之后docker就会启动,不需要执行上面的sudo systemctl start docker命令了

# 设置开机自启动
sudo systemctl enable docker

docker配置镜像加速

配置docker阿里云镜像加速,因为如果每次下载镜像都去国外的网站下载比较慢

image.png

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

docker安装MySQL

下载mysql镜像

sudo docker pull mysql:5.7

image.png 创建实例容器并启动

# --name指定容器名字 -v目录挂载 -p指定端口映射  -e设置mysql参数 -d后台运行
sudo docker run -p 3306:3306 --name mysql \
-v /mydata/mysql/log:/var/log/mysql \
-v /mydata/mysql/data:/var/lib/mysql \
-v /mydata/mysql/conf:/etc/mysql \
-e MYSQL_ROOT_PASSWORD=root \
-d mysql:5.7

上面参数说明

  • -p 3306:3306 将容器的3306端口映射到主机即192.168.56.103306端口
  • -v /mydata/mysql/log:/var/log/mysql \: 将容器mysql日志文件夹/var/log/mysql挂载到主机即192.168.56.10/mydata/mysql/log文件夹中,以后访问192.168.56.10/mydata/mysql/log,就相当于访问容器mysql中的/var/log/mysql文件夹
  • -v /mydata/mysql/data:/var/lib/mysql \:将容器mysql数据文件夹/var/lib/mysql挂载到主机即192.168.56.10/mydata/mysql/data文件夹中,以后访问192.168.56.10/mydata/mysql/data,就相当于访问容器mysql中的/var/lib/mysql文件夹
  • -v /mydata/mysql/conf:/etc/mysql \:将容器mysql配置文件夹/etc/mysql挂载到主机即192.168.56.10/mydata/mysql/conf文件夹中,以后访问192.168.56.10/mydata/mysql/conf,就相当于访问容器mysql中的/etc/mysql文件夹
  • -e MYSQL_ROOT_PASSWORD=root \:表示设置mysql中的root用户的密码为root
  • -d mysql:5.7:表示以后台方式运行mysql:5.7镜像

执行上面的命令之前需要切换为root用户才有权限执行上面的命令,执行su root命令,接着输入密码vagrant

#切换为root用户
su root

接着执行上面的命令,然后查看docker正在运行中的容器

#查看docker正在运行中的容器
docker ps

因为每一个容器都是一个linux操作系统,所以可以进入到咱们刚刚启动的mysql容器中,执行以下命令,即可进入到对应的容器中。

#mysql为刚刚创建容器的名称 -it表示以交互发容方式,bin/bash表示运行bash
docker exec -it mysql bin/bash

image.png 接着修改mysql的字符集

#因为有目录映射,所以我们可以直接在镜像外执行
vi /mydata/mysql/conf/my.conf 

#修改字符集
[client]
default-character-set=utf8
[mysql]
default-character-set=utf8
[mysqld]
init_connect='SET collation_connection = utf8_unicode_ci'
init_connect='SET NAMES utf8'
character-set-server=utf8
collation-server=utf8_unicode_ci
skip-character-set-client-handshake
skip-name-resolve

#重新启动
docker restart mysql

docker安装Redis

下载redis镜像

docker pull redis

创建redis容器

# 在虚拟机中
mkdir -p /mydata/redis/conf
touch /mydata/redis/conf/redis.conf

docker pull redis

#运行redis容器
docker run -p 6379:6379 --name redis \
-v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf

# 直接进去redis客户端。
docker exec -it redis redis-cli

默认是不持久化的,即数据只是存储在内存中,当redis重启启动之后,原先的数据会丢失。所以在配置文件中输入appendonly yes,设置redis持久化。

vim /mydata/redis/conf/redis.conf
# 插入下面内容
appendonly yes
 

修改完重启redisdocker restart redis,然后以bash交互方式进去redis容器中,即docker -it redis redis-cli

#重启redis
docker restart redis

#设置redis容器在docker启动的时候启动
docker update redis --restart=always

image.png

接着我们可以用redis可视化工具redis desktop manager连接redis

image.png

image.png

开发工具&环境安装配置

一、maven3.6.1 配置maven使用阿里云镜像

<mirrors>
    <mirror>
      <id>nexus-aliyun</id>
      <mirrorOf>central</mirrorOf>
      <name>Nexus-aliyun</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </mirror>
</mirrors>

配置jdk1.8编译项目

<profile>
    <id>jdk-1.8</id>
    <activation>
           <activeByDefault>true</activeByDefault>
           <jdk>1.8</jdk>
    </activation><properties>
       <maven.compiler.source>1.8</maven.compiler.source>
       <maven.compiler.target>1.8</maven.compiler.target>
      <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
    </properties>
</profile>

接着打开idea配置maven

image.png

使用IDEA安装MyBatisX插件,该插件能够通过方法快速定位到MyBatis映射文件

image.png

使用VsCode安装如下插件

  • Auto Close Tag
  • Auto Rename Tag
  • Chinese
  • ESlint
  • HTML CSS Support
  • HTML Snippets
  • JavaScript ES6
  • Live Server
  • open in brower
  • Vetur

image.png

下载git并配置

首先下载git并安装,然后打开git bash,设置用户签名

# 配置用户名
git config --global user.name "username"  //(名字,随意写)

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

image.png

接着需要设置ssh免密登录gitee,我们先把本地的.ssh目录删了

image.png

# 配置ssh免密登录,进入git bash
ssh-keygen -t rsa -C 自己的邮箱

#三次回车后生成了密钥:公钥私钥
cat ~/.ssh/id_rsa.pub

image.png

然后查看发现当前目录重新生成了.ssh目录了

image.png

接着打开gitee中的settings

image.png

复制公钥文件id_rsa.pub的内容,打开

image.png

image.png

项目结构创建

首先点击创建仓库 image.png

仓库信息如下 image.png

从码云中把项目克隆下来

image.png

image.png

image.png

首先在这个项目创建module

image.png

image.png

首先选择spring-web还有openfeign image.png

image.png

image.png

依次创建出以下服务模块

  • 商品服务gulimall-product
  • 存储服务gulimall-ware
  • 订单服务gulimall-order
  • 优惠券服务gulimall-coupon
  • 用户服务gulimall-member

image.png

然后随意复制一个module中的pom.xml文件作为父项目gulimall_hspom文件 父项目的pom.xml内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.hs.gulimall</groupId>
    <artifactId>gulimall_hs</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>gulimall_hs</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 project管理中

image.png

image.png

image.png

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

**/mvnw
**/mvnw.cmd
**/.mvn
**/target/
.idea
**/.gitignore

image.png

然后将新增的文件加入git管理

image.png

接着使用IDEA安装gitee插件,然后把上面初始化项目修改提交到远程仓库中

image.png

image.png

初始化数据库

设置MySQL与Redis自启动

docker update redis --restart=always
docker update mysql --restart=always

搭建后台管理系统

使用人人开源的两个项目,如下图

image.png

使用git bash将这两个项目克隆下来

`

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

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

image.png

image.png

先把后台项目renren-fast中的.git文件删除掉

image.png

将后台项目renren-fast导入到gulimall_hs

image.png

修改父项目的pom.xml文件,将renren-fast加入到其中

image.png

然后复制renren-fast中的mysql.sql文件,里面是后台管理系统的数据库信息

image.png

创建一个新的数据库名gulimall-admin,然后执行一下上面的mysql.sql脚本

image.png

接着修改renren-fast项目中的application-dev.yml文件中国的数据库连接信息

image.png

安装node(官网下载,傻瓜式安装即可),node需要配合npm使用,因为nom为包管理工具(简单理解就是通过npm下载包依赖),然后配置npm的镜像仓库地址。直接cmd执行如下脚本

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

接着同样我们把项目renren-fast-vue中的.git文件删除掉,然后用VsCode打开 ,然后去VScode的项目终端中输入 npm install,是要去拉取依赖(package.json类似于pom.xmldependency

image.png

然后运行renren-fast项目

image.png

接着使用npm install运行renren-fast-vue项目

image.png

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

image.png

前端项目账号跟密码都是admin image.png

逆向工程搭建

我们可以通过renren-generator为我们的服务生成基本的增删改查代码

image.png

首先克隆人人开源中的renren-generator工程

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

image.png

image.png

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

image.png

<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>

image.png 在maven中刷新一下,让项目名变粗体,稍等下面进度条完成。在逆向工程renren-generator中的application.yml中的数据库信息,可以设置我要给哪个数据库里面的表生成基本的增删改查代码。

image.png

首先我们先给gulimall-pms数据库生成增删改查代码,所以修改application.yml

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

image.png

然后修改generator.properties(这里乱码的百度IDEA设置properties编码)

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

运行逆向工程 RenrenApplication 逆向工程,

image.png 访问localhost:80,如下图所示

image.png

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

image.png

接着进行解压

image.png

把复制main文件夹放到gulimall-product替换原有的main文件夹。

image.png 先删除掉resource下生成的src目录

image.png 我们查看生成的一个service实现类,发现还有些依赖没有

image.png

所以我们创建出一个公共的gulimall-common模块,以后需要的公共依赖或者公共的类都添加到该模块下,然后其他模块想要使用,就依赖该模块

image.png

image.png 添加pom文件依赖如下:

<!-- 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>

然后在product项目中的pom.xml中加入下面内容, 依赖common模块

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

此时我们发现service实现类中还缺少几个工具类,这些工具类都在renren-fast项目中,我们复制出来放到gulimall-commoncom.hs.common.utils包中(手动创建出包名)

image.png

image.png

image.png

此时还差一个Constant类和xss文件夹中的类,也是一样从renren-fast项目中复制到gulimall-common

image.png

image.png

此时我们发现gulimall-product模块中只有controller中的注解报错了,先注释掉注解

image.png

注释掉gulimall-product模块中controller类的//import org.apache.shiro.authz.annotation.RequiresPermissions;,他是shiro的东西。可以修改逆向工程中的生成controller类的模板,生成controller类的时候不生成上面的shiro注解,全部注释掉该类注解,如下图所示

image.png

重新运行逆向工程,重新生成controller,替换掉之前的controller目录,替换之后的controller不再报错了。

测试逆向工程

测试与整合商品服务里的mybatisplus,mp.baomidou.com/guide/quick…配置

commonpom.xml中导入

<!-- 数据库驱动 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>

删掉commonxss/xssfiler和XssHttpServletRequestWrapper,在gulimall-product项目的resources目录下新建application.yml

#配置数据源
spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.10:3306/guli_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.jdbc.Driver

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

然后在主启动类上加上注解@MapperScan()告诉mapper接口路径在哪儿

@MapperScan("com.atguigu.gulimall.product.dao")
@SpringBootApplication
public class gulimallProductApplication {
    public static void main(String[] args) {
        SpringApplication.run(gulimallProductApplication.class, args);
    }

}

然后去测试,先通过下面方法给数据库添加内容

@SpringBootTest
public class gulimallProductApplicationTests {
    @Autowired
    BrandService brandService;

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

同样的道理,依次生成其他微服务模块的增删改查代码

SpringCloud Alibaba

SpringCloud Alibaba致力于提供微服务开发的一站式解决方案,此项目包含开发分布式应用微服务的必需组件,方便开发者通过SpringCloud变成模型轻松使用这些组件开开发分布式应用服务。

依托SpringCloud Alibaba,您只需要添加一些注解和少量配置,就可以将SpringCloud应用接入阿里微服务解决方案,通过阿里中间件来迅速搭建分布式应用系统。

github.com/alibaba/spr…

image.png

  • 注册中心:nacos
  • 配置中心:nacos
  • 网关:gateway
  • 远程调用:netflixfeign闭源了,spring cloud开了个openFeign

因为我们所有的服务都是微服务项目,为了便于依赖管理,我们在gulimall-common模块中的pom.xml文件中加入如下内容:

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

Nacos注册中心

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

一、下载nacos-server

下载地址:github.com/alibaba/nac…

二、安装启动nacos

下载–解压安装nacos,双击bin/startup.cmdhttp://localhost:8848/nacos/#/login 账号密码nacos

image.png

image.png

三、添加Nacos依赖:放到gulimall-commonpom.xml中,不写版本是因为里面有了版本管理

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

image.png 四、使用 @EnableDiscoveryClient 注解开启服务注册与发现功能

@SpringBootApplication
@EnableDiscoveryClient
public class GulimallCouponApplication {

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

}

image.png

image.png

五、最后application.yml内容,配置服务注册中心地址:127.0.0.1:8848和当前模块名字

spring:
  datasource:
    username: root
    password: root
    url: jdbc:mysql://192.168.56.10:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
    driver-class-name: com.mysql.cj.jdbc.Driver
  cloud:
    nacos:
      discovery:
        #指定nacos地址,即注册中心地址
        server-addr: 127.0.0.1:8848
  #指定服务名称
  application:
    name: gulimall-coupon

mybatis-plus:
  mapper-locations: classpath:/mapper/**/*.xml
  global-config:
    db-config:
      id-type: auto


server:
  port: 7000

image.png

image.png

六、启动对应的模块,查看nacos中的服务列表信息,如下图所示

image.png

Feign(远程调用)

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

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

一、首先引入feign依赖

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

2.我们之前在member的pom.xml已经引用过了(微服务)。在coupon中修改如下的内容,即添加一个测试接口用于其他服务的远程调用测试

@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;

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

3.在member模块中编写Feign接口,如下:

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

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

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

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

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

@RestController
@RequestMapping("member/member")
public class MemberController {
    @Autowired
    private MemberService memberService;

    @Autowired
    CouponFeignService couponFeignService;

    @RequestMapping("/coupons")
    public R test(){
        MemberEntity memberEntity = new MemberEntity();
        memberEntity.setNickname("会员昵称张三");
        R membercoupons = couponFeignService.membercoupons();//假设张三去数据库查了后返回了张三的优惠券信息

        //打印会员和优惠券信息
        return R.ok().put("member",memberEntity).put("coupons",membercoupons.get("coupons"));
    }

6.重新启动服务,在浏览器中访问http://localhost:8000/member/member/coupons 响应的数据如下:

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

openFeign报错如下:

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 'com.atguigu.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?

错误参考帖子:blog.csdn.net/weixin_4572…

nacos配置中心

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

官方教程:github.com/alibaba/spr…

1.common中添加依赖 nacos配置中心

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

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

#指定微服务名称
spring.application.name=gulimall-coupon 
#指定配置中心的地址
spring.cloud.nacos.config.server-addr=127.0.0.1:8848

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

还是配合@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);
    }

但是如果想要修改工程配置文件中配置项的值肿么办?实际生产中不能重启应用。在coupon的控制层上加@RefreshScope

@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
    @Autowired
    private CouponService couponService;

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

        return R.ok().put("name",name).put("age",age);
    }

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

image.png

重启后(让注解生效),在nacos浏览器里修改配置,修改就可以观察到能动态修改了

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

综上nacos作为配置中心步骤总结如下:

/**
 * nacos配置中心步骤
 * 1)添加nacos作为配置中心的依赖
 * 2)在工程中创建一个bootstrap.properties文件,该文件会优先加载于application.properties/yml
 *      在该文件中配置微服务名称(nacos中的微服务名称),并且指定配置中心的地址
 *      spring.application.name=gulimall-coupon
 *      spring.cloud.nacos.config.server-addr=127.0.0.1:8848
 *3)需要给配置文件中心添加一个叫数据集(Data Id)gulimall-coupon.properties,默认规则:应用名称.properties
 *4)给应用.properties添加任何配置
 *5)动态获取配置
 *  在对应的Controller类上面添加注解 @RefreshScope:动态获取并且刷新配置
 *  @value("${配置项的名称}"),获取到配置
 *  如果配置中心和当前的工程中的配置文件都配置了相同的配置项,优先使用配置中心中的配置
 */
@SpringBootApplication
@EnableDiscoveryClient
public class GulimallCouponApplication {

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

}

Nacos配置中心进阶

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

  • 默认public。默认新增的配置都在public空间下
  • 开发、测试、开发可以用命名空间分割。properties每个空间有一份。
  • 在bootstrap.properties里配置(测试完去掉,学习不需要) 简单演示如下:

image.png

image.png

image.png

image.png

接着在gulimall-coupon工程中的bootstrap.properties中指定上面新建的命名空间ID,项目启动就会从该命名空间下读取gulimall-coupon.properties配置文件的信息。注意指定namespace命名空间不能直接使用名称,例如prod,必须使用prod对应的唯一id

spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=16c5c604-e1cf-4a45-89b4-12961e856e0c

controller中的测试代码如下:

@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);
}

启动项目,查看测试效果如下图所示

image.png

当然也可以为每个微服务配置一个命名空间,微服务互相隔离,看怎么设计

配置集:一组相关或不相关配置项的集合。即一个配置文件中会有很多的配置项,例如配置数据源的,配置跟mybatis整合的,这些就是配置集。

配置集ID:类似于配置文件名,即Data ID,配置集ID默认规则:应用名称.properties。即默认情况下,nacos会默认使用默认命名空间public下面DEFAULT_GROUP分组下面的应用名称.properties配置文件。

配置分组:默认所有的配置集都属于DEFAULT_GROUP。双十一,618的优惠策略改分组即可

简单演示如下:

image.png

image.png

image.png

修改gulimall-coupon工程中的bootstrap.properties文件,指定分组,如下

spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=16c5c604-e1cf-4a45-89b4-12961e856e0c
spring.cloud.nacos.config.group=TEST_DROUP

启动项目测试结果如下:

image.png

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

加载多配置集:很多时候咱们的配置文件中配置的东西太多,配置文件过于庞大,我们要把原来application.yml里的内容都分文件抽离出去。比如配置跟mybatis整合的分离出去mybatis.yml,配置数据源的datasource.yml等等,我们在nacos里创建好后,在coupons里指定要导入的配置即可bootstrap.properties修改如下:

spring.application.name=gulimall-coupon

spring.cloud.nacos.config.server-addr=127.0.0.1:8848
# 可以选择对应的命名空间 # 写上对应环境的命名空间ID
spring.cloud.nacos.config.namespace=b176a68a-6800-4648-833b-be10be8bab00
# 更改配置分组
spring.cloud.nacos.config.group=dev

#新版本不建议用下面的了
#spring.cloud.nacos.config.ext-config[0].data-id=datasource.yml
#spring.cloud.nacos.config.ext-config[0].group=dev
#spring.cloud.nacos.config.ext-config[0].refresh=true
#spring.cloud.nacos.config.ext-config[1].data-id=mybatis.yml
#spring.cloud.nacos.config.ext-config[1].group=dev
#spring.cloud.nacos.config.ext-config[1].refresh=true
#spring.cloud.nacos.config.ext-config[2].data-id=other.yml
#spring.cloud.nacos.config.ext-config[2].group=dev
#spring.cloud.nacos.config.ext-config[2].refresh=true

spring.cloud.nacos.config.extension-configs[0].data-id=datasource.yml
spring.cloud.nacos.config.extension-configs[0].group=dev
spring.cloud.nacos.config.extension-configs[0].refresh=true

spring.cloud.nacos.config.extension-configs[1].data-id=mybatis.yml
spring.cloud.nacos.config.extension-configs[1].group=dev
spring.cloud.nacos.config.extension-configs[1].refresh=true

spring.cloud.nacos.config.extension-configs[2].data-id=other.yml
spring.cloud.nacos.config.extension-configs[2].group=dev
spring.cloud.nacos.config.extension-configs[2].refresh=true

上述配置中config是一个数组,数组中每一个元素就是一个配置集,即比如配置mybatis整合的就是config[0].配置数据源配置集的就是config[1]。

具体配置步骤略,启动项目,查看日志,输出内容有

2020-06-25 00:04:13.677  WARN 17936 --- [           main] c.a.c.n.c.NacosPropertySourceBuilder     : Ignore the empty nacos configuration and get it based on dataId[gulimall-coupon] & group[dev]

2020-06-25 00:04:13.681  INFO 17936 --- [           main] b.c.PropertySourceBootstrapConfiguration :
Located property source: [
BootstrapPropertySource {name='bootstrapProperties-gulimall-coupon.properties,dev'}, 
BootstrapPropertySource {name='bootstrapProperties-gulimall-coupon,dev'}, 
BootstrapPropertySource {name='bootstrapProperties-other.yml,dev'}, 
BootstrapPropertySource {name='bootstrapProperties-mybatis.yml,dev'}, 
BootstrapPropertySource {name='bootstrapProperties-datasource.yml,dev'}]

网关gateway

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

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

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

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

spring.io/projects/sp…

参考手册:cloud.spring.io/spring-clou…

三大核心概念

  • Route: 发一个请求给网关,网关要将请求路由到指定的服务。路由有id,目的地uri,断言的集合,匹配了断言就能到达指定位置,

  • Predicate断言: 就是java里的断言函数,匹配请求里的任何信息,包括请求头等。根据请求头路由哪个服务

  • Filter: 过滤器请求和响应都可以被修改。客户端发请求给服务端。中间有网关。先交给映射器,如果能处理就交给handler处理,然后交给一系列filer,然后给指定的服务,再返回回来给客户端。

image.png

一句话:当请求发送到网关时,首先根据断言判断是否能路由,如果可以路由,则将请求交给过滤器链,最终到达目标服务;请求的响应也要先经过过滤器链,然后才给返回

image.png

image.png

创建,使用initilizer,Group:com.atguigu.gulimall,Artifact: gulimall-gateway,package:com.atguigu.gulimall.gateway。 搜索gateway选中。pom.xml里加上common依赖, 修改jdk版本,

pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>guli-mall</artifactId>
        <groupId>com.zsy</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>mall-gateway</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <description>API网关</description>
    <name>mall-gateway</name>

    <dependencies>
        <dependency>
            <groupId>com.zsy</groupId>
            <artifactId>mall-common</artifactId>
            <exclusions>
                <exclusion>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-starter-web</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

主启动类,下面在@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})过滤掉数据源信息,这是因为guliall-gateway工程依赖common,common中存在mybatis依赖,需要配置数据源,如果不配置的话启动项目就会报错,所以把数据源信息去掉,项目启动就不会报错

@EnableDiscoveryClient
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class MallGatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(MallGatewayApplication.class, args);
    }
}

配置文件application.yaml

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.163.131:8848
server:
  port: 88

bootstrap.yaml,读取配置中心的配置,在配置中心为每个分组创建各自的命名空间。

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        file-extension: yaml
        namespace: 07abe11f-3ead-4ae4-add6-71e8f129bfb9

配置gateway路由规则

spring:
  application:
    name: mall-gateway
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.163.131:8848
    gateway:
      routes:
        #Query A 参数有A就行,Query B,C 参数B的值为C即可
        #实现针对于“http://localhost:88/hello?url=baidu”,转发到“https://www.baidu.com/hello”,
        #针对于“http://localhost:88/hello?url=qq”的请求,转发到“https://www.qq.com/hello”
        - id: baidu_route
          uri: https://www.baidu.com
          predicates:
            - Query=url,baidu

        - id: github_route
          uri: https://www.github.com
          predicates:
            - Query=url,github

server:
  port: 88

启动项目分别请求:

http://localhost:88/s?wd=Ep%E6%B5%81%E8%8B%8F&url=baidu

github.com/zsy0216?url…

会分别跳转到百度和github 表示成功。

网关底层使用的是Netty