# 从浅入深 学习 SpringCloud 微服务架构(十三)SCG 网关中使用 sentinel 限流

从浅入深 学习 SpringCloud 微服务架构(十三)SCG 网关中使用 sentinel 限流

一、SCG 网关中使用 sentinel 限流:入门案例

1、基于 Sentinel 的限流:

1) Sentinel 支持对 Spring Cloud Gateway, Zuul 等主流的 API Gateway 进行限流。
2) 从 Sentinel-1.6.0 版本开始,Sentinel 提供了 Spring Cloud Gateway 的适配模块,可以提供两种资源维度的限流:

  • route 维度 : 即在 Spring 配置文件中配置的路由条目,资源名为对应的 routeld
  • 自定义 API 维度 : 用户可以利用 Sentinel 提供的 API 来自定义一些 API 分组

3)Sentinel1.6.0 引入了 Sentinel APl Gateway Adapter Common 模块,此模块中包含网关限流的规则
和自定义 API的实体和管理逻辑:

  • GatewayF1owu1e : 网关限流规则,针对 APl Gateway 的场景定制的限流规则,可以针对不同 route 或自定义的 API 分组进行限流,支持针对请求中的参数、Header、来源 IP 等进行定制化的限流。
  • ApiDefinition : 用户自定义的 API 定义分组,可以看做是一些 URL 匹配的组合。比如我们可以定义一个 AP| 叫 my_api,请求 path 模式为 /foo/**和 /baz/**的都归到 my_api 这个 API 分组下面。限流的时候可以针对这个自定义的 API分组维度进行限流。

2、SCG 网关中使用 sentinel 限流:入门案例:环境搭建。

2.1 在子工程(子模块) api_gateway_service 的 pom.xml 中导入 Sentinel 限流 依赖坐标。
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>spring_cloud_demo</artifactId><groupId>djh.it</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>api_gateway_service</artifactId><dependencies><!-- springcloudgateway 的内部是通过 netty + webflux 实现。webflux 实现和 springmvc 存在冲突,需要注销掉父工程中的 web 依赖,在各子模块中导入 web 依赖。--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-gateway</artifactId></dependency><!-- 引入 EurekaClient 依赖坐标 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><!-- 配置 SCG 网关 filter 限流 依赖坐标:redis 监控依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><!-- 配置 SCG 网关 filter 限流 依赖坐标:redis 依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId></dependency><!-- sentinel 网关限流 --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-spring-cloud-gateway-adapter</artifactId><version>1.6.3</version></dependency></dependencies>
</project>
<!-- spring_cloud_demo\api_gateway_service\pom.xml -->
2.2、在子工程 api_gateway_service(子模块)中,创建 Sentinel 限流 配置类 GatewayConfiguration.java
/***   spring_cloud_demo\api_gateway_service\src\main\java\djh\it\gateway\GatewayConfiguration.java**   2024-5-8 创建 Sentinel 限流 配置类 GatewayConfiguration.java*/package djh.it.gateway;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.result.view.ViewResolver;
import javax.annotation.PostConstruct;
import java.util.*;@Configuration
public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}//配置限流的异常处理器:SentinelGatewayBlockExceptionHandler@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}//配置限流过滤器@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter(){return new SentinelGatewayFilter();}//配置初始化的限流参数,用于指定资源的限流规则:1)资源名称(路由id),2)配置统计时间,3)配置限流阈值。@PostConstructpublic void initGatewayRules(){Set<GatewayFlowRule> rules = new HashSet<>();rules.add(new GatewayFlowRule("product-service").setCount(1).setIntervalSec(1));GatewayRuleManager.loadRules(rules);}
}
2.3、在子工程 api_gateway_service(子模块)中,修改 application.yml 配置文件,
##  spring_cloud_demo\api_gateway_service\src\main\resources\application.ymlserver:port: 8088  # 启动端口 命令行注入。
spring:application:name: api-gateway-service  #spring应用名, # 注意 FeignClient 不支持名字带下划线redis:  # 引入 redishost: localhostpool: 6379database: 0# 配置 SpringCloudGateway 的路由cloud:gateway:routes:  # 配置路由,路由Id,路由到微服务的 uri, 断言(判断条件)- id: product-service   # 保持唯一uri: lb://service-product  # lb://  根据微服务名称从注册中心拉取服务请求路径。predicates:   # 断言(判断条件)设置- Path=/product-service/**  # 将当前请求转发到 http://127.0.0.1/product/1filters:  # 配置路由过滤器 http://localhost:8088/product-service/product/1  --> http://127.0.0.1:9001/product/1- RewritePath=/product-service/(?<segment>.*), /$\{segment}  # 路径重写的过滤器。
eureka:  # 配置 Eurekaclient:service-url:defaultZone: http://localhost:9000/eureka/instance:prefer-ip-address: true  # 使用ip地址注册。

