大家好,欢迎来到IT知识分享网。
SpringCloud Alibaba完整使用
- 资料领取
- 一、AlibabaCloud微服务初级篇依赖认知
- 二、AlibabaCloud微服务运维篇环境搭建
-
- 1、虚拟机搭建
- 3、Docker-compose搭建Maven私服
- 4、Docker-compose搭建Nacos搭建
- 5、Docker-compose搭建mysql数据库
- 6、Docker-compose搭建Sentinel限流服务
- 7、Docker-compose搭建Zipkin链路追踪
- 8、Docker-compose搭建Elasticsearch
- 9、Docker-compose搭建Redis
- 10、Docker-compose搭建RebaitMQ
- 11、Docker-compose搭建 Nginx
- 12、kafka集群搭建
- 13、DNS解析
- 14、Docker-compose搭建MogoDB
- 15、Docker-compose搭建RocketMQ
- 16、docker-compose安装
- 三、AlibabaCloud微服务组件与搭建模型
-
- 1、模块划分
- 2、搭建模块
- 3、全部服务统一配置环境
- 4、配置IDEA的Run DashBoard模式
- 5、配置cloud-Admin微服务模块
- 6、配置Cloud-common服务
- 7、整合Alibaba Cloud gateway服务
- 8、整合Alibaba Cloud Nacos注册中心
- 9、整合Alibaba Cloud Config Nacos的配置中心
- 10、整合Alibaba Cloud zkpin链路追踪
- 11、整合Alibaba Cloud Feign组件
- 12、整合Alibaba Cloud Feign超时配置
- 13、整合Alibaba Cloud Feign性能优化
- 14、整合Feign整合Alibaba Cloud sentinel
- 15、整合Alibaba Cloud Feign整合日志
- 16、整合Alibaba Cloud Feign重试机制
- 17、整合优化Alibaba Cloud Feign压缩
- 18、移Feign配置到Alibaba Cloud Nacos中心
- 19、整合Alibaba Cloud OSS服务
- 2)导入到cloud_common工具类
- 20、整合Alibaba Cloud SMS 短信服务
- 21、整合AlibabaCloud集成ELK收集日志
- 22、ELK监控MYSQL
- 23、整合AlibabaCloud全局异常
- 24、AlibAbaCloud微服务负载均衡
- 25、整合AlibabaCloud全局日志注解
- 26、整合AlibabaCloud RocketMQ消息队列生产
- 27、新增AlibabaCloud RocketMQ日志服务消费
- 28、监听RocketMQ操作日志到MongoDB
- 29、全部服务RockMQ配置迁移Nacos
- 30、Nacos配置中心共享YML
- 31、配置BootAdmin权限登录监控
- 32、CloudAlibaba整合报警配置
- 四、AlibabaCloud微服务中级篇下鉴权
- 五、AlibabaCloud微服高级篇章业务模型
- 六、kubesphere高级运维云原生
资料领取
可以学到微服务里面的各种组件搭建使用教程、6666
1、视频学习
2、学习搭建网站
3、技术交流QQ群
4、源码地址
https://gitee.com/yswyn_admin/cloud_api
一、AlibabaCloud微服务初级篇依赖认知
1、版本依赖关系讲解
1)官方网站
2)采取毕业版本依赖关系
由于 Spring Boot 2.4+ 和以下版本之间变化较大,目前企业级客户老项目相关 Spring Boot 版本仍停留在
Spring Boot 2.4 以下,为了同时满足存量用户和新用户不同需求,社区以 Spring Boot 2.4 为分界线,
同时维护 2.2.x 和 2021.x 两个分支迭代。
2、Cloud Alibaba Maven坐标
Spring Cloud Alibaba Version | 2021.0.1.0 |
---|---|
Spring Cloud Version | Spring Cloud 2021.0.1 |
Spring Boot Version | 2.6.3 |
Sentinel Version | 1.8.3 |
Nacos Version | 1.4.2 |
RocketMQ Version | 4.9.2 |
Seata Version | 1.4.2 |
3、2021.0.1.0升级指南
1)升级指针
升级版本 (注意版本对应关系)
<dependencyManagement>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencyManagement>
2)官网
4、官网地址收集
1)Cloud Alibaba官网组件大全
2)Cloud Alibaba依赖关系
3)Cloud Alibaba 2021.0.1.0 升级定制指南
4)Cloud Alibaba Nacos 版本大全
5)Cloud Alibaba Sentinel 版本大全
5、虚拟机搭建
二、AlibabaCloud微服务运维篇环境搭建
1、虚拟机搭建
1)搭建学习地址
2)百度到哔哩哔哩
3)下载VMware16
4)安装
3、Docker-compose搭建Maven私服
4、Docker-compose搭建Nacos搭建
5、Docker-compose搭建mysql数据库
6、Docker-compose搭建Sentinel限流服务
7、Docker-compose搭建Zipkin链路追踪
8、Docker-compose搭建Elasticsearch
9、Docker-compose搭建Redis
10、Docker-compose搭建RebaitMQ
11、Docker-compose搭建 Nginx
12、kafka集群搭建
13、DNS解析
14、Docker-compose搭建MogoDB
15、Docker-compose搭建RocketMQ
16、docker-compose安装
三、AlibabaCloud微服务组件与搭建模型
1、模块划分
cloud_api 聚合服务
cloud_commont 工具服务
cloud_party 图片服务
cloud_login 登录服务
cloud_gateway 网关服务
cloud_admin 数据监控服务
cloud_production 数据生产服务
cloud_data 数据清洗服务
cloud_ouath 接口认证服务
cloud_log 日志服务
2、搭建模块
**IDEA 2021 工具搭建**
搭建前提先看我视频搭建下要的环境
视频地址 点我进行观看
1)聚合工程搭建
(1) 给聚合父POM增加依赖
<distributionManagement>
<repository>
<!--此名称要和.m2/settings.xml中设置的ID一致 -->
<id>nexus</id>
<name>Nexus Releases Repository</name>
<url>http://192.168.2.110:8081/repository/maven-releases/</url>
</repository>
<snapshotRepository>
<!--此名称要和.m2/settings.xml中设置的ID一致 -->
<id>nexus</id>
<name>Nexus Snapshots Repository</name>
<url>http://192.168.2.110:8081/repository/maven-snapshots/</url>
</snapshotRepository>
</distributionManagement>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/>
</parent>
<dependencies>
<!--由于2021版本去除了-bootstrap.yml支持、所以我们要加上去-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
</dependencies>
<!--2021毕业版本依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!--maven插件-->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>none</mainClass> <!-- 取消查找本项目下的Main方法:为了解决Unable to find main class的问题 -->
<classifier>execute</classifier> <!-- 为了解决依赖模块找不到此模块中的类或属性 -->
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
(2) 全局动态切换环境
配置到父pom里面
<!--统一环境-->
<profiles>
<profile>
<id>prod</id>
<properties>
<profiles.active>prod</profiles.active>
</properties>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
</profile>
<profile>
<id>dev</id>
<properties>
<profiles.active>dev</profiles.active>
</properties>
</profile>
</profiles>
2)创建工具服务
3)图片服务
4)登陆服务
5)网关服务
6)数据监控服务
7)数据生产服务
8)数据清洗服务
9)接口认证服务
3、全部服务统一配置环境
1)创建三个yml
application.yml
application-dev.yml
application-prod.yml
2)整体端口和服务名称配置
给 application.yml 配置文件添加如下
server:
port: 8087
spring:
profiles:
active: dev
application:
name: 自己的服务名称比如/cloud-log
3)全部服务统一包名的昵称
创建每个服务的包名
com.cloud.api
4)全部服务增加启动类配置
@SpringBootApplication
public class APP {
public static void main(String[] args) {
//APP 每个服务的名称开头比如 APILogSpringApplication
SpringApplication.run(APP.class, args);
}
}
4、配置IDEA的Run DashBoard模式
(1) 给Workspace.xml 新增如下配置
<component name="RunDashboard">
<option name="configurationTypes">
<set>
<option value="SpringBootApplicationConfigurationType" />
</set>
</option>
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
(2) 启动不成功
需要配置
<artifactId>改成自己的服务</artifactId>
<groupId>com.cloud.api</groupId>
<version>1.0-SNAPSHOT</version>
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.3</version>
<relativePath/>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
<!--2021毕业版本依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
5、配置cloud-Admin微服务模块
1)新增监控server依赖
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-server</artifactId>
<version>2.5.1</version>
</dependency>
2)启动类怎加注解
@EnableAdminServer
3)监控配置暴漏
spring:
boot:
admin:
client:
# Admin Server的URL,若是要注册到多个admin服务端上,用逗号分隔就可以
# url: http://localhost:8080,http://localhost:8081
url: http://192.168.2.110:3005
instance:
# 使用IP的方式
prefer-ip: true
management:
endpoint:
health:
show-details: always # 显示health指标的详细信息,否则只会显示 status
# 默认情况下,大多数Actuator端点都不通过http公开,这里我们公开了所有端点。
# 对于生产,您应该仔细选择要公开的端点。
endpoints:
web:
exposure:
include: ["*"]
6、配置Cloud-common服务
1)增加依赖
这个是针对每一个服务需要注册到Admin服务的客户端
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2)每个服务新增客户端配置
在resources 下创建application.properties
# Admin Server的URL,若是要注册到多个admin服务端上,用逗号分隔就可以
# url: http://localhost:8080,http://localhost:8081
spring.boot.admin.client.url=http://localhost:3000
#使用IP的方式
spring.boot.admin.client.instance.prefer-ip=true
# 默认情况下,大多数Actuator端点都不通过http公开,这里我们公开了所有端点。
# 对于生产,您应该仔细选择要公开的端点。
management.endpoints.web.exposure.include=*
#日志收集
logging.file.name=/var/log/sample-boot-application.log
logging.pattern.file=%clr(%d{
yyyy-MM-dd HH:mm:ss.SSS}){
faint} %clr(%5p) %clr(${
PID}){
magenta} %clr(---){
faint} %clr([%15.15t]){
faint} %clr(%-40.40logger{
39}){
cyan} %clr(:){
faint} %m%n%wEx
#按实例显示标签
#元数据 ---改成自己的服务名称
spring.boot.admin.client.instance.metadata.tags.environment=cloud_data
#信息断点---改成自己的服务名称
info.tags.environment=cloud_data
3)每个微服务客户端新增依赖
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
<version>2.5.1</version>
</dependency>
4)新增整体工具依赖
<properties>
<fastjson.version>1.2.60</fastjson.version>
<org.projectlombok.version>1.18.8</org.projectlombok.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${
org.projectlombok.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${
fastjson.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!--开启自定义 配置 需要提示功能-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
</dependencies>
5)全部启动查看效果
7、整合Alibaba Cloud gateway服务
1)配置gateway依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
2)配置sentinel-gateway限流监控依赖
<!--网关流控-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
</dependency>
3)Gateway跨域
Gateway服务新增配置类
创建 com.api.gateway 的包 在创建配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
@Configuration
public class ApiCorsConfiguration {
@Bean
public CorsWebFilter corsWebFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration corsConfiguration = new CorsConfiguration();
//1、配置跨域
corsConfiguration.addAllowedHeader("*");
corsConfiguration.addAllowedMethod("*");
corsConfiguration.addAllowedOrigin("*");
corsConfiguration.setAllowCredentials(true);
source.registerCorsConfiguration("/**", corsConfiguration);
return new CorsWebFilter(source);
}
}
4)Gateway 路由
spring:
cloud:
gateway:
routes:
- id: test_route
uri: https://www.baidu.com
predicates:
- Query=url,baidu
- id: qq_route
uri: https://www.qq.com
predicates:
- Query=url,qq
- id: party_route
uri: lb://cloud-party
predicates:
- Path=/api/party/**,/hello filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: login_route uri: lb://cloud-login predicates: - Path=/api/login/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: gateway-route uri: lb://cloud-gateway predicates: - Path=/api/gateway/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: admin-route uri: lb://cloud-admin predicates: - Path=/api/admin/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment} - id: production-route uri: lb://cloud-production predicates: - Path=/api/production/** filters: - RewritePath=/api/(?<segment>.*),/$\{segment}
5)每个服务配置Sentinel注册
在dev环境下
spring:
cloud:
#监控限流
sentinel:
transport:
dashboard: 192.168.2.110:8080 #看上面提前搭建好了
8、整合Alibaba Cloud Nacos注册中心
1)cloud-common服务增加Nacos依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
2)每个服务配置Nacos注册中心
spring:
#监控限流
cloud:
nacos:
server-addr: cloud.api.com:8848
discovery:
namespace: d4dc3568-39bc-4258-83bb-a88c56fa9321 #看上面提前搭建好了
group: dev
3)每个启动类加注册Nacos注解
@EnableDiscoveryClient
4)启动看效果
9、整合Alibaba Cloud Config Nacos的配置中心
1)导入配置依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2)Nacos配置创建文件
3)担心的话进行测试
以最简单的方式配置一下
加到启动类里面进行测试获取--可以看到动态获取到参数了
while(true) {
//当动态配置刷新时,会更新到 Enviroment中,
//因此这里每隔一秒中从Enviroment中获取配置
String userName = applicationContext.getEnvironment().getProperty("user.name");
System.err.println("user name :"+userName);
TimeUnit.SECONDS.sleep(1);
}
4)配置各个微服务模块YML
spring:
#注册中心
cloud:
nacos:
server-addr: cloud.api.com:8848
discovery:
namespace: d4dc3568-39bc-4258-83bb-a88c56fa9321
group: dev
#配置中心
config:
server-addr: cloud.api.com:8848
group: dev
file-extension: yaml
namespace: d4dc3568-39bc-4258-83bb-a88c56fa9321
5、优化YML配置优先级
不进行优化导致配置拉取不到
把自己的application全部修改为bootstrap即可
10、整合Alibaba Cloud zkpin链路追踪
1)介绍
在大型系统的微服务化构建中,一个系统被拆分成了许多模块。这些模块负责不同的功能,组合成 系统,最终可以提供丰富的功能。在这种架构中,一次请求往往需要涉及到多个服务。互联网应用构建 在不同的软件模块集上,这些软件模块,有可能是由不同的团队开发、可能使用不同的编程语言来实 现、有可能布在了几千台服务器,横跨多个不同的数据中心,也就意味着这种架构形式也会存在一些问题:
如何快速发现问题?
如何判断故障影响范围?
如何梳理服务依赖以及依赖的合理性?
如何分析链路性能问题以及实时容量规划?
2)common工具配置zkpin依赖
<!-- 链路跟踪 sleuth和zipkin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>
3)在各个微服务模块加入
spring:
sleuth:
web:
client:
# 开启采集链路
enabled: true
sampler:
# 默认采集是 0.1(百分之十),生产环境采用默认,测试环境可以修改为1.0
probability: 1.0
# zipkin服务所在地址
zipkin:
base-url: http://cloud.api.com:9411/
discovery-client-enabled: false #让nacos把它当成一个URL,而不要当做服务名
4)启动看效果
5、各个服务迁移到Nacos配置中心
spring:
sleuth:
web:
client:
# 开启采集链路
enabled: true
sampler:
# 默认采集是 0.1(百分之十),生产环境采用默认,测试环境可以修改为1.0
probability: 1.0
# zipkin服务所在地址
zipkin:
base-url: http://cloud.api.com:9411/
discovery-client-enabled: false #让nacos把它当成一个URL,而不要当做服务名
11、整合Alibaba Cloud Feign组件
1)导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2)增加注解
启动类增加注解
@EnableFeignClients
3)配置请求注解
@FeignClient("cloud_login")
4)Feign整合问题一
(1) 修改每个服务的
application.properties配置文件
两个服务名改为-
(2) 修改每个服务的YML
每一个application.name= 下划线_变成-
(3) 修改Nacos的配置文件名为-
删除重新创建即可
(4) 启动报错
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:382) ~[spring-cloud-openfeign-core-3.1.1.jar:3.1.1]
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getTarget(FeignClientFactoryBean.java:427) ~[spring-cloud-openfeign-core-3.1.1.jar:3.1.1]
at org.springframework.cloud.openfeign.FeignClientFactoryBean.getObject(FeignClientFactoryBean.java:402) ~[spring-cloud-openfeign-core-3.1.1.jar:3.1.1]
at org.springframework.cloud.openfeign.FeignClientsRegistrar.lambda$registerFeignClient$0(FeignClientsRegistrar.java:235) ~[spring-cloud-openfeign-core-3.1.1.jar:3.1.1]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.obtainFromSupplier(AbstractAutowireCapableBeanFactory.java:1249) ~[spring-beans-5.3.15.jar:5.3.15]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1191) ~[spring-beans-5.3.15.jar:5.3.15]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582) ~[spring-beans-5.3.15.jar:5.3.15]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.15.jar:5.3.15]
... 33 common frames omitted
2022-10-06 16:01:58.614 WARN [cloud-data,,] 24988 --- [ Thread-27] c.a.nacos.common.notify.NotifyCenter : [NotifyCenter] Start destroying Publisher
2022-10-06 16:01:58.614 WARN [cloud-data,,] 24988 --- [ Thread-27] c.a.nacos.common.notify.NotifyCenter : [NotifyCenter] Destruction of the end
Exception in thread "Thread-17" zipkin2.reporter.ClosedSenderException
at zipkin2.reporter.AsyncReporter$BoundedAsyncReporter.flush(AsyncReporter.java:265)
at org.springframework.cloud.sleuth.autoconfig.zipkin2.ZipkinAutoConfiguration$2.run(ZipkinAutoConfiguration.java:142)
(5) 原因
引入openfeign时报No Feign Client for loadBalancing defined. Did you forget to
include spring-cloud-starter-loadbalancer错误
原因:由于SpringCloud Feign高版本不使用Ribbon而是使用spring-cloud-loadbalancer,
所以需要引用spring-cloud-loadbalancer或者降版本、
解决方案在common工程加入此依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>
排除注册中心中的ribbon
<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>
12、整合Alibaba Cloud Feign超时配置
1)超时配置存在Ribbon(过时)
默认fegin客户端只等待一秒、但是服务端处理需要等待1秒中、导致fegin客户端不想等待了、
直接返回报错、为了避免这样的情况、有时候我们需要设置fegin客户端的超时时间
需要在消费者 yml加入超时配置
#设置fegin客户端超时时间(OpenFegin 默认ribbon)
ribbon:
#指的是建立连接所用的时间,适用于网络状态正常情况下、两端连接所用的时间
ReadTimeout: 5000
#指的是建立连接后从服务器读取到可用资源所用时间
ConnecTimeout: 5000
2)不存在Ribbon的超时配置(重点)
feign:
client:
config:
#服务名称
cloud-production:
# 连接超时时间
connectTimeout: 90000
# 请求处理超时时间
readTimeout: 90000
3)超时配置全局
可新增配置类来解决超时
@Bean
public Request.Options options(){
// Request.Options(int connectTimeoutMillis, int readTimeoutMillis)方法已经过时
return new Request.Options(10000,60000);
}
13、整合Alibaba Cloud Feign性能优化
全部服务都配置
1)介绍
Feign底层的客户端实现:
1、URLConnection:默认实现,不支持连接池
2、Apache HttpClient:支持连接池
3、OKHttp:支持连接池
因此优化feign主要包括:
1、使用连接池代替默认的URLConnection
2、日志级别,最好用basic或none
2)引入依赖
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
3) yml新增配置
feign:
client:
config:
default: # default 全局配置
loggerLevel: BASIC #日志级别,BASIC就是最基本的请求和响应信息
httpclient:
enabled: true # 支持httpClient的开关
max-connections: 200 #最大连接数
max-connections-per-route: 50 # 单个路径的最大连接数
14、整合Feign整合Alibaba Cloud sentinel
全部服务都配置----随便找个服务测试、具体可参数我的视频来做
1)YML新增配置
#开启fegin对sentinel支持
feign:
sentinel:
enabled: true
2)创建容错类
@Slf4j
@Component
public class FallbackFactoryService implements FallbackFactory<DataProductionFeignService> {
@Override
public DataProductionFeignService create(Throwable cause) {
log.error("服务异常。。。。。。。。。。。。。。。。。。。" + cause);
return new DataProductionFeignService() {
@Override
public String getProduction(String id) {
JSONObject data = new JSONObject();
data.put("code","414");
data.put("message","Fallback回滚");
return data.toJSONString();
}
};
}
}
3)创建Feign请求
@FeignClient(value = "cloud-production", fallbackFactory = FallbackFactoryService.class)
public interface DataProductionFeignService {
@GetMapping("/production/all/getMysql")
String getProduction(@RequestParam("id") String id);
}
15、整合Alibaba Cloud Feign整合日志
1)新增日志类
public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志级别为BASIC
}
}
2)新增日志配置
feign:
client:
config:
default: # 这里用default就是全局配置,如果是写服务名称,则是针对某个微服务的配置
loggerLevel: FULL # 日志级别
如果要全局生效
,将其放到启动类的@EnableFeignClients这个注解中
@EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class)
局部生效
feign:
client:
config:
userservice: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
如果是局部生效,则把它放到对应的@FeignClient这个注解中
:
@FeignClient(value = “userservice”, configuration = DefaultFeignConfiguration .class)
3)高级配置法
logging:
level:
com.cloud.api.data.feign.DataProductionFeignService: debug #扫描的是你那个service的类全类名
4)各个服务模块新增
都需要配置同样的配置和日志类
16、整合Alibaba Cloud Feign重试机制
给各个服务模块配置重试机制
当feign调用返回HTTP报文时,会触发这个方法,方法内可以获得HTTP状态码,可以用来定制一些处理逻辑等等。
/** * @summary fegin 客户端的自定义配置 */
@Slf4j
public class MyConfiguration {
/** * 自定义重试机制 * @return */
@Bean
public Retryer feignRetryer() {
//最大请求次数为5,初始间隔时间为100ms,下次间隔时间1.5倍递增,重试间最大间隔时间为1s,
return new Retryer.Default();
}
@Bean
public ErrorDecoder feignError() {
return (key, response) -> {
if (response.status() == 400) {
log.error("请求xxx服务400参数错误,返回:{}", response.body());
}
if (response.status() == 409) {
log.error("请求xxx服务409异常,返回:{}", response.body());
}
if (response.status() == 404) {
log.error("请求xxx服务404异常,返回:{}", response.body());
}
// 其他异常交给Default去解码处理
// 这里使用单例即可,Default不用每次都去new
return new ErrorDecoder.Default().decode(key, response);
};
}
}
17、整合优化Alibaba Cloud Feign压缩
gzip是一种数据格式
,采用deflate算法压缩数据。当Gzip压缩到一个纯文本数据时,可以减少70%以上的数据大小。
gzip作用
:网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。
只配置Feign请求-应答的GZIP压缩
1)Feign压缩配置
给各个服务模块配置feign压缩
feign:
#Feign 压缩数据
compression:
request:
enabled: true
# 配置压缩的类型
mime-types: text/xml,application/xml,application/json
# 最小压缩值
min-request-size: 2048
response:
enabled: true
2)Springboot开启压缩
给各个服务模块配置Springboot压缩
server:
compression:
min-response-size: 512
mime-types: application/json,application/xml,text/html,text/xml,text/plain
excluded-user-agents: gozilla,traviata
enabled: true
application.properties配置形式
# spring boot gzip
# 开启spring boot中的gzip压缩。就是针对和当前应用所有相关的http请求-应答的gzip压缩。
server.compression.enabled=true
# 哪些客户端发出的请求不压缩,默认是不限制
server.compression.excluded-user-agents=gozilla,traviata
# 配置想压缩的请求/应答数据类型,默认是 text/html,text/xml,text/plain
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain
# 执行压缩的阈值,默认为2048
server.compression.min-response-size=512
18、移Feign配置到Alibaba Cloud Nacos中心
1)把feign压缩迁移Nacos
具体看我的视频
屏蔽Yml的配置
2)把SpringBoot压缩迁移Nacos
具体看我的视频
屏蔽Yml的配置
19、整合Alibaba Cloud OSS服务
1)导入OSS依赖
给party图片服务加入如下依赖
<properties>
<oss.version>2.2.0.RELEASE</oss.version>
</properties>
<!--com.alibaba.cloud-OSS-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>${
oss.version}</version>
</dependency>
2)导入到cloud_common工具类
1)导入转换Base64工具类
package com.api.common.utils.img;
import org.springframework.web.multipart.MultipartFile;
import sun.misc.BASE64Decoder;
import java.io.*;
/** * base64图片转为MultipartFile * 类 名 称:BASE64DecodedMultipartFile * 类 描 述:base64转MultipartFile */
public class BASE64DecodedMultipartFile implements MultipartFile {
private final byte[] imgContent;
private final String header;
public BASE64DecodedMultipartFile(byte[] imgContent, String header) {
this.imgContent = imgContent;
this.header = header.split(";")[0];
}
@Override
public String getName() {
// TODO - implementation depends on your requirements
return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
}
@Override
public String getOriginalFilename() {
// TODO - implementation depends on your requirements
return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1];
}
@Override
public String getContentType() {
// TODO - implementation depends on your requirements
return header.split(":")[1];
}
@Override
public boolean isEmpty() {
return imgContent == null || imgContent.length == 0;
}
@Override
public long getSize() {
return imgContent.length;
}
@Override
public byte[] getBytes() throws IOException {
return imgContent;
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(imgContent);
}
@Override
public void transferTo(File dest) throws IOException, IllegalStateException {
new FileOutputStream(dest).write(imgContent);
}
/** * base64转MultipartFile文件 * * @param base64 * @return */
public static MultipartFile base64ToMultipart(String base64) {
try {
String[] baseStrs = base64.split(",");
BASE64Decoder decoder = new BASE64Decoder();
byte[] b = new byte[0];
b = decoder.decodeBuffer(baseStrs[1]);
for (int i = 0; i < b.length; ++i) {
if (b[i] < 0) {
b[i] += 256;
}
}
return new BASE64DecodedMultipartFile(b, baseStrs[0]);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
2)状态码工具类
package com.cloud.api.common.utils;
public enum BizCodeEnume {
BD_BASE64_TYPE(200, "BASE64"), //百度Base64 类型
BD_URL_TYPE(200, "URL"), //通用URL格式图片
KS_IMG_HTTPS(200, "https"),//矿视 Base64图片类型
KS_IMG_TYPE(200, "image_base64"),//矿视 Base64图片类型
TO_MANY_REQUEST(10002, "请求流量过大"),
UNKNOW_EXCEPTION(10000, "系统未知异常"),
VAILD_EXCEPTION(10001, "参数格式校验失败"),
SMS_EXCEPTION(10002, "验证码获取频率太高,稍后再试"),
PRODUCT_UP_EXCEPTION(11000, "商品商家异常"),
USER_EXIT_EXCEPTION(15001, "用户存在"),
PHONE_EXIT_EXCEPTION(15002, "手机号存在"),
NO_STOCK_EXCEPTION(21000, "商品库存不足"),
BASE64_UTILS(001, "BASE64"),
URL_UTILS(002, "URL"),
MultiParTile_UTILS(003, "MultiParTile"),
ALI_BUCKET(004, "api-uexpo");
private int code;
private String msg;
BizCodeEnume(int code, String msg) {
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public String getMsg() {
return msg;
}
}
3)封装返回结果
package com.cloud.api.common.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.apache.http.HttpStatus;
import java.util.HashMap;
import java.util.Map;
/** * 返回数据 * * @author Mark sunlightcs@gmail.com */
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public <T> T getData(String key, TypeReference<T> typeReference){
Object data = get(key);
String s = JSON.toJSONString(data);
T t = JSON.parseObject(s, typeReference);
return t;
}
public R() {
put("code", 200);
put("msg", "success");
}
public static long getSerialVersionUID() {
return serialVersionUID;
}
public static R error() {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok(Object data) {
R r = new R();
r.put("data", data);
return r;
}
public static R ok() {
return new R();
}
public <T> T getDta(TypeReference<T> typeReference) {
Object data = get("data"); //默认是map
String s = JSON.toJSONString(data);
T t = JSON.parseObject(s, typeReference);
return t;
}
public R setDta(Object data) {
put("data", data);
return this;
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
public Integer getCode() {
return (Integer) this.get("code");
}
}
4)自定义异常
package com.cloud.api.common.utils;
/** * 自定义异常 * * @author Mark sunlightcs@gmail.com */
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg) {
super(msg);
this.msg = msg;
}
public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
3)整合Alibaba 0SS图片上传
(1)创建Controller
package com.cloud.api.party.controller;
import com.aliyun.oss.OSSClient;
import com.cloud.api.common.utils.R;
import com.cloud.api.party.service.ImgService;
import com.cloud.api.party.utils.OSSEntity;
import com.cloud.api.party.utils.ToImages;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/** * @Author 小坏 * @Date 2022/08/29 14:44 * @Version 1.0 * @program: 图片上传服务 */
@RestController
@RequestMapping("party/oss")
public class OSSController {
@Autowired
private ImgService imgService;
/** * @param toImages * @return */
@PostMapping("toImages")
public R toImages(@RequestBody ToImages toImages) {
return imgService.toImages(toImages);
}
/** * 图片文件流转换base64 * * @param file * @return */
@PostMapping("upLoad")
public R toImages(@RequestParam("file") MultipartFile file) throws IOException {
return R.ok();
}
/** * 阿里云文件图片上传 * * @param file * @return */
@PostMapping("toFilePutLoad")
public R toFilePutLoad(@RequestParam("file") MultipartFile file) {
return imgService.toFilePutLoad(file);
}
/** * 阿里云BASE64图片上传 * * @return */
@PostMapping("toBasePutLoad")
public R toBasePutLoad(@RequestBody OSSEntity os) {
return imgService.toBasePutLoad(os);
}
}
(2)创建Service
package com.cloud.api.party.service;
import com.cloud.api.common.utils.R;
import com.cloud.api.party.utils.OSSEntity;
import com.cloud.api.party.utils.ToImages;
import org.springframework.web.multipart.MultipartFile;
public interface ImgService {
R toImages(ToImages toImages);
R toFilePutLoad(MultipartFile file);
R toBasePutLoad(OSSEntity oss);
}
(3)创建实现类
package com.cloud.api.party.service.impl;
import com.aliyun.oss.OSSClient;
import com.cloud.api.common.utils.BizCodeEnume;
import com.cloud.api.common.utils.R;
import com.cloud.api.party.service.ImgService;
import com.cloud.api.party.utils.OSSEntity;
import com.cloud.api.party.utils.OSSUtils;
import com.cloud.api.party.utils.ToImages;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.HashMap;
/** * @Author 小坏 * @Date 2022/08/29 14:44 * @Version 1.0 * @program: 图片统一转换 */
@Service
public class ImgServiceImpl implements ImgService {
@Resource
private OSSClient ossClient;
@Override
public R toImages(ToImages toImages) {
return R.ok();
}
@Override
public R toFilePutLoad(MultipartFile file) {
OSSEntity ossEntity = OSSUtils.build().putOSS(file);
HashMap<String, Object> map = getStringObjectHashMap(ossEntity);
return R.ok().setDta(map);
}
@Override
public R toBasePutLoad(OSSEntity os) {
OSSEntity ossEntity = OSSUtils.build().putOSS(os.getImage());
HashMap<String, Object> map = getStringObjectHashMap(ossEntity);
return R.ok().setDta(map);
}
private HashMap<String, Object> getStringObjectHashMap(OSSEntity ossEntity) {
ossClient.putObject(BizCodeEnume.ALI_BUCKET.getMsg(),
ossEntity.getFilename(),
ossEntity.getInputStream(),
ossEntity.getObjectMetadata());
String url = ossEntity.getUrl().concat(ossEntity.getFilename());
HashMap<String, Object> map = new HashMap<>();
map.put("url", url);
return map;
}
}
(4)创建图片使用的工具
@Data
public class OSSEntity {
private String image;
private String filename;
private InputStream inputStream;
private ObjectMetadata objectMetadata;
private String url;
}
package com.cloud.api.party.utils;
import com.aliyun.oss.model.ObjectMetadata;
import com.cloud.api.common.utils.BASE64DecodedMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
public class OSSUtils {
private final static String bucketName = "https://alibaba-api.oss-cn-shanghai.aliyuncs.com/";
/** * 文件流上传阿里云 * * @param file * @return */
public OSSEntity putOSS(MultipartFile file) {
return putLoadOSS(file);
}
/** * base64上传阿里云 * * @param base64 * @return */
public OSSEntity putOSS(String base64) {
String base = "data:image/jpg;base64,/".concat(base64);
MultipartFile file = BASE64DecodedMultipartFile.base64ToMultipart(base);
return putLoadOSS(file);
}
/** * base64上传阿里云 * @param file * @return */
private OSSEntity putLoadOSS(MultipartFile file) {
ObjectMetadata objectMetadata = new ObjectMetadata();
//获取上传文件的扩展名,截取扩展名
//设置文本类型
objectMetadata.setContentType("image/jpg");
InputStream inputStream = null;
try {
inputStream = file.getInputStream();
} catch (IOException e) {
e.printStackTrace();
}
//获取上传的文件的名字
String filename = file.getOriginalFilename();
//随机uuid是为了拼接文件名,防止用户上传两个名字相同的文件后覆盖掉前一个
UUID uuid = UUID.randomUUID();
//这里是为了按上传时间分配目录。精确到月
String date = new SimpleDateFormat("yyyy/MM/").format(new Date());
//拼接成完整的文件名。
filename = date.concat(uuid.toString()).concat(filename);
OSSEntity oss = new OSSEntity();
oss.setFilename(filename);
oss.setInputStream(inputStream);
oss.setObjectMetadata(objectMetadata);
oss.setUrl(bucketName);
return oss;
}
public static OSSUtils build() {
return new OSSUtils();
}
}
@Data
public class ToImages {
private String type;
private String images;
private MultipartFile multipartFile;
}
(5)配置OSS YML文件
spring:
cloud:
# 阿里云Alibaba-OSS
alicloud:
secret-key: 自己的
access-key: 自己
oss:
endpoint: 自己
改成自己的OSS块
(6)项目效果图
(7)项目效果图
20、整合Alibaba Cloud SMS 短信服务
1)新增依赖
<properties>
<sms.version>2.2.0.RELEASE</sms.version>
</properties>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-sms</artifactId>
<version>${
sms.version}</version>
</dependency>
短信发送用到redis
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
2)配置YML
spring:
cloud:
# 阿里云Alibaba-OSS
alicloud:
secret-key: 自己的 ---需要看我视频配置
access-key: 自己的---需要看我视频配置
oss:
endpoint: 自己的---需要看我视频配置
redis:
host: cloud.api.com
port: 6379
password: 123456
# 指定数据库 默认是0
database: 0
timeout: 5000
3)创建短信controller
package com.api.auth.controller;
import com.api.auth.service.SendSmsService;
import com.api.auth.vo.SendCodeVo;
import com.api.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/** * @Author 小坏 * @Date 2022/08/29 14:44 * @Version 1.0 * @program: 普通登录 */
@RestController
@RequestMapping("/auth/login")
public class AuthLoginController {
@Autowired
private SendSmsService sendSmsService;
@GetMapping("sendMail")
public void sendMail() {
System.out.println("邮箱");
}
/** * 阿里云获取验证码 * @param phone * @return */
@GetMapping("sendCode")
public R sendCode(@RequestParam("phone") String phone) {
return R.ok(sendSmsService.sendCheckCode(phone));
}
/** * 验证验证码 * @param vo * @return */
@PostMapping("sendCheckPhoneCode")
public R sendCheckPhoneCode(@RequestBody SendCodeVo vo) {
return R.ok(sendSmsService.sendCheckPhoneCode(vo));
}
}
4)创建短信Service
package com.api.auth.service;
import com.api.auth.vo.SendCodeVo;
import com.api.common.utils.R;
public interface SendSmsService {
//获取验证码
R sendCheckCode(String phone);
//验证验证码
R sendCheckPhoneCode(SendCodeVo vo);
}
5)创建短信Service
package com.cloud.api.party.service.impl;
import com.alibaba.alicloud.sms.ISmsService;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.exceptions.ClientException;
import com.cloud.api.common.result.R;
import com.cloud.api.common.utils.AuthServerConstant;
import com.cloud.api.common.utils.BizCodeEnume;
import com.cloud.api.common.utils.UUIDGenerator;
import com.cloud.api.party.service.SendSmsService;
import com.cloud.api.party.utils.SendCodeVo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import java.util.concurrent.TimeUnit;
/** * @Author 小坏 * @Date 2022/08/29 14:44 * @Version 1.0 * @program: 阿里云验证码封装 */
@Service
public class SendSmsServiceImpl implements SendSmsService {
@Value("${spring.cloud.alicloud.sms.code}")
private String springAliSmsCode;
@Autowired
private ISmsService smsService;
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Override
public R sendCheckCode(String phone) {
//接口防刷
//先验证redis是否有缓存验证码
String redisCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone);
System.out.println(redisCode);
//如果命中缓存走
if (!StringUtils.isEmpty(redisCode)) {
long l = Long.parseLong(redisCode.split("_")[1]);
if (System.currentTimeMillis() - l < 60000) {
return R.error(BizCodeEnume.SMS_EXCEPTION.getCode(), BizCodeEnume.SMS_EXCEPTION.getMsg());
}
}
//防止同一个phone在60秒内再次发送验证码
String code = UUIDGenerator.MobileVfCode();
String currentTime = code + "_" + System.currentTimeMillis();
//防止同一个phone在60秒内再次发送验证码
redisTemplate.opsForValue().set(AuthServerConstant.SMS_CODE_CACHE_PREFIX + phone, currentTime, 10, TimeUnit.MINUTES);
//调用发送短信服务
R r = sendCheckCode(phone, code);
if (r.getCode() == 200) {
return R.ok("发送成功!");
}
return R.error(BizCodeEnume.SMS_EXCEPTION.getCode(), BizCodeEnume.SMS_EXCEPTION.getMsg());
}
/** * 验证码登录对比 * * @param vo * @return */
@Override
public R sendCheckPhoneCode(SendCodeVo vo) {
//1、校验验证码
//从redis中获取
String code = vo.getCode();
String b = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
//如果命中缓存
if (!StringUtils.isEmpty(b)) {
//就把获取的code和redis中做对比
if (code.equals(b.split("_")[0])) {
//删除验证码
redisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + vo.getPhone());
//验证码通过 //真正注册。调用远程服务进行注册/或者本地注册逻辑
return R.ok("验证码对比成功!");
} else {
//验证不通过
return R.error("验证码超时!");
}
} else {
//如果等于null、就是没有查到
return R.error("验证码错误!");
}
}
public R sendCheckCode(String phone, String code) {
SendSmsRequest request = new SendSmsRequest();
// Required:the mobile number 接收短信的号码
request.setPhoneNumbers(phone);
// Required:SMS-SignName-could be found in sms console 签名
request.setSignName("有铂科技");
// Required:Template-could be found in sms console 模板
request.setTemplateCode(springAliSmsCode);
// Required:The param of sms template.For exmaple, if the template is "Hello,your verification code is ${code}". The param should be like following value
request.setTemplateParam("{\"code\":\"" + code + "\"}");
SendSmsResponse sendSmsResponse = null;
try {
sendSmsResponse = smsService.sendSmsRequest(request);
} catch (ClientException e) {
e.printStackTrace();
sendSmsResponse = new SendSmsResponse();
}
if (sendSmsResponse.getCode().equals("OK")) {
return R.ok(code);
}
if (sendSmsResponse.getCode().equals("isv.BUSINESS_LIMIT_CONTROL")) {
return R.error("aliyun限流!");
}
return R.error("不存在");
}
}
6)创建短信对象
@Data
public class SendCodeVo {
private String phone;
private String code;
}
7)创建随机数
package com.api.common.http;
import java.net.InetAddress;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Random;
import java.util.Set;
public class UUIDGenerator {
/** * 产生一个32位的UUID * * @return */
public static String generate() {
return new StringBuilder(32).append(format(getIP())).append(
format(getJVM())).append(format(getHiTime())).append(
format(getLoTime())).append(format(getCount())).toString();
}
private static final int IP;
static {
int ipadd;
try {
ipadd = toInt(InetAddress.getLocalHost().getAddress());
} catch (Exception e) {
ipadd = 0;
}
IP = ipadd;
}
private static short counter = (short) 0;
private static final int JVM = (int) (System.currentTimeMillis() >>> 8);
private final static String format(int intval) {
String formatted = Integer.toHexString(intval);
StringBuilder buf = new StringBuilder("00000000");
buf.replace(8 - formatted.length(), 8, formatted);
return buf.toString();
}
private final static String format(short shortval) {
String formatted = Integer.toHexString(shortval);
StringBuilder buf = new StringBuilder("0000");
buf.replace(4 - formatted.length(), 4, formatted);
return buf.toString();
}
private final static int getJVM() {
return JVM;
}
private final static short getCount() {
synchronized (UUIDGenerator.class) {
if (counter < 0) {
counter = 0;
}
return counter++;
}
}
/** * Unique in a local network */
private final static int getIP() {
return IP;
}
/** * Unique down to millisecond */
private final static short getHiTime() {
return (short) (System.currentTimeMillis() >>> 32);
}
private final static int getLoTime() {
return (int) System.currentTimeMillis();
}
private final static int toInt(byte[] bytes) {
int result = 0;
for (int i = 0; i < 4; i++) {
result = (result << 8) - Byte.MIN_VALUE + (int) bytes[i];
}
return result;
}
public static String getNumber() {
Set<Integer> set = new HashSet<Integer>(); //定义一个set。
Random r = new Random(); //定义一个产生随机数的实体对象;
while (set.size() < 6) {
//产生6个:因为set是无序唯一的;
int r_number = r.nextInt(10);// 产生0到9的整型数据
set.add(r_number);
}
/** * 下面是遍历出产生的随机数 */
Iterator<Integer> it = set.iterator();//迭代器
String s1 = "P";
while (it.hasNext()) {
Integer u = it.next();
String s = String.valueOf(u);
s1 += s;
}
return s1;
}
private final static int OFFSET = 538309;
public static String MobileVfCode() {
long seed = System.currentTimeMillis() + OFFSET;
SecureRandom secureRandom = null; // 安全随机类
try {
secureRandom = SecureRandom.getInstance("SHA1PRNG");
secureRandom.setSeed(seed);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
String codeList = "1234567890"; // 验证码数字取值范围
String sRand = ""; // 定义一个验证码字符串变量
for (int i = 0; i < 6; i++) {
int code = secureRandom.nextInt(codeList.length() - 1); // 随即生成一个0-9之间的整数
String rand = codeList.substring(code, code + 1);
sRand += rand; // 将生成的随机数拼成一个六位数验证码
}
return sRand; // 返回一个六位随机数验证码
}
}
21、整合AlibabaCloud集成ELK收集日志
·此节搭建环境在上面、请参考我的视频·
1)创建日志文件
logback-spring.xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration debug="false" scan="true" scanPeriod="1 seconds">
<include resource="org/springframework/boot/logging/logback/base.xml" />
<contextName>logback</contextName>
<appender name="cloud_api" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<destination>cloud_api:5044</destination>
<!-- encoder必须配置,有多种可选 -->
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder" />
</appender>
<root level="info">
<appender-ref ref="cloud_api" />
</root>
</configuration>
2)依赖logstash日志
<!--集成logstash-->
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>5.3</version>
</dependency>
3)启动服务
4)创建ES索引
5)查看日志
6、所有微服务日志
22、ELK监控MYSQL
·此节搭建环境在上面、请参考我的视频·
1)服务器下载metricbeat监控文件
curl -L -O https://artifacts.elastic.co/downloads/beats/metricbeat/metricbeat-7.10.2-linux-x86_64.tar.gz
2)解压监控文件
tar xzvf metricbeat-7.10.2-linux-x86_64.tar.gz
3)修改配置文件metricbeat.yml
setup.template.settings:
# 因为我这里es是单节点,所以设置主分片数为1,副本分片数为0.否则会报黄
index.number_of_shards: 1
index.number_of_replicas: 0
output.elasticsearch:
# 你的es所在服务器ip
hosts: ["192.168.244.11:9200"]
username: "elastic"
password: "elastic"
setup.kibana:
# kibana所在服务器ip
host: "192.168.2.110:5601"
4)启动mysql模块
metricbeat会根据modules.d/mysql.yml中的配置项来获取系统数据
./metricbeat modules enable mysql
5)配置要采集的内容,修改modules.d/mysql.yml配置文件
vi modules.d/mysql.yml
配置文件内容,这里我们将
status、galera_status、performance
的指标都开启,具体可根据自己的需要进行配置
注意
:这里没有开启query指标集,这是因为query用于监控我们自定义查询语句的指标数据的,需要额外配置其他项并且需要自己构建看板,并不能拆箱即用,所以我们在以后单独介绍。如果直接开启query的话,会出现报错
- module: mysql
metricsets:
- status
- galera_status
- performance
# - query
period: 10s
hosts: ["root:123456@tcp(192.168.2.110:3306)/"]
这里的mysql配置也可以采取如下形式
hosts: ["tcp(127.0.0.1:3306)/"]
username: root
password: 123456
6)加载kibana仪表盘
./metricbeat setup
7、启动metricbeat
./metricbeat -e
8、这里可以在kibana的mysql指标部署流程
9、mysql指标仪表板
我们对数据库做一下查询、新增、修改等操作,创造一些数据,然后点击mysql指标仪表板(Metricbeat MySQL)
可以看到mysql的相关指标都显示出来了
23、整合AlibabaCloud全局异常
1)在common服务创建exception包
创建异常类
package com.cloud.api.common.exception;
public class CloudApiException extends RuntimeException {
private static final long serialVersionUID = 1L;
public CloudApiException(String message){
super(message);
}
public CloudApiException(Throwable cause)
{
super(cause);
}
public CloudApiException(String message, Throwable cause)
{
super(message,cause);
}
}
实现异常接口
package com.cloud.api.common.exception;
import com.alibaba.fastjson.JSONObject;
import com.cloud.api.common.result.R;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;
import java.util.Map;
/** * 异常处理器 * * @Author scott * @Date 2019 */
@RestControllerAdvice
public class CloudApiExceptionHandler {
/** * 处理自定义异常 * @param e * @return */
@ExceptionHandler(CloudApiException.class)
public R handleRRException(CloudApiException e) {
return R.error(e.getMessage());
}
@ExceptionHandler(NoHandlerFoundException.class)
public R handlerNoFoundException(Exception e) {
return R.error(404, "路径不存在,请检查路径是否正确");
}
/** * 全局异常 * @param e * @return */
@ExceptionHandler(Exception.class)
public R handleException(Exception e) {
StackTraceElement stackTraceElement = e.getStackTrace()[0];
JSONObject map = new JSONObject();
// map.put("类名:", stackTraceElement.getClassName());
map.put("class:", stackTraceElement.getFileName());
map.put("error:", e.toString());
map.put("methodName:", stackTraceElement.getMethodName());
map.put("errorLine:", stackTraceElement.getLineNumber());
Map<String, String> m = System.getenv();
String userName = m.get("USERNAME");// 获取用户名
System.out.println(userName);
if (userName == null) {
userName = "Linux";
}
//发送钉钉/邮箱
return R.error(map);
}
/** * 请求格式不对 * @param e * @return */
@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public R HttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
StringBuffer sb = new StringBuffer();
sb.append("不支持");
sb.append(e.getMethod());
sb.append("请求方法,");
sb.append("支持以下");
String[] methods = e.getSupportedMethods();
if (methods != null) {
for (String str : methods) {
sb.append(str);
sb.append("!");
}
}
return R.error(405, sb.toString());
}
/** * spring默认上传大小100MB 超出大小捕获异常MaxUploadSizeExceededException * @param e * @return */
@ExceptionHandler(MaxUploadSizeExceededException.class)
public R handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
return R.error("文件大小超出10MB限制, 请压缩或降低文件质量! ");
}
}
2)微服务增加扫包
各个微服务都增加扫包
@SpringBootApplication(scanBasePackages = "com.cloud.api")
24、AlibAbaCloud微服务负载均衡
1)复制微服务配置
2)配置副本微服务端口
3)生成副本
启动即可
4)测试效果
采用的轮询机制
25、整合AlibabaCloud全局日志注解
1)自定义注解
package com.cloud.api.common.log;
import java.lang.annotation.*;
/** * @Program: aop * @ClassName CloudApiAnnotation * @Description: 自定义系统操作注解 * @Author: liutao * @DateTime: 2022/10/5 2:32 * @Version: 1.0 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CloudApiAnnotation {
String operMoudle() default "";//操作模块
String operMethod() default "";//操作方法
String operDes() default "";//操作描述
}
2)封装AOP请求
package com.cloud.api.common.log;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.messaging.Source;
import org.springframework.integration.support.MessageBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
/** * @Program: aop * @ClassName SysLogger * @Description: aop日志具体实现 * @Author: liutao * @DateTime: 2022/6/5 2:38 * @Version: 1.0 */
//@EnableBinding(value = Source.class)
@Aspect
@Component
public class CloudApiLogger {
/** * spring cloud stream里面发消息通过 Source 发送 */
//@Autowired
//private Source source;
private CloudApiLog logs = new CloudApiLog();
private final Logger logger = LoggerFactory.getLogger(CloudApiLogger.class);
@Value("${spring.application.name}")
private String SpringApplicationName;
private ThreadLocal startTime = new ThreadLocal<Long>();
@Pointcut("@annotation(com.cloud.api.common.log.CloudApiAnnotation)")
public void operLoggerPointCut() {
logger.info("===============系统操作日志===============");
}
@Pointcut("execution(public * com.cloud.api.*.controller.*.*(..))")
public void controllerMethod() {
}
@Before("operLoggerPointCut()")
public void logBefore(JoinPoint joinPoint) {
startTime.set(System.currentTimeMillis());
Map<String, String> map = System.getenv();
String userName = map.get("USERNAME");// 获取// 用户名
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
StringBuilder requestLog = new StringBuilder();
Signature signature = joinPoint.getSignature();
Method method = ((MethodSignature) signature).getMethod();
CloudApiAnnotation sysAnnotation = method.getAnnotation(CloudApiAnnotation.class);//利用反射获取到自定义注解
// 打印请求内容
logger.info("===============请求内容开始===============");
logger.info("请求时间:" + new Date());
logger.info("开发电脑昵称:" + userName);
logs.setUserName(userName);
logger.info("服务模块:" + SpringApplicationName);
logs.setSpringApplicationName(SpringApplicationName);
logger.info("操作模块:" + sysAnnotation.operMoudle());
logs.setOperationModular(sysAnnotation.operMoudle());
logger.info("操作方法:" + sysAnnotation.operMethod());
logs.setOperationMethod(sysAnnotation.operMethod());
logger.info("操作描述:" + sysAnnotation.operDes());
logs.setOperationDes(sysAnnotation.operDes());
logger.info("请求地址:" + request.getRequestURL().toString());
logs.setRequestURL(request.getRequestURL().toString());
logger.info("请求IP:" + request.getRemoteAddr());
logs.setRequestIp(request.getRemoteAddr());
logger.info("请求方式:" + request.getMethod());
logs.setRequestMethod(request.getMethod());
logger.info("请求类方法:" + joinPoint.getSignature());
logs.setRequestSignature(joinPoint.getSignature().toString());
logger.info("请求类方法参数值:" + Arrays.toString(joinPoint.getArgs()));
// 处理请求参数
String[] paramNames = ((MethodSignature) signature).getParameterNames();
Object[] paramValues = joinPoint.getArgs();
int paramLength = null == paramNames ? 0 : paramNames.length;
if (paramLength == 0) {
requestLog.append(" {} ");
} else {
requestLog.append(" {");
for (int i = 0; i < paramLength - 1; i++) {
requestLog.append(paramNames[i]).append("=").append(JSONObject.toJSONString(paramValues[i])).append(",");
}
requestLog.append(paramNames[paramLength - 1]).append("=").append(JSONObject.toJSONString(paramValues[paramLength - 1])).append("}");
}
logger.info("请求参数明细:" + requestLog.toString());
logs.setRequestArgs(requestLog.toString());
logger.info("===============请求内容结束===============");
}
@AfterReturning(returning = "o", pointcut = "operLoggerPointCut()")
public void logResultVOInfo(Object o) {
long l = System.currentTimeMillis() - (long) startTime.get();
System.out.println((long) startTime.get());
System.out.println(System.currentTimeMillis());
logger.info("--------------返回内容开始----------------");
logger.info("Response内容:" + JSON.toJSONString(o));
logs.setResult(o.toString());
logger.info("--------------返回内容结束----------------");
logger.info("--------------操作耗时----------------");
logger.info(": " + l);
logs.setRequestTime(l);
// boolean send = source.output().send(MessageBuilder.withPayload(JSONObject.toJSONString(logs)).build());
// System.out.println(send);
}
@AfterThrowing(pointcut = "controllerMethod()", throwing = "ex")
public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
String methodName = joinPoint.getSignature().getName();
List<Object> args = Arrays.asList(joinPoint.getArgs());
System.out.println("连接点方法为:" + methodName + ",参数为:" + args + ",异常为:" + ex);
}
}
3)新增日志对象
package com.cloud.api.common.log;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.io.Serializable;
import java.util.Date;
public class CloudApiLog implements Serializable {
@JsonFormat(pattern = "yyyy.MM.dd",timezone = "GMT+8")
private Date createTime;
private String userName;
private String springApplicationName;
private String operationModular;
private String operationMethod;
private String operationDes;
private String requestURL;
private String requestIp;
private String requestMethod;
private String requestSignature;
private String requestArgs;
private String result;
private Long requestTime;
public String getResult() {
return result;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setSpringApplicationName(String springApplicationName) {
this.springApplicationName = springApplicationName;
}
public void setOperationModular(String operationModular) {
this.operationModular = operationModular;
}
public void setOperationMethod(String operationMethod) {
this.operationMethod = operationMethod;
}
public void setOperationDes(String operationDes) {
this.operationDes = operationDes;
}
public void setRequestURL(String requestURL) {
this.requestURL = requestURL;
}
public void setRequestIp(String requestIp) {
this.requestIp = requestIp;
}
public void setRequestMethod(String requestMethod) {
this.requestMethod = requestMethod;
}
public void setRequestSignature(String requestSignature) {
this.requestSignature = requestSignature;
}
public void setRequestArgs(String requestArgs) {
this.requestArgs = requestArgs;
}
public void setResult(String result) {
this.result = result;
}
public void setRequestTime(Long requestTime) {
this.requestTime = requestTime;
}
}
4)记录日志注解
方法上自定义
@CloudApiAnnotation(operMoudle = "测试接口",operMethod="getName", operDes = "测试")
26、整合AlibabaCloud RocketMQ消息队列生产
1)网站
https://github.com/alibaba/spring-cloud-alibaba/wiki/RocketMQ-en
2)采用流式依赖
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-stream-rocketmq</artifactId>
</dependency>
3、整合common服务生产
(1)绑定发送
在日志类编码
@EnableBinding(value = Source.class)
(2)注入bean
@Autowired
private Source source;
(3)发送消息
boolean send = source.output().send(MessageBuilder.withPayload(JSONObject
.toJSONString(logs)).build());
(4)需要记录日志服务配置
spring:
#注册中心
cloud:
stream:
#RocketMQ 通用配置
rocketmq:
binder:
name-server: cloud.api.com:9876
# 不加, 会报错:Property 'group' is required - producerGroup
group: rocketmq-group
#bindings 具体生产消息、消费消息的桥梁
bindings:
#Produce Config
output: # 查看org.springframework.cloud.stream.config.BindingProperties
destination: log-topic #指定发送的topic
contentType: application/json #默认是application/json
group: log-group
27、新增AlibabaCloud RocketMQ日志服务消费
1)创建log日志服务
2)配置POM依赖
<dependencies>
<dependency>
<artifactId>cloud_common</artifactId>
<groupId>com.cloud.api</groupId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<!--2021毕业版本依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.6.3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2021.0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3)配置YML
spring:
#注册中心
cloud:
nacos:
server-addr: cloud.api.com:8848
discovery:
namespace: d4dc3568-39bc-4258-83bb-a88c56fa9321
group: dev
#配置中心
config:
server-addr: cloud.api.com:8848
group: dev
file-extension: yaml
namespace: d4dc3568-39bc-4258-83bb-a88c56fa9321
stream:
#RocketMQ 通用配置
rocketmq:
binder:
#客户端接入点,必填 rocketMQ的连接地址,binder高度抽象
name-server: cloud.api.com:9876
# 不加, 会报错:Property 'group' is required - producerGroup
group: rocketmq-group
#bindings 具体生产消息、消费消息的桥梁
bindings:
#Consumer Config
input:
destination: log-topic
contentType: application/json #默认是application/json
group: log-group
4)监听消费日志消息
package com.cloud.api.log.controller;
import com.alibaba.fastjson.JSONObject;
import com.cloud.api.log.entity.CloudApiLogEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.annotation.EnableBinding;
import org.springframework.cloud.stream.annotation.StreamListener;
import org.springframework.cloud.stream.messaging.Sink;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.messaging.Message;
import java.io.UnsupportedEncodingException;
import java.util.Date;
@EnableBinding(value = {
Sink.class})
public class ReceiveService {
/** * spring cloud stream里面通过 Sink 接收消息 */
@Autowired
private MongoTemplate mongoTemplate;
@StreamListener(value = Sink.INPUT)
public void listener(Message<byte[]> message) throws UnsupportedEncodingException {
System.out.println("headers:" + message.getHeaders());
byte[] payload = message.getPayload();
String s = new String(payload, "utf-8");
CloudApiLogEntity cloudApiLog = JSONObject.parseObject(s, CloudApiLogEntity.class);
System.out.println("接收到的消息:" + new String(payload, "utf-8"));
cloudApiLog.setCreateTime(new Date());
CloudApiLogEntity insert = mongoTemplate.insert(cloudApiLog);
System.out.println("...."+insert);
System.out.println(cloudApiLog);
}
}
28、监听RocketMQ操作日志到MongoDB
1)配置依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2)配置mongodb链接
data:
mongodb:
uri: mongodb://root:root@cloud.api.com:27017/cloud-api-log??authSource=admin&authMechanism=SCRAM-SHA-1
3)注入Mongodb的模板
调用新增即可
4)新增表
package com.cloud.api.log.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
import java.io.Serializable;
import java.util.Date;
@Data
@Document(collection = "cloud-api-log") //指定要对应的文档名(表名)
public class CloudApiLogEntity implements Serializable {
/*** 自定义mongo主键 加此注解可自定义主键类型以及自定义自增规则 * 若不加 插入数据数会默认生成 ObjectId 类型的_id 字段 * org.springframework.data.annotation.Id 包下 * mongo库主键字段还是为_id (本文实体类中字段为为id,意思查询字段为_id,但查询结果_id会映射到实体对象id字段中) */
@Id
private String id;
@JsonFormat(locale = "zh", timezone = "Asia/Shanghai", pattern = "yyyy-MM-dd HH:mm:ss")
@Field("createTime")
private Date createTime;
private String userName;
private String springApplicationName;
private String operationModular;
private String operationMethod;
private String operationDes;
private String requestURL;
private String requestIp;
private String requestMethod;
private String requestSignature;
private String requestArgs;
private String result;
private String requestTime;
}
5)效果展示
29、全部服务RockMQ配置迁移Nacos
1)配置中心服务依赖
为每一个服务新增日志依赖依赖迁移到Nacos
spring:
#注册中心
cloud:
stream:
#RocketMQ 通用配置
rocketmq:
binder:
name-server: cloud.api.com:9876
# 不加, 会报错:Property 'group' is required - producerGroup
group: rocketmq-group
#bindings 具体生产消息、消费消息的桥梁
bindings:
#Produce Config
output: # 查看org.springframework.cloud.stream.config.BindingProperties
destination: log-topic #指定发送的topic
contentType: application/json #默认是application/json
group: log-group
2)新增扫包
@SpringBootApplication(scanBasePackages = "com.cloud.api")
30、Nacos配置中心共享YML
1)新增共享配置文件
什么是共享配置、重复、一致的配置文件
user:
name: aaa
spring:
#注册中心
cloud:
# 限流
sentinel:
transport:
dashboard: cloud.api.com:8080
sleuth:
web:
client:
# 开启采集链路
enabled: true
sampler:
# 默认采集是 0.1(百分之十),生产环境采用默认,测试环境可以修改为1.0
probability: 1.0
# zipkin服务所在地址
zipkin:
base-url: http://cloud.api.com:9411/
discovery-client-enabled: false #让nacos把它当成一个URL,而不要当做服务名
# Springboot压缩算法
server:
compression:
min-response-size: 512
mime-types: application/json,application/xml,text/html,text/xml,text/plain
excluded-user-agents: gozilla,traviata
enabled: true
feign:
client:
config:
cloud-production: #服务名称
connectTimeout: 90000 #连接超时时间
readTimeout: 90000 #请求处理超时时间
#Feign 压缩数据
compression:
request:
enabled: true
# 配置压缩的类型
mime-types: text/xml,application/xml,application/json
# 最小压缩值
min-request-size: 2048
response:
enabled: true
#更改自带的连接池
httpclient:
enabled: true # 支持httpClient的开关
max-connections: 200 #最大连接数
max-connections-per-route: 50 # 单个路径的最大连接数
#开启fegin对sentinel支持
sentinel:
enabled: true
2)加入共享配置
spring:
#注册中心
cloud:
nacos:
server-addr: cloud.api.com:8848
discovery:
namespace: d4dc3568-39bc-4258-83bb-a88c56fa9321
group: dev
#配置中心
config:
server-addr: cloud.api.com:8848
group: dev
file-extension: yaml
namespace: d4dc3568-39bc-4258-83bb-a88c56fa9321
# 共享配置
shared-configs:
- data-id: application-dev.yaml
group: dev
31、配置BootAdmin权限登录监控
1)增加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2)增加权限配置类
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {
private final String adminContextPath;
public SecuritySecureConfig(AdminServerProperties adminServer) {
this.adminContextPath = adminServer.getContextPath();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler();
successHandler.setTargetUrlParameter("redirectTo");
successHandler.setDefaultTargetUrl(adminContextPath + "/");
http.authorizeRequests()
.antMatchers(adminContextPath + "/login",
adminContextPath + "/assets/**",
adminContextPath + "/manage/**",
adminContextPath + "/actuator/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().loginPage(adminContextPath + "/login").successHandler(successHandler)
.and()
.logout().logoutUrl(adminContextPath + "/logout")
.and()
.csrf().disable();
}
}
3)配置账户密码
spring:
security:
user:
name: admin
password: admin
32、CloudAlibaba整合报警配置
1)配置报警
@Component
public class AdminNotifier extends AbstractStatusChangeNotifier {
private static final Logger log = LoggerFactory.getLogger(AdminNotifier.class);
/** * 消息模板 */
private static final String template = "<<<%s>>> \n 【服务名】: %s(%s) \n 【状态】: %s(%s) \n 【服务ip】: %s \n 【详情】: %s";
private String titleAlarm = "系统告警";
private String titleNotice = "系统通知";
private String[] ignoreChanges = new String[]{
"UNKNOWN:UP","DOWN:UP","OFFLINE:UP"};
public AdminNotifier(InstanceRepository repository) {
super(repository);
}
@Override
protected boolean shouldNotify(InstanceEvent event, Instance instance) {
if (!(event instanceof InstanceStatusChangedEvent)) {
return false;
} else {
InstanceStatusChangedEvent statusChange = (InstanceStatusChangedEvent)event;
String from = this.getLastStatus(event.getInstance());
String to = statusChange.getStatusInfo().getStatus();
return Arrays.binarySearch(this.ignoreChanges, from + ":" + to) < 0 && Arrays.binarySearch(this.ignoreChanges, "*:" + to) < 0 && Arrays.binarySearch(this.ignoreChanges, from + ":*") < 0;
}
}
@Override
protected Mono<Void> doNotify(InstanceEvent event, Instance instance) {
return Mono.fromRunnable(() -> {
if (event instanceof InstanceStatusChangedEvent) {
log.info("Instance {} ({}) is {}", instance.getRegistration().getName(),
event.getInstance(),
((InstanceStatusChangedEvent) event).getStatusInfo().getStatus());
String status = ((InstanceStatusChangedEvent) event).getStatusInfo().getStatus();
String messageText = null;
switch (status) {
// 健康检查没通过
case "DOWN":
log.info("发送 健康检查没通过 的通知!");
messageText = String
.format(template,titleAlarm, instance.getRegistration().getName(), event.getInstance(),
((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "健康检查没通过通知",
instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
log.info(messageText);
break;
// 服务离线
case "OFFLINE":
log.info("发送 服务离线 的通知!");
messageText = String
.format(template,titleAlarm, instance.getRegistration().getName(), event.getInstance(),
((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服务离线通知",
instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
log.info(messageText);
break;
//服务上线
case "UP":
log.info("发送 服务上线 的通知!");
messageText = String
.format(template,titleNotice, instance.getRegistration().getName(), event.getInstance(),
((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服务上线通知",
instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
log.info(messageText);
break;
// 服务未知异常
case "UNKNOWN":
log.info("发送 服务未知异常 的通知!");
messageText = String
.format(template,titleAlarm, instance.getRegistration().getName(), event.getInstance(),
((InstanceStatusChangedEvent) event).getStatusInfo().getStatus(), "服务未知异常通知",
instance.getRegistration().getServiceUrl(), JSONObject.toJSONString(instance.getStatusInfo().getDetails()));
log.info(messageText);
break;
default:
break;
}
} else {
log.info("Instance {} ({}) {}", instance.getRegistration().getName(), event.getInstance(),
event.getType());
}
});
}
}
2)邮箱报警整合
(1)整合邮箱依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
(2)配置邮箱信息
# 邮件配置
spring.mail.host=smtp.qq.com
spring.mail.port=465
# 邮件发送人
spring.mail.username=1477227147@qq.com
# 授权码
spring.mail.password=ypqpgrqjojlnheef
spring.mail.default-encoding=utf-8
spring.mail.properties.mail.smtp.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.debug=true
spring.mail.protocol=smtp
spring.mail.properties.mail.smtp.auth=true
spring.mail.properties.mail.smtp.ssl.enable=true
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.test-connection=true
# 邮件发送人
spring.boot.admin.notify.mail.from=1477227147@qq.com
# 邮件接收人
spring.boot.admin.notify.mail.to=1477227147@qq.com
# 忽略什么情况才不发邮件,不填代表有变化都会发邮件
spring.boot.admin.notify.discord.ignore-changes=
(3)编写发送实现类代码
package com.cloud.api.admin.service.impl;
import com.cloud.api.admin.service.SendMailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class SendMailServiceImpl implements SendMailService {
@Autowired
private JavaMailSender javaMailSender;
//发送人
private String from = "1477227147@qq.com";
//接收人
private String to = "1477227147@qq.com";
//标题
private String subject = "cloud_api服务报警";
//正文
private String context = "测试邮件正文内容";
@Override
public void sendMail() {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from+"(小甜甜)");
message.setTo(to);
message.setSubject(subject);
message.setText(context);
javaMailSender.send(message);
}
}
(5)编写实现类
package com.cloud.api.admin.service;
public interface SendMailService {
public void sendMail();
}
(6)编写发送邮箱控制器
package com.cloud.api.admin.controller;
import com.cloud.api.admin.service.SendMailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/admin/mail")
public class SendMailController {
@Autowired
private SendMailService sendMailService;
@GetMapping("/sendMail")
public void SendMail() {
sendMailService.sendMail();
}
}
四、AlibabaCloud微服务中级篇下鉴权
1、Sa-Token权限鉴权demo
加群领取
2)SpringSecurty权限认证demo
加群领取
五、AlibabaCloud微服高级篇章业务模型
具体看我的视频
1)微信APP统一登录
(1)微信网地址
https://open.weixin.qq.com/
(2)注册账户
(3)创建应用
(4)获取签名
https://open.weixin.qq.com/cgi-bin/showdocument?action=dir_list&t=resource/res_list&verify=1&id=open1419319167&token=&lang=zh_CN
(5)
等待审核通过
(6)整合uniapp获取授权
uni.getProvider({
service: 'oauth',
success: function(res) {
if (~res.provider.indexOf('weixin')) {
uni.login({
provider: 'weixin',
success: function(loginRes) {
// 获取用户信息
uni.getUserInfo({
provider: 'weixin',
success: function(infoRes) {
// console.log('-------获取微信用户所有-----');
// console.log(JSON.stringify(infoRes .userInfo));
// console.log('-------获取微信用户所有1-----');
api.sendLoign({
"openId": infoRes.userInfo.openId,
"nickName": infoRes.userInfo.nickName,
"gender": infoRes.userInfo.gender,
"avatarUrl": infoRes.userInfo.avatarUrl,
"unionId": infoRes.userInfo.unionId,
"country": infoRes.userInfo.country,
"province": infoRes.userInfo.province,
"city": infoRes.userInfo.city
}).then(res = >{
if (res.datas.openId) {
that.nickName = res.datas.nickName that.avatarUrl = res.datas.avatarUrl uni.setStorageSync('loign_status', res.datas.openId) uni.setStorageSync('loign_success', res.datas) uni.setStorageSync('radio', res.datas.radio) console.log(res)
} else {
console.log('66')
}
}).
catch(err = >{
console.log(err)
})
},
fail(e) {
uni.showToast({
icon: 'none',
// title: '登陆失败,请确保已安装或已登录微信',
title: res.errMsg,
duration: 2000
});
}
});
}
});
}
},
fail(e) {
uni.showToast({
icon: 'none',
// title: '登陆失败,请确保已安装或已登录微信',
title: "登陆失败,请确保已安装或已登录微信",
duration: 2000
});
}
});
2)QQ APP统一登陆
1、QQ授权申请网站
https://connect.qq.com/
2、创建应用
3、获取签名
4、整合QQAPP授权
uni.login({
provider: 'qq',
success: function (loginRes) {
// 登录成功
uni.getUserInfo({
provider: 'qq',
success: function(info) {
// 获取用户信息成功, info.authResult保存用户信息
console.log(info.authResult)
console.log(info)
console.log(loginRes)
}
})
},
fail: function (err) {
// 登录授权失败
// err.code是错误码
}
});
5、效果
获取到的数据
3)微信小程序登录
六、kubesphere高级运维云原生
1)安装依赖
yum install socat -y
yum install conntrack -y
yum install ebtables -y
yum install ipset -y
2)关闭分区
临时生效
echo 0 > /proc/sys/vm/swappiness
永久生效
vi /etc/sysctl.conf
vm.swappiness = 0
sysctl -p
关闭
swapoff -a &
关闭swap挂载
vi /etc/fstab
# /dev/mapper/cl-swap swap swap defaults 0 0
3)关闭防火墙
systemctl stop firewalld
systemctl disable firewalld
4、DNF解析
Ip Master1
Ip Node1
Ip Node2
5、使用脚本快速安装
6、启动脚本
请去看我的视频搭建、由于命令太多
7、开启可插拔组件
8、监控日志
kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l 'app in (ks-install, ks-installer)' -o jsonpath='{
.items[0].metadata.name}') -f
jar包下载
- 搭建AlibabaCloud 首先搭建几个环境全部在Linux下
1、nacos 注册中心文档
2、nacos 注册中心jar包
3、sentinel 流量控制,断路 文档
4、apache-skywalking-apm-bin 链路跟踪
5、Rocketmq 的使用
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/20556.html