SpringCloud Alibaba完整使用

SpringCloud Alibaba完整使用小白必学SpringClodAlibaba微服务技术组件搭建学不会就是我的锅AlibabaCloud微服务初级篇依赖认知1、SpringClodAlibaba版本依赖关系讲解2、SpringClodAlibaba官方网站3、SpringClodAlibabaMaven坐标4、SpringClodAlibabaNacos注册中心5、SpringClodAlibabaNacos配置中心6、SpringClodAlibabaSMS短信发送配置7、SpringClodAlibabaOSS

大家好,欢迎来到IT知识分享网。

SpringCloud Alibaba完整使用

资料领取

可以学到微服务里面的各种组件搭建使用教程、6666

1、视频学习

我的视频搭建教程

2、学习搭建网站

小白必学习搭建网站

3、技术交流QQ群

加入开发社区

4、源码地址

https://gitee.com/yswyn_admin/cloud_api

一、AlibabaCloud微服务初级篇依赖认知

1、版本依赖关系讲解

1)官方网站

gitHup地址

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)官网

githup官网

4、官网地址收集

1)Cloud Alibaba官网组件大全

Cloud Alibaba官网组件大全

2)Cloud Alibaba依赖关系

Cloud Alibaba依赖关系

3)Cloud Alibaba 2021.0.1.0 升级定制指南

升级定制指南

4)Cloud Alibaba Nacos 版本大全

Cloud Alibaba Nacos 版本大全

5)Cloud Alibaba Sentinel 版本大全

Cloud Alibaba Sentinel 版本大全

5、虚拟机搭建

虚拟机搭建教程地址

二、AlibabaCloud微服务运维篇环境搭建

1、虚拟机搭建

1)搭建学习地址

搭建学习教程地址

2)百度到哔哩哔哩

在这里插入图片描述

3)下载VMware16

下载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 ServerURL,若是要注册到多个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 ServerURL,若是要注册到多个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底层的客户端实现:
1URLConnection:默认实现,不支持连接池
2Apache HttpClient:支持连接池
3OKHttp:支持连接池

因此优化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包下载

项目下载地址
sentinel JAR下载地址

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/20556.html

(0)
上一篇 2024-02-07 16:15
下一篇 2024-02-08 10:15

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

关注微信