3、重新启动 父工程 spring_cloud_demo 下 全部子项目(eureka,product,order,gateway)的启动类,进行测试:

1)浏览器地址栏输入(正常访问):
http://localhost:8088/product-service/product/1 就转发到 http://127.0.0.1:9001/product/1

在这里插入图片描述

2)浏览器地址栏输入(快速多刷新几次,发现不能正常访问):
http://localhost:8088/product-service/product/1 就转发到 http://127.0.0.1:9001/product/1

在这里插入图片描述

二、SCG 网关中使用 sentinel 限流:限流异常提示

1、SCG 网关中使用 sentinel 限流,自定义异常提示

当触发限流后页面显示的是 Blocked bySentinel: FlowException。为了展示更加友好的限流提示 Sentinel 支持自定义异常处理。

可以在 Gatewayca11backmanager 注册回调进行定制:

setB1ockHandler : 注册函数用于实现自定义的逻辑处理被限流的请求,对应接口为 B1ockRequestHandler。

默认实现为 Defau1tBlockRequestHandler 当被限流时会返回类似于下面的错误信息 : B1ocked by sentine1:FlowException 。

2、在子工程 api_gateway_service(子模块)中,修改 Sentinel 限流 配置类 GatewayConfiguration.java 添加 自定义限流 处理器方法。

/***   spring_cloud_demo\api_gateway_service\src\main\java\djh\it\gateway\GatewayConfiguration.java**   2024-5-8 创建 Sentinel 限流 配置类 GatewayConfiguration.java*/package djh.it.gateway;import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.*;@Configuration
public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}//配置限流的异常处理器:SentinelGatewayBlockExceptionHandler@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}//配置限流过滤器@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter(){return new SentinelGatewayFilter();}//配置初始化的限流参数,用于指定资源的限流规则:1)资源名称(路由id),2)配置统计时间,3)配置限流阈值。@PostConstructpublic void initGatewayRules(){Set<GatewayFlowRule> rules = new HashSet<>();rules.add(new GatewayFlowRule("product-service").setCount(1).setIntervalSec(1));
//        rules.add(new GatewayFlowRule("order_api").setCount(1).setIntervalSec(1));GatewayRuleManager.loadRules(rules);}// 自定义限流 处理器方法@PostConstructpublic void initBlockHandlers(){BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {Map map = new HashMap<>();map.put("code",001);map.put("message", "对不起,接口限流了");return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(map));}};GatewayCallbackManager.setBlockHandler(blockRequestHandler);}//    @PostConstruct
//    private void initCustomizedApis(){
//        Set<ApiDefinition> definitions = new HashSet<>();
//        ApiDefinition api1 = new ApiDefinition("product_api")
//                .setPredicateItems(new HashSet<ApiPredicateItem>(){{
//            add(new ApiPathPredicateItem().setPattern("/product-service/product/**")
//                    .setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));
//                 }});
//        ApiDefinition api2 = new ApiDefinition("order_api")
//                .setPredicateItems(new HashSet<ApiPredicateItem>(){{
//                    add(new ApiPathPredicateItem().setPattern("/order-service/order"));
//                }});
//        definitions.add(api1);
//        definitions.add(api2);
//        GatewayApiDefinitionManager.loadApiDefinitions(definitions);
//    }
}

3、重新启动 父工程 spring_cloud_demo 下 全部子项目(eureka,product,order,gateway)的启动类,进行测试:

1)浏览器地址栏输入(正常访问):
http://localhost:8088/product-service/product/1 就转发到 http://127.0.0.1:9001/product/1

在这里插入图片描述

2)浏览器地址栏输入(快速多刷新几次,不能正常访问,异常页面是我们自定义的方法):
http://localhost:8088/product-service/product/1 就转发到 http://127.0.0.1:9001/product/1

在这里插入图片描述

三、SCG 网关中使用 sentinel 限流:自定义分组限流

1、在子工程 api_gateway_service(子模块)中,修改 Sentinel 限流 配置类 GatewayConfiguration.java 添加 自定义 API 限流分组方法。

