提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
谷粒商场:
项目采用SpringCloudAlibaba技术栈。由业务集群系统+后台管理系统构成,打通了微服务分布式开发及全栈开发技能,包含前后分离全栈开发、Restful接口、数据校验、网关、注册发现、配置中心、熔断、限流、降级、链路追踪、性能监控、压力测试、系统预警、集群部署、持续集成、持续部署…
包括前台商城系统以及后台管理系统,基于 SpringCloud + SpringCloudAlibaba + MyBatis-Plus等技术实现。 采用 Docker 容器化部署,前后端分离开发。前台商城系统包括:用户登录、注册;商品搜索、商品详情、购物车、下订单流程、秒杀活动等模块…
微服务架构风格,就像是把一个单独的应用程序开发为一套小服务,每个小服务运行在自己的进程中,并使用轻量级机制通信,通常是HTTP API。这些服务围绕业务能力来构建,并通过完全自动化部署机制来独立部署。这些服务使用不同的编程语言书写,以及不同数据存储技术,并保持最低限度的集中式管理。
简而言之:拒绝大型单体应用,基于业务边界进行服务微化拆分,各个服务独立部署运行。
集群是个物理形态,分布式是个工作方式。
集群是指将几台服务器集中在一起,实现统一业务。
分布式是指将不同的业务分布在不同的地方。
节点:集群中的一个服务器。 分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像是单个相关系统。
分布式中的每一个节点,都可以叫集群。而集群不一定就是分布式的。
在分布式系统中,各个服务可能处于不同主机,但是服务之间不可避免的需要互相调用,我们称之为远程调用。
Spring Cloud 中使用 HTTP + JSON 的方式完成远程调用。
常见负载均衡算法:
轮询: 按顺序依次循环调用。
最小连接: 优先选择连接数量最少的,也就是压力最小的后端服务器,在会话较长的情况下可以考虑采取这种方式。
散列: 根据请求源的 IP 的散列来选择要转发的服务器。这种方式可以一定程度上保证特定用户能连接到相同的服务器。如果你的应用需要处理状态而要求用户能连接到和之前相同的服务器,可以考虑采取这种方式。
A 服务调用 B 服务,A 服务并不知道 B 服务当前在哪几台服务器有,哪些正常,哪些服务已经下线。解决这个问题引入注册中心。如果某些服务下线,我们其他人可以实时的感知到其他服务的状态,从而避免调用不可用的服务。
集中管理微服务的配置信息
服务熔断: 设置服务的超时,当被调用的服务经常失败到达某个阈值,我们可以开启断路保护机制,后来的请求不再去调用这个服务。本地直接返回默认的数据。
服务降级: 在运维期间,当系统处于高峰期,系统资源紧张,我们可以让非核心业务降级运行。降级:某些业务不处理,或者简单处理【抛异常、返回 Null 、返回 Mock 数据、调用 Fallback 处理逻辑】
在微服务架构中,API Gateway 作为整体架构的重要组件,它抽象了微服务中都需要的公共功能,同时提供了客户端负载均衡、服务自动熔断、灰度发布、统一认证、限流流控、日志统计等丰富的功能,帮助我们解决了很多 API 管理难题。
外网是面向公众访问的,部署前端项目,可以有手机APP,电脑网页;
内网部署的是后端集群,前端在页面上操作发送请求到后端,在这途中会经过Nginx集群,Nginx把请求转交给API网关(springcloud gateway)(网关可以根据当前请求动态地路由到指定的服务,看当前请求是想调用商品服务还是购物车服务还是检索),从路由过来如果请求很多,可以负载均衡地调用商品服务器中一台(商品服务复制了多份),当商品服务器出现问题也可以在网关层面对服务进行熔断或降级(使用阿里的sentinel组件),网关还有其他的功能如认证授权、限流(只放行部分到服务器)等。
到达服务器后进行处理(springboot为微服务),服务与服务可能会相互调用(使用OpenFeign组件),有些请求可能经过登录才能进行(基于OAuth2.0的认证中心。安全和权限使用springSecurity控制)
服务可能保存了一些数据或者需要使用缓存,我们使用redis集群(分片+哨兵集群)。持久化使用mysql,读写分离和分库分表。
服务和服务之间会使用消息队列(RabbitMQ),来完成异步解耦,分布式事务的一致性。有些服务可能需要全文检索,检索商品信息,使用ElaticSearch。
服务可能需要存取数据,使用阿里云的对象存储服务OSS。
项目上线后为了快速定位问题,使用ELK对日志进行处理,使用LogStash收集业务里的各种日志,把日志存储到ES中,用Kibana可视化页面从ES中检索出相关信息,帮助我们快速定位问题所在。
在分布式系统中,由于我们每个服务都可能部署在很多台机器,服务和服务可能相互调用,就得知道彼此都在哪里,所以需要将所有服务都注册到注册中心。服务从注册中心发现其他服务所在位置(使用阿里Nacos作为注册中心)。
每个服务的配置众多,为了实现改一处配置相同配置就同步更改,就需要配置中心,也使用阿里的Nacos,服务从配置中心中动态取配置。
服务追踪,追踪服务调用链哪里出现问题,使用springcloud提供的Sleuth、Zipkin、Metrics,把每个服务的信息交给开源的Prometheus进行聚合分析,再由Grafana进行可视化展示,提供Prometheus提供的AlterManager实时得到服务的告警信息,以短信/邮件的方式告知服务开发人员。
还提供了持续集成和持续部署。项目发布起来后,因为微服务众多,每一个都打包部署到服务器太麻烦,有了持续集成后开发人员可以将修改后的代码提交到github,运维人员可以通过自动化工具Jenkins Pipeline将github中获取的代码打包成docker镜像,最终是由k8s集成docker服务,将服务以docker容器的方式运行。
微服务划分图
反映了需要创建的微服务以及相关技术。
前后分离开发。前端项目分为admin-vue(工作人员使用的后台管理系统)、shop-vue(面向公众访问的web网站)、app(公众)、小程序(公众)
#卸载系统之前的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
sudo systemctl start docker
# 设置开机自启动
sudo systemctl enable docker
docker -v
sudo docker images
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://chqac97z.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
sudo docker pull mysql:5.7
# --name指定容器名字 -v目录挂载 -p指定端口映射 -e设置mysql参数 -d后台运行
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
# 进入已启动的容器
docker exec -it mysql bin/bash
# 退出进入的容器
exit;
因为有目录映射,所以我们可以直接在镜像外执行
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
保存(注意评论区该配置不对,不是collection而是collation)
docker restart mysql
如果直接挂载的话docker会以为挂载的是一个目录,所以我们先创建一个文件然后再挂载,在虚拟机中。
# 在虚拟机中
mkdir -p /mydata/redis/conf
touch /mydata/redis/conf/redis.conf
docker pull redis
docker run -p 6379:6379 --name redis \
-v /mydata/redis/data:/data \
-v /mydata/redis/conf/redis.conf:/etc/redis/redis.conf \
-d redis redis-server /etc/redis/redis.conf
# 直接进去redis客户端。
docker exec -it redis redis-cli
默认是不持久化的。在配置文件中输入appendonly yes,就可以aof持久化了。修改完docker restart redis,docker -it redis redis-cli
vim /mydata/redis/conf/redis.conf
# 插入下面内容
appendonly yes
保存
docker restart redis
设置redis容器在docker启动的时候启动
docker update redis --restart=always
课件提供了sql文件
由于是第一次打开,使用npm install下载前端项目运行需要的各种环境:
1.npm install
出现以下错误信息:
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] install: `node install.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] install script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! C:\Users\DELL\AppData\Roaming\npm-cache\_logs\2021-12-04T07_35_55_129Z-debug.log
应该是镜像拉取的时候被墙屏蔽了,使用下面命令进行解决:
npm install [email protected] --ignore-scripts
package.json相当于pom文件,设置版本号。node_modules是用于存放下载的组件
ERROR Failed to compile with 6 errors 下午3:47:18
error in ./src/assets/scss/index.scss
Module build failed: Error: Cannot find module 'node-sass'
解决方案:
npm install node-sass --save
npm install -g cnpm --registry=https://registry.npm.taobao.org
cnpm install node-sass --save
cnpm : 无法加载文件 C:\Users\DELL\AppData\Roaming\npm\cnpm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=135170 中的 about_Execution_Policies。
所在位置 行:1 字符: 1
cnpm install node-sass --save
CategoryInfo : SecurityError: (:) [],PSSecurityException
FullyQualifiedErrorId : UnauthorizedAccess
解决方案:
1.以管理员身份运行Windows POWERSHELL
2.输入set-ExecutionPolicy RemoteSigned指令
3.输入A
4.再次执行cnpm install node-sass --save命令
git clone https://gitee.com/renrenio/renren-generator.git
下载到桌面后,同样把里面的.git文件删除,然后移动到我们IDEA项目目录中,同样配置好pom.xml
刷新maven出现以下错误信息:
'parent.relativePath' of POM io.renren:renren-generator:1.0.0 (D:\IdeaProject\gulimall\renren-generator\pom.xml) points at com.atguigu.gulimall:gulimall instead of org.springframework.boot:spring-boot-starter-parent, please verify your project structure @ line 11, column 10
It is highly recommended to fix these problems because they threaten the stability of your build.
For this reason, future Maven versions might no longer support building such malformed projects.
解决方案:添加 < relativePath/>
ss
url: jdbc:mysql://192.168.56.10:3306/gulimall-pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
username: root
password: root
#代码生成器配置
mainPath=com.ljn
#包名
package=com.ljn.gulimall
moduleName=coupon
#作者
author=ljn
#Email
email=1046016768@qq.com
# 表前缀(添加后,类名不会包含表前缀)
# 由于gulimall_product数据库中的表都是以pms为前缀的,所以tablePrefix为pms
tablePrefix=sms_
生成代码的路径名为:package+moduleName
启动项目,登录localhost:80,生成代码,并将生成的代码进行替换,并改正代码错误
在common项目的pom.xml中添加
<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>
<!-- 导入mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.26</version>
</dependency>
</dependencies>
我们把每个微服务里公共的类和依赖放到common里。
然后在product等所有项目模块中的pom.xml中加入下面内容,作为common的子项目
<dependency>
<groupId>com.atguigu.gulimall</groupId>
<artifactId>gulimall-common</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
1.在product项目的resources目录下新建application.yml
spring:
datasource: #配置数据源
driver-class-name: com.mysql.cj.jdbc.Driver #配置驱动
url: jdbc:mysql://192.168.10.129:3306/gulimall_pms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai #配置url
username: root
password: root
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml #配置mybatis-plus扫描映射文件的位置
global-config:
db-config:
id-type: auto #配置主键自增 ,
2.然后在主启动类上加上注解@MapperScan()
/**
* 1.整合mybatis-plus
* 1.导入依赖
* 2.配置:
* 1.配置数据源
* 1.导入数据库驱动(在common中)
* 2.在application.yml中配置数据源相关信息
* 2.配置mybatis-plus相关信息
* 1.使用@MapperScan 注解
* 2.告诉mybatis-plus,sql映射文件位置
*/
@MapperScan("com.ljn.gulimall.product.dao")
@SpringBootApplication
public class GulimallProductApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallProductApplication.class, args);
}
}
3.测试
@SpringBootTest
class gulimallProductApplicationTests {
@Autowired
BrandService brandService;
@Test
void contextLoads() {
BrandEntity brandEntity = new BrandEntity();
brandEntity.setDescript("哈哈1哈");
brandEntity.setName("华为");
brandService.save(brandEntity);
System.out.println("保存成功");
}
}
在数据库中就能看到新增数据了
如:生成coupon服务代码
# 主目录
mainPath=com.atguigu
#包名
package=com.atguigu.gulimall
#模块名--修改的地方
moduleName=coupon
#作者
autho=hh
#email
email=55333@qq.com
#表前缀(类名不会包含表前缀) # 我们的pms数据库中的表的前缀都pms
# 如果写了表前缀,每一张表对于的javaBean就不会添加前缀了
tablePrefix=sms_ #这里也修改了
spring:
datasource:
username: root
password: root
url: jdbc:mysql://192.168.56.10:3306/gulimall-sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml
global-config:
db-config:
id-type: auto
logic-delete-value: 1
logic-not-delete-value: 0
server:
port: 7000
3.让coupon也依赖于common,修改pom.xml
<dependency>
<groupId>com.ljn.gulimall</groupId>
<artifactId>gulimall-commom</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
启动生成RenrenApplication.java,运行后去浏览器80端口查看,同样让他一页全显示后选择全部后生成。生成后解压复制到coupon项目对应目录下。
6.配置coupon服务的application.yaml
spring:
datasource: #配置数据源
driver-class-name: com.mysql.cj.jdbc.Driver #配置驱动
url: jdbc:mysql://192.168.10.129:3306/gulimall_sms?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai #配置url
username: root
password: root
mybatis-plus:
mapper-locations: classpath:/mapper/**/*.xml #配置mybatis-plus扫描映射文件的位置
global-config:
db-config:
id-type: auto #配置主键自增 ,
5.启动coupon服务
访问http://localhost:8080/coupon/coupon/list
在common模块中引入依赖,在common的pom.xml中加入
下面是依赖管理,相当于以后再dependencies里引spring cloud alibaba就不用写版本号, 全用dependencyManagement进行管理
<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 Cloud 应用如何接入 Nacos Discovery。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
启动命令windows:startup.cmd -m standalone
在应用的application.yml 配置文件中配置Nacos地址
spring:
cloud:
nacos:
discovery:
server-addr: localhost:8848
application:
name: gulimall-coupon
在服务的启动类中加上 @EnableDiscoveryClient 注解(如coupon)
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallCouponApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallCouponApplication.class, args);
}
}
其他服务配置步骤相同
想要获取当前会员领取到的所有优惠券。先去注册中心找优惠券服务,
注册中心调一台优惠券服务器给会员,会员服务器发送请求给这台优
惠券服务器,然后对方响应。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在coupon服务的CouponController类中
@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");//优惠券的名字
// 放入一个coupons
return R.ok().put("coupons",Arrays.asList(couponEntity));
}
在member的配置类上加注解
@EnableFeignClients(basePackages="com.yxj.gulimall.member.feign"),
告诉spring这里面是一个远程调用客户端,member要调用的接口
package com.ljn.gulimall.member;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
/*
* 想要远程调用的步骤:
* 1 引入openfeign
* 2 编写一个接口,接口告诉springcloud这个接口需要调用远程服务
* 2.1 在接口里声明@FeignClient("gulimall-coupon")他是一个远程调用客户端且要调用coupon服务
* 2.2 要调用coupon服务的/coupon/coupon/member/list方法
* 3 开启远程调用功能 @EnableFeignClients,要指定远程调用功能放的基础包
* */
@EnableFeignClients(basePackages="com.ljn.gulimall.member.feign")//扫描接口方法注解
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallMemberApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallMemberApplication.class, args);
}
}
1.在member的com.ljn.gulimall.member.feign包下新建类:
// 这是一个声明式的远程调用
@FeignClient("gulimall-coupon")
public interface CouponFeignService {
//告诉spring cloud这个接口是一个远程客户端,要调用coupon服务(nacos中找到),具体是调用coupon服务的/coupon/coupon/member/list对应的方法
// 远程服务的url
@RequestMapping("/coupon/coupon/member/list")//注意写全优惠券类上还有映射//注意我们这个地方不是控制层,所以这个请求映射请求的不是我们服务器上的东西,而是nacos注册中心的
public R membercoupons();//得到一个R对象
}
2.在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"));// membercoupons.get("coupons") 获取coupons中放入的coupons
}
测试:http://localhost:8000/member/member/coupons
用nacos作为配置中心。配置中心的意思是不在application.properties等文件中配置了,而是放到nacos配置中心公用,这样无需每台机器都改。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
# 改名字,对应nacos里的配置文件名
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
//从application.properties中获取
// 不要写user.name,他是环境里的变量
@Value("${coupon.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);
}
data ID:gulimall-coupon.properties,添加配置
默认规则:应用名.properties
coupon.user.name=zhagnsan
coupon.user.age=100
实际生产中不能重启应用。在coupon的控制层上加@RefreshScope
动态获取配置:
@RefreshScope
@RestController
@RequestMapping("coupon/coupon")
public class CouponController {
@Autowired
private CouponService couponService;
@Value("${coupon.user.name}")//从application.properties中获取//不要写user.name,他是环境里的变量
private String name;
@Value("${coupon.user.age}")
private Integer age;
@RequestMapping("/test")
public R test(){
return R.ok().put("name",name).put("age",age);
}
nacos的配置内容优先于项目本地的配置内容。
在nacos浏览器中还可以配置:
命名空间:用作配置隔离。(一般每个微服务一个命名空间)
可以选择对应的命名空间 # 写上对应环境的命名空间ID
spring.cloud.nacos.config.namespace=b176a68a-6800-4648-833b-be10be8bab00
配置集:一组相关或不相关配置项的集合
配置集ID:类似于配置文件名,即Data ID
配置分组:默认所有的配置集都属于DEFAULT_GROUP。双十一,618的优惠策略改分组即可
更改配置分组
spring.cloud.nacos.config.group=DEFAULT_GROUP(选择需要使用的组)
项目中的使用:每个微服务创建自己的命名空间,使用配置分组区分环境,dev,test,prod。
我们要把原来application.yml里的内容都分文件抽离出去。我们在nacos里创建好后,在coupons里指定要导入的配置即可。
比如抽取:datasource.yml、mybatis.yml、other.yml。
在bootstrap.properties中加载配置
# 改名字,对应nacos里的配置文件名
spring.application.name=gulimall-coupon
spring.cloud.nacos.config.server-addr=localhost:8848
# 可以选择对应的命名空间 # 写上对应环境的命名空间ID
spring.cloud.nacos.config.namespace=79d5ebaa-bd56-446e-97e1-ba06cd7e51fa
# 更改配置分组
spring.cloud.nacos.config.group=dev
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
网关是请求流量的入口,常用功能包括路由转发,权限校验,限流控制等。springcloud gateway取代了zuul网关。
流程:
客户端发请求给服务端。中间有网关。先交给映射器,如果能处理就交给handler处理,然后交给一系列filer,然后给指定的服务,再返回回来给客户端。
<!-- 依赖common-->
<dependency>
<groupId>com.ljn.gulimall</groupId>
<artifactId>gulimall-commom</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
在主启动类中添加注解@EnableDiscoveryClient
@EnableDiscoveryClient
@SpringBootApplication
public class GulimallGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GulimallGatewayApplication.class, args);
}
}
去nacos里创建命名空间gateway(项目与项目用命名空间隔离),然后在命名空间里创建文件guilmall-gateway.yml
spring.application.name=gulimall-gateway
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
server.port=88
spring.application.name=gulimall-gateway
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=0769376d-1b8c-49ce-a9aa-b814667204ec
spring:
cloud:
gateway:
routes:
- id: baidu_route
uri: http://www.baidu.com
predicates:
- Query=url,baidu
- id: test_route
uri: http://www.qq.com
predicates:
- Query=url,qq
var在{}之外也起作用
let在{}之外不起作用
var多次声明同一变量不会报错,let多次声明会报错,只能声明一次。
var 会变量提升(打印和定义可以顺序反)。let 不存在变量提升(顺序不能反)
const声明之后不允许改变
支持let arr = [1,2,3]; let [a,b,c] = arr;这种语法
支持对象解析:const { name: abc, age, language } = person; 冒号代表改名
字符串函数
支持一个字符串为多行
占位符功能 ${}
原来想要函数默认值得这么写b = b || 1; 现在可以直接写了function add2(a, b = 1) {
函数不定参数function fun(...values) {
支持箭头函数(lambda表达式),还支持使用{}结构传入对象的成员
//箭头函数+解构
var hello2 = ({name}) => console.log("hello," +name);
hello2(person);
可以获取map的键值对等Object.keys()、values、entries
Object.assgn(target,source1,source2) 合并
const person2 = { age, name } //声明对象简写
…代表取出该对象所有属性拷贝到当前对象。let someone = { …p1 }
//数组中新增了map和reduce方法。
//map():接收一个函数,将原数组中的所有元素用这个函数处理后放入新数组返回。
let arr = ['1', '20', '-5', '3'];
arr = arr.map(item=> item*2);
//reduce() 为数组中的每一个元素依次执行回调函数,不包括数组中被删除或从未被赋值的元素,
//[2, 40, -10, 6]
//arr.reduce(callback,[initialValue])
1、previousValue (上一次调用回调返回的值,或者是提供的初始值(initialValue))
2、currentValue (数组中当前被处理的元素)
3、index (当前元素在数组中的索引)
4、array (调用 reduce 的数组
let result = arr.reduce((a,b)=>{
console.log("上一次处理后:"+a);
console.log("当前正在处理:"+b);
return a + b;
},100);
corse_score_10.json 得分
{
"id": 100,
"score": 90
}
user.json 用户
{
"id": 1,
"name": "zhangsan",
"password": "123456"
}
user_corse_1.json 课程
{
"id": 10,
"name": "chinese"
}
以前嵌套ajax的时候很繁琐。
解决方案:
把Ajax封装到Promise中,赋值给let p
在Ajax中成功使用resolve(data),交给then处理,
失败使用reject(err),交给catch处理p.then().catch()
//1、Promise可以封装异步操作
let p = new Promise((resolve, reject) => { //传入成功解析,失败拒绝
//1、异步操作
$.ajax({
url: "mock/user.json",
success: function (data) {
console.log("查询用户成功:", data)
resolve(data);
},
error: function (err) {
reject(err);
}
});
});
p.then((obj) => { //成功以后做什么
return new Promise((resolve, reject) => {
$.ajax({
url: `mock/user_corse_${obj.id}.json`,
success: function (data) {
console.log("查询用户课程成功:", data)
resolve(data);
},
error: function (err) {
reject(err)
}
});
})
}).then((data) => { //成功以后干什么
console.log("上一步的结果", data)
$.ajax({
url: `mock/corse_score_${data.id}.json`,
success: function (data) {
console.log("查询课程得分成功:", data)
},
error: function (err) {
}
});
})
//自己定义一个方法整合一下
function get(url, data) {
return new Promise((resolve, reject) => {
$.ajax({
url: url,
data: data,
success: function (data) {
resolve(data);
},
error: function (err) {
reject(err)
}
})
});
}
get("mock/user.json")
.then((data) => {
console.log("用户查询成功~~~:", data)
return get(`mock/user_corse_${data.id}.json`);
})
.then((data) => {
console.log("课程查询成功~~~:", data)
return get(`mock/corse_score_${data.id}.json`);
})
.then((data)=>{
console.log("课程成绩查询成功~~~:", data)
})
.catch((err)=>{ //失败的话catch
console.log("出现异常",err)
});
模块化就是把代码进行拆分,方便重复利用。类似于java中的导包,
而JS换了个概念,是导模块。
模块功能主要有两个命令构成 export 和import
export用于规定模块的对外接口
import用于导入其他模块提供的功能