/***   spring_cloud_demo\api_gateway_service\src\main\java\djh\it\gateway\GatewayConfiguration.java**   2024-5-8 创建 Sentinel 限流 配置类 GatewayConfiguration.java*/package djh.it.gateway;import com.alibaba.csp.sentinel.adapter.gateway.common.SentinelGatewayConstants;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPathPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiPredicateItem;
import com.alibaba.csp.sentinel.adapter.gateway.common.api.GatewayApiDefinitionManager;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule;
import com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayRuleManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.SentinelGatewayFilter;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.BlockRequestHandler;
import com.alibaba.csp.sentinel.adapter.gateway.sc.callback.GatewayCallbackManager;
import com.alibaba.csp.sentinel.adapter.gateway.sc.exception.SentinelGatewayBlockExceptionHandler;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.*;@Configuration
public class GatewayConfiguration {private final List<ViewResolver> viewResolvers;private final ServerCodecConfigurer serverCodecConfigurer;public GatewayConfiguration(ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer) {this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);this.serverCodecConfigurer = serverCodecConfigurer;}//配置限流的异常处理器:SentinelGatewayBlockExceptionHandler@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SentinelGatewayBlockExceptionHandler sentinelGatewayBlockExceptionHandler(){return new SentinelGatewayBlockExceptionHandler(viewResolvers, serverCodecConfigurer);}//配置限流过滤器@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public GlobalFilter sentinelGatewayFilter(){return new SentinelGatewayFilter();}//配置初始化的限流参数,用于指定资源的限流规则:1)资源名称(路由id),2)配置统计时间,3)配置限流阈值。@PostConstructpublic void initGatewayRules(){Set<GatewayFlowRule> rules = new HashSet<>();
//        rules.add(new GatewayFlowRule("product-service")
//                .setCount(1)
//                .setIntervalSec(1));rules.add(new GatewayFlowRule("product-api").setCount(1).setIntervalSec(1));rules.add(new GatewayFlowRule("order_api").setCount(1).setIntervalSec(1));GatewayRuleManager.loadRules(rules);}// 自定义限流 处理器方法@PostConstructpublic void initBlockHandlers(){BlockRequestHandler blockRequestHandler = new BlockRequestHandler() {@Overridepublic Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, Throwable throwable) {Map map = new HashMap<>();map.put("code",001);map.put("message", "对不起,接口限流了");return ServerResponse.status(HttpStatus.OK).contentType(MediaType.APPLICATION_JSON_UTF8).body(BodyInserters.fromObject(map));}};GatewayCallbackManager.setBlockHandler(blockRequestHandler);}//自定义API限流分组方法:1)定义分组,2)对小组配置限流规则。@PostConstructprivate void initCustomizedApis(){Set<ApiDefinition> definitions = new HashSet<>();ApiDefinition api1 = new ApiDefinition("product-api").setPredicateItems(new HashSet<ApiPredicateItem>(){{add(new ApiPathPredicateItem().setPattern("/product-service/product/**")  // 以 /product-service/product/ 开头的所有 url.setMatchStrategy(SentinelGatewayConstants.URL_MATCH_STRATEGY_PREFIX));}});ApiDefinition api2 = new ApiDefinition("order_api").setPredicateItems(new HashSet<ApiPredicateItem>(){{add(new ApiPathPredicateItem().setPattern("/order-service/order"));  // 完成匹配 /order-service/order}});definitions.add(api1);definitions.add(api2);GatewayApiDefinitionManager.loadApiDefinitions(definitions);}
}

2、重新启动 父工程 spring_cloud_demo 下 全部子项目(eureka,product,order,gateway)的启动类,进行测试:

1)浏览器地址栏输入(正常访问):
http://localhost:8088/product-service/product/1 就转发到 http://127.0.0.1:9001/product/1

在这里插入图片描述

2)浏览器地址栏输入(快速多刷新几次,不能正常访问,返回异常页面是我们自定义的方法):
http://localhost:8088/product-service/product/1 就转发到 http://127.0.0.1:9001/product/1

在这里插入图片描述

四、SCG 网关高可用:概述

1、网关高可用

高可用 HA(High Availability) 是分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计减少系统不能提供服务的时间。

我们都知道,单点是系统高可用的大敌,单点往往是系统高可用最大的风险和敌人,应该尽量在系统设计的过程中避免单点。

方法论上,高可用保证的原则是“集群化”,或者叫“冗余”:只有一个单点,挂了服务会受影响;如果有冗余备份,挂了还有其他 backup 能够顶上。

2、我们实际使用 Spring Cloud Gateway 的方式如下图:

在这里插入图片描述

3、不同的客户端使用不同的负载将请求分发到后端的 Gateway,Gateway 再通过 HTTP 调用后端服务,最后对外输出。因此为了保证 Gateway 的高可用性,前端可以同时启动多个 Gateway 实例进行负载,在 Gateway 的前端使用 Nginx 或者 F5 进行负载转发以达到高可用性。

五、SCG 网关高可用:ngnix 结合网关集群构造高可用网关

1、在 idea 的 Run Dashboard 面板上,复制一个 GatewayServerApplication 网关服务,重命名为:GatewayServerApplication(2) 并在 application.yml 配置文件修改端口号为:8089

在这里插入图片描述

如果找不到 idea 的 Run Dashboard 面板上,请查看:
# IDEA2019 如何打开 Run Dashboard 运行仪表面板

2、重新启动 父工程 spring_cloud_demo 下 全部子项目(eureka,product,order,gateway,gateway2)的启动类,进行测试:

1)浏览器地址栏输入(正常访问):
http://localhost:8088/product-service/product/1 就转发到 http://127.0.0.1:9001/product/1

在这里插入图片描述

2)浏览器地址栏输入(也可以正常访问):
http://localhost:8089/product-service/product/1 就转发到 http://127.0.0.1:9001/product/1

在这里插入图片描述

3、安装一个 Nginx,并在安装目录下的 conf 目录下,找到配置文件 nginx.conf 打开并编辑它。

在这里插入图片描述

# D:\Program Files\nginx-1.8.1\conf\nginx.conf#user  nobody;
worker_processes  1;#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;#pid        logs/nginx.pid;events {worker_connections  1024;
}http {include       mime.types;default_type  application/octet-stream;#log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '#                  '$status $body_bytes_sent "$http_referer" '#                  '"$http_user_agent" "$http_x_forwarded_for"';#access_log  logs/access.log  main;sendfile        on;#tcp_nopush     on;#keepalive_timeout  0;keepalive_timeout  65;#gzip  on;# 集群配置upstream gateway {server 127.0.0.1:8088;server 127.0.0.1:8089;}server {listen       80;server_name  localhost;#charset koi8-r;#access_log  logs/host.access.log  main;#location / {#   root   html;#    index  index.html index.htm;#}# 当请求到 127.0.0.1 就转发到 gatewaylocation  / {proxy_pass http://gateway;}# 路由到订单服务#location  /api-product {#	proxy_pass http://127.0.0.1:9001/;#}# 路由到商品服务#location  /api-order {#	proxy_pass http://127.0.0.1:9002/;#}#error_page  404              /404.html;# redirect server error pages to the static page /50x.html#error_page   500 502 503 504  /50x.html;location = /50x.html {root   html;}# proxy the PHP scripts to Apache listening on 127.0.0.1:80##location ~ \.php$ {#    proxy_pass   http://127.0.0.1;#}# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000##location ~ \.php$ {#    root           html;#    fastcgi_pass   127.0.0.1:9000;#    fastcgi_index  index.php;#    fastcgi_param  SCRIPT_FILENAME  /scripts$fastcgi_script_name;#    include        fastcgi_params;#}# deny access to .htaccess files, if Apache's document root# concurs with nginx's one##location ~ /\.ht {#    deny  all;#}}# another virtual host using mix of IP-, name-, and port-based configuration##server {#    listen       8000;#    listen       somename:8080;#    server_name  somename  alias  another.alias;#    location / {#        root   html;#        index  index.html index.htm;#    }#}# HTTPS server##server {#    listen       443 ssl;#    server_name  localhost;#    ssl_certificate      cert.pem;#    ssl_certificate_key  cert.key;#    ssl_session_cache    shared:SSL:1m;#    ssl_session_timeout  5m;#    ssl_ciphers  HIGH:!aNULL:!MD5;#    ssl_prefer_server_ciphers  on;#    location / {#        root   html;#        index  index.html index.htm;#    }#}}

在这里插入图片描述

4、启动 Nginx 服务,并重新启动 父工程 spring_cloud_demo 下 全部子项目(eureka,product,order,gateway,gateway2)的启动类,进行测试:

浏览器地址栏输入(也能正常访问):
http://localhost/product-service/product/1

在这里插入图片描述

就相当于访问转发到

http://localhost:8088/product-service/product/1
http://localhost:8089/product-service/product/1

5、如果在 idea 的 Run Dashboard 面板上,停掉一个 GatewayServerApplication 如:8088

在这里插入图片描述

浏览器地址栏输入(也能正常访问):
http://localhost/product-service/product/1

在这里插入图片描述

但是,http://localhost:8088/product-service/product/1 就不能正常访问了。

在这里插入图片描述

上一节关联链接请点击:
# 从浅入深 学习 SpringCloud 微服务架构(十二)网关限流算法和 SCG 网关 filter 限流。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/681257.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MT3034 算术招亲

跟MT3033新的表达式类似&#xff0c;只多了一个括号合法性的判断 #include <bits/stdc.h> using namespace std; const int N 40; bool tag[N]; bool is_op(char c) {return c || c - || c * || c / || c ^; } int priority(char op) { // 优先级排序if (op ||…

大数据传输且不想布线时,如何实时传输数据?

在数字化转型的时代背景下&#xff0c;企业对数据传输的效率和安全性要求日益增加。过去&#xff0c;有线数据传输方式曾一度是企业网络建设的主流选择&#xff0c;但在当今的商业环境中&#xff0c;其局限性逐渐显现。本文将深入剖析传统有线数据传输的不足&#xff0c;并对比…

使用WPF中的Trigger实现按钮样式动态更改

使用WPF中的Trigger实现按钮样式动态更改 在Windows Presentation Foundation (WPF)中&#xff0c;Trigger 是一种强大的机制&#xff0c;它可以基于控件的属性值来动态更改控件的样式。这篇博客将介绍如何使用Trigger实现按钮在鼠标悬停时样式动态更改的效果。我们将详细讨论为…

Javaweb第五次作业

poet数据库sql语言 create table poet(id int unsigned primary key auto_increment comment ID,name varchar(10) not null comment 姓名,gender tinyint unsigned not null comment 性别, 说明: 1 男, 2 女,dynasty varchar(10) not null comment朝代,title varchar(20) not…

TypeScript 基础学习笔记:泛型 <T> vs 断言 as

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 TypeScript 基础学习笔记&#xff1a;泛型 <T> vs 断言 as&#x1f525; 引言&#x1f9e9; 泛型 <T>&#xff1a;灵活多变的类型容器示例&#xff1a;一个简单的泛型函数 &#x1f3c6; 类型断言 as&#xff1…

2024蓝桥杯CTF writeUP--packet

根据流量分析&#xff0c;我们可以知道129是攻击机&#xff0c;128被留了php后门&#xff0c;129通过get请求来获得数据 129请求ls Respons在这 里面有flag文件 这里请求打开flag文件&#xff0c;并以base64编码流传输回来 获得flag的base64的数据 然后解码 到手

Java:Servlet详解

目录 一、什么是Servlet 二、Servlet原理 Servlet的生命周期 三、 Servlet注释 WebServlet 一、什么是Servlet Servlet是JavaWeb开发的一种技术&#xff0c;Servlet程序需要部署在Servlet容器&#xff08;服务端&#xff09;中才能运行&#xff0c;常见的Servlet容器有Tom…

Oracle 23ai rpm安装配置及问题处理

1.安装介质下载 Oracle 23ai 免费版本已经正式发布&#xff0c;Oracle官网提供免费的下载试用&#xff08;无需账号&#xff09;地址如下 官网下载和试用地址 Oracle Database 23ai Free&#xff1a; https://www.oracle.com/database/free/get-started 三种安装方式可选…

Ansible-inventory和playbook

文章目录 一、inventory 主机清单1、列表表示2、inventory 中的变量3、变量3.1 主机变量3.2 组变量3.3 组嵌套 二、playbook剧本1、playbook的组成2、编写剧本2.1 剧本制作2.2 准备nginx.conf2.3 运行剧本2.4 查看webservers服务器2.5 补充参数 3、剧本定义、引用变量3.1 剧本制…

mysql中varchar与bigint直接比较会导致精度丢失以至于匹配到多行数据

在mysql中&#xff0c;我们都知道如果一个索引字段使用了函数或者计算那么查询的时候索引会失效&#xff0c;可是我相信在联表的时候我们只会关注两个表关联字段是否都创建了索引&#xff0c;却没有关注过这两个字段的类型是否一致&#xff0c;如果不一致的话索引是会失效的&am…

解决html2canvas生成图片慢的问题

// 主要看那个点击事件就行 <divclass"textBox-right-board-group"v-for"item in screenList":key"item.id"><!-- 获取不同分辨率下的屏幕的展示的文字大小DPI&#xff1a; fontSize: getFontSize(item.resolutionRatio), --><di…

NTP网络时间服务器如何实现煤矿智能化管理?

随着煤矿行业的不断发展&#xff0c;安全生产和效率是煤矿企业始终关注的重点。NTP网络时间服务器作为一种高精度的时间同步技术&#xff0c;其应用在煤矿领域也逐渐得到广泛推广。 ZRBG1000 NTP网络时间服务器是对煤矿等行业对网络时间同步应用需求设计的高准确度、高性能NTP网…