当前位置: 首页 > article >正文

详解springcloud gateway工作原理、断言、filter、uri、id、全局跨域、globalfilter等以及关键源码实现

1.gateway概念
  1. 网关就是当前微服务项目的"统一入口"
  2. 程序中的网关就是当前微服务项目对外界开放的统一入口
  3. 所有外界的请求都需要先经过网关才能访问到我们的程序
  4. 提供了统一入口之后,方便对所有请求进行统一的检查和管理
2. 网关的主要功能
  • 将所有请求统一经过网关
  • 网关可以对这些请求进行检查
  • 网关方便记录所有请求的日志
  • 网关可以统一将所有请求路由到正确的模块\服务上

“路由"的近义词就是"分配”
在这里插入图片描述

3. 工作原理

在这里插入图片描述
在这里插入图片描述
Spring Gateway的工作原理基于路由、断言(Predicates)和过滤器(Filters)三大核心概念:

  • ‌路由(Route):定义了请求的转发规则,包括目标URL和匹配条件。
  • 断言(Predicates):用于匹配HTTP请求的各种条件,如路径、头信息、参数等。只有匹配成功的请求才会被路由处理。
  • 过滤器(Filters):在请求处理前后执行特定的逻辑,例如权限校验、日志记录
4. 配置和使用示例
spring:cloud:gateway:routes:- id: myrouteuri: http://example.compredicates:- Path=/api/**filters:- AddRequestHeader=X-Request-ID, \${requestId}

这个配置定义了一个路由,所有路径以/api/开头的请求都会被转发到http://example.com,并且在请求头中添加一个X-Request-ID字段‌

springcloud gateway中配置uri有3种方式:

  • ws(websocket)方式: uri: ws://localhost:9000
  • http方式: uri: http://localhost:8130/
  • lb(注册中心中服务名字)方式: uri: lb://brilliance-consumer

springcloud gatetway命名规范

能被gateway的lb方式识别到的命名规则为:

   "[a-zA-Z]([a-zA-Z]|\\d|\\+|\\.|-)*:.*"

如果名字中有非*“a-zA-Z:.”*规则字符或者使用“_”,则会报错

5.网关gateway routes的组成

1. id:必须唯一

2. predicates(断言)
在这里插入图片描述
关键类源码分析:

package org.springframework.cloud.gateway.handler.predicate;import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.style.ToStringCreator;
import org.springframework.http.server.PathContainer;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.util.pattern.PathPattern;
import org.springframework.web.util.pattern.PathPattern.PathMatchInfo;
import org.springframework.web.util.pattern.PathPatternParser;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_MATCHED_PATH_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_PATH_CONTAINER_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.GATEWAY_PREDICATE_ROUTE_ATTR;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.putUriTemplateVariables;
import static org.springframework.http.server.PathContainer.parsePath;/*** @author Spencer Gibb* @author Dhawal Kapil*/
public class PathRoutePredicateFactory extends AbstractRoutePredicateFactory<PathRoutePredicateFactory.Config> {private static final Log log = LogFactory.getLog(PathRoutePredicateFactory.class);private static final String MATCH_TRAILING_SLASH = "matchTrailingSlash";private PathPatternParser pathPatternParser = new PathPatternParser();public PathRoutePredicateFactory() {super(Config.class);}private static void traceMatch(String prefix, Object desired, Object actual, boolean match) {if (log.isTraceEnabled()) {String message = String.format("%s \"%s\" %s against value \"%s\"", prefix, desired,match ? "matches" : "does not match", actual);log.trace(message);}}public void setPathPatternParser(PathPatternParser pathPatternParser) {this.pathPatternParser = pathPatternParser;}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("patterns", MATCH_TRAILING_SLASH);}@Overridepublic ShortcutType shortcutType() {return ShortcutType.GATHER_LIST_TAIL_FLAG;}@Overridepublic Predicate<ServerWebExchange> apply(Config config) {final ArrayList<PathPattern> pathPatterns = new ArrayList<>();synchronized (this.pathPatternParser) {pathPatternParser.setMatchOptionalTrailingSeparator(config.isMatchTrailingSlash());config.getPatterns().forEach(pattern -> {PathPattern pathPattern = this.pathPatternParser.parse(pattern);pathPatterns.add(pathPattern);});}return new GatewayPredicate() {@Overridepublic boolean test(ServerWebExchange exchange) {PathContainer path = (PathContainer) exchange.getAttributes().computeIfAbsent(GATEWAY_PREDICATE_PATH_CONTAINER_ATTR,s -> parsePath(exchange.getRequest().getURI().getRawPath()));PathPattern match = null;for (int i = 0; i < pathPatterns.size(); i++) {PathPattern pathPattern = pathPatterns.get(i);if (pathPattern.matches(path)) {match = pathPattern;break;}}if (match != null) {traceMatch("Pattern", match.getPatternString(), path, true);PathMatchInfo pathMatchInfo = match.matchAndExtract(path);putUriTemplateVariables(exchange, pathMatchInfo.getUriVariables());exchange.getAttributes().put(GATEWAY_PREDICATE_MATCHED_PATH_ATTR, match.getPatternString());String routeId = (String) exchange.getAttributes().get(GATEWAY_PREDICATE_ROUTE_ATTR);if (routeId != null) {// populated in RoutePredicateHandlerMappingexchange.getAttributes().put(GATEWAY_PREDICATE_MATCHED_PATH_ROUTE_ID_ATTR, routeId);}return true;}else {traceMatch("Pattern", config.getPatterns(), path, false);return false;}}@Overridepublic Object getConfig() {return config;}@Overridepublic String toString() {return String.format("Paths: %s, match trailing slash: %b", config.getPatterns(),config.isMatchTrailingSlash());}};}@Validatedpublic static class Config {private List<String> patterns = new ArrayList<>();private boolean matchTrailingSlash = true;public List<String> getPatterns() {return patterns;}public Config setPatterns(List<String> patterns) {this.patterns = patterns;return this;}/*** @deprecated use {@link #isMatchTrailingSlash()}*/@Deprecatedpublic boolean isMatchOptionalTrailingSeparator() {return isMatchTrailingSlash();}/*** @deprecated use {@link #setMatchTrailingSlash(boolean)}*/@Deprecatedpublic Config setMatchOptionalTrailingSeparator(boolean matchOptionalTrailingSeparator) {setMatchTrailingSlash(matchOptionalTrailingSeparator);return this;}public boolean isMatchTrailingSlash() {return matchTrailingSlash;}public Config setMatchTrailingSlash(boolean matchTrailingSlash) {this.matchTrailingSlash = matchTrailingSlash;return this;}@Overridepublic String toString() {return new ToStringCreator(this).append("patterns", patterns).append(MATCH_TRAILING_SLASH, matchTrailingSlash).toString();}}}
package org.springframework.cloud.gateway.handler.predicate;import java.util.function.Consumer;
import java.util.function.Predicate;
import org.springframework.cloud.gateway.handler.AsyncPredicate;
import org.springframework.cloud.gateway.support.Configurable;
import org.springframework.cloud.gateway.support.NameUtils;
import org.springframework.cloud.gateway.support.ShortcutConfigurable;
import org.springframework.web.server.ServerWebExchange;
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.toAsyncPredicate;/*** @author Spencer Gibb*/
@FunctionalInterface
public interface RoutePredicateFactory<C> extends ShortcutConfigurable, Configurable<C> {/*** Pattern key.*/String PATTERN_KEY = "pattern";// useful for javadsldefault Predicate<ServerWebExchange> apply(Consumer<C> consumer) {C config = newConfig();consumer.accept(config);beforeApply(config);return apply(config);}default AsyncPredicate<ServerWebExchange> applyAsync(Consumer<C> consumer) {C config = newConfig();consumer.accept(config);beforeApply(config);return applyAsync(config);}default Class<C> getConfigClass() {throw new UnsupportedOperationException("getConfigClass() not implemented");}@Overridedefault C newConfig() {throw new UnsupportedOperationException("newConfig() not implemented");}default void beforeApply(C config) {}Predicate<ServerWebExchange> apply(C config);default AsyncPredicate<ServerWebExchange> applyAsync(C config) {return toAsyncPredicate(apply(config));}default String name() {return NameUtils.normalizeRoutePredicateName(getClass());}}

自定义Vip路由断言工厂实现

package com.wemedia.gateway.config;import jakarta.validation.constraints.NotEmpty;
import org.springframework.cloud.gateway.handler.predicate.AbstractRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.CookieRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.GatewayPredicate;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.server.ServerWebExchange;import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;/*** 自定义Vip路由断言工厂*/
@Component
public class VipRoutePredicateFactory extends AbstractRoutePredicateFactory<VipRoutePredicateFactory.Config> {public VipRoutePredicateFactory(){super(Config.class);}@Overridepublic List<String> shortcutFieldOrder() {return Arrays.asList("param","value");}@Overridepublic Predicate<ServerWebExchange> apply(Config config) {return new GatewayPredicate() {@Overridepublic boolean test(ServerWebExchange serverWebExchange) {//localhost/search?q=hhh&user=jackmaServerHttpRequest request = serverWebExchange.getRequest();String first = request.getQueryParams().getFirst(config.param);return StringUtils.hasText(first)&&first.equals(config.value);}};}@Validatedpublic static class Config {@NotEmptyprivate String value;@NotEmptyprivate String param;public String getParam() {return param;}public void setParam(String param) {this.param = param;}public String getValue() {return value;}public void setValue(String value) {this.value = value;}}
}在这里插入代码片

配置Vip断言
在这里插入图片描述
3. Filter(过滤器)
在这里插入图片描述
3.1 rewritePath(路径重写)
在这里插入图片描述
在这里插入图片描述

  • 添加RewritePath过滤器,重写原先路径/readDb,在访问路径前面追加/api/order/readDb,不然网关无法直接访问/readDb;
  • 添加AddReponseHeader过滤器,给响应头增加参数X-Response-ABC,值为123

3.2 默认过滤器filter:
在这里插入图片描述
增加默认过滤器default-filters, 参数Add-ReponseHeader=X-Reponse-Abc ,值为123 给所有服务的相应头中

3.3 全局过滤器GlobalFilter

package com.wemedia.gateway.filter;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;/*** 实现响应时间全局过滤器*/
@Component
@Slf4j
public class RTGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();String uri = request.getURI().toString();long start=System.currentTimeMillis();log.info("请求【{}】开始时间:{}",uri,start );//================以上是前置逻辑==============Mono<Void> filter = chain.filter(exchange).doFinally((result) -> {//================后置逻辑long end = System.currentTimeMillis();log.info("请求【{}】结束时间:{},耗时:{}ms", uri, end, end - start);});return filter;}@Overridepublic int getOrder() {return 0;}
}

过滤器filter 列表:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3.4 自定义过滤器工厂

关键源码分析

package org.springframework.cloud.gateway.filter.factory;
import reactor.core.publisher.Mono;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.web.server.ServerWebExchange;import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator;/*** @author Spencer Gibb*/
public class AddResponseHeaderGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {return chain.filter(exchange).then(Mono.fromRunnable(() -> addHeader(exchange, config)));}@Overridepublic String toString() {return filterToStringCreator(AddResponseHeaderGatewayFilterFactory.this).append(config.getName(), config.getValue()).toString();}};}void addHeader(ServerWebExchange exchange, NameValueConfig config) {final String value = ServerWebExchangeUtils.expand(exchange, config.getValue());HttpHeaders headers = exchange.getResponse().getHeaders();// if response has been commited, no more response headers will bee added.if (!exchange.getResponse().isCommitted()) {headers.add(config.getName(), value);}}}

1.实现一次性token自定义过滤器工厂

package com.wemedia.gateway.filter;import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractNameValueGatewayFilterFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.UUID;/*** 实现一次性令牌的自定义过滤器工场*/
@Component
@Slf4j
public class OnceTokenGatewayFilterFactory extends AbstractNameValueGatewayFilterFactory {@Overridepublic GatewayFilter apply(NameValueConfig config) {return new GatewayFilter() {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//每次响应之前,添加一个一次性令牌,支持uuid,jwt等格式return chain.filter(exchange).then(Mono.fromRunnable(()->{ServerHttpResponse response = exchange.getResponse();HttpHeaders headers = response.getHeaders();String value = config.getValue();if("uuid".equalsIgnoreCase(value)){value = UUID.randomUUID().toString();}if("jwt".equalsIgnoreCase(value)){value="";}headers.add(config.getName(),value);}));}};}
}

2.配置一次性token过滤器
在这里插入图片描述
3.访问api响应结果如下:
在这里插入图片描述
3.5 实现全局跨域
在这里插入图片描述

  • 解决单机跨域方法:直接在每个controller上增加注解@CrossOrigin

在这里插入图片描述

  • 在分布式系统上解决跨域问题,在gateway上统一处理跨域问题
    配置全局跨域:
    在这里插入图片描述
    运行结果如下,增加了跨域处理:
    在这里插入图片描述

相关文章:

详解springcloud gateway工作原理、断言、filter、uri、id、全局跨域、globalfilter等以及关键源码实现

1.gateway概念 网关就是当前微服务项目的"统一入口"程序中的网关就是当前微服务项目对外界开放的统一入口所有外界的请求都需要先经过网关才能访问到我们的程序提供了统一入口之后,方便对所有请求进行统一的检查和管理 2. 网关的主要功能 将所有请求统一经过网关网…...

C++面向对象特性之继承篇

C语音是面向过程的语言&#xff0c;而C在其之上多了面向对象的特性&#xff0c;面向对象三大特性:封装性、继承性、多态性。今天主包来讲讲自己学到的关于C继承特性的知识。 一、继承是什么 继承是提高代码复用的一种重要手段。正如C的模版、泛型编程等等都是为了实现代码复用…...

【Java设计模式及实践学习-第4章节-结构型模式】

第4章节-结构型模式 笔记记录 1. 适配器模式2. 代理模式3. 装饰器模式4. 桥接模式5. 组合模式6. 外观模式7. 享元模式8. 总结 1. 适配器模式 2. 代理模式 3. 装饰器模式 4. 桥接模式 5. 组合模式 6. 外观模式 7. 享元模式 Java语言中的String字符串就使用了享元模式&…...

【AI News | 20250423】每日AI进展

AI Repos 1、suna Suna是一款完全开源的AI助手&#xff0c;旨在通过自然对话帮助用户轻松完成现实世界的任务。它作为您的数字伙伴&#xff0c;提供研究、数据分析和日常问题解决等功能&#xff0c;并结合强大的能力与直观的界面&#xff0c;理解您的需求并交付成果。Suna的工…...

大数据利器Kafka

大数据利器Kafka&#xff1a;从入门到实战的全面指南 在大数据的世界里&#xff0c;Kafka就像是一个高效的“数据快递员”&#xff0c;负责在不同的系统之间快速、可靠地传递数据。今天&#xff0c;咱们就一起来深入了解一下这个强大的工具。Kafka是由LinkedIn开发的分布式发布…...

.NET、java、python语言连接SAP系统的方法

💡 本文会带给你 可用哪些技术与Sap系统连接怎样用Rfc技术连接SAP一. SAP系统与外部系统集成技术 SAP系统提供了多种方式供Java、.NET、Python等外部编程语言进行连接和集成。 1. RFC (Remote Function Call) 连接 适用语言:Java, .NET, Python, 其他支持RFC的编程语言 …...

【学习准备】算法和开发知识大纲

1 缘起 今年&#xff08;2025年&#xff09;的职业升级结果&#xff1a;不通过。没办法升职加薪了。 需要开始完善学习&#xff0c;以应对不同的发展趋势&#xff0c;为了督促自己学习&#xff0c;梳理出相关学习大纲。 分为算法和开发两部分。 算法&#xff0c;包括基础算法和…...

【Nova UI】七、SASS 全局变量体系:组件库样式开发的坚固基石

序言 咱们已经实现了 SASS 中一系列实用的函数和混入&#xff0c;可它们究竟如何在实际的组件库样式开发里大展身手&#xff0c;尤其是在构建全局变量体系这一关键环节呢&#x1f9d0;&#xff1f;这篇文章将为你揭晓答案&#xff0c;带你深入了解怎样利用这些工具实现 SASS 全…...

第七篇:linux之基本权限、进程管理、系统服务

第七篇&#xff1a;linux之基本权限、进程管理、系统服务 文章目录 第七篇&#xff1a;linux之基本权限、进程管理、系统服务一、基本权限1、什么是权限&#xff1f;2、为什么要有权限&#xff1f;3、权限与用户之间的关系&#xff1f;4、权限对应的数字含义5、使用chmod设定权…...

Windows 同步技术-一次性初始化

组件通常设计为在首次调用时执行初始化任务&#xff0c;而不是加载它们时。 一次性初始化函数可确保此初始化仅发生一次&#xff0c;即使多个线程可能尝试初始化也是如此。 Windows Server 2003 和 Windows XP&#xff1a; 应用程序必须使用 互锁函数 或其他同步机制提供自己的…...

爬虫案例-爬取某企数据

文章目录 1、准备要爬取企业名称数据表2、爬取代码3、查看效果 1、准备要爬取企业名称数据表 企业名称绍兴市袍江王新国家庭农场绍兴市郑杜粮油专业合作社绍兴市越城区兴华家庭农场绍兴市越城区锐意家庭农场绍兴市越城区青甸畈家庭农场绍兴市袍江王新国家庭农场绍兴市袍江月明…...

VAE-LSTM异常检测模型复刻报告

VAE-LSTM异常检测模型复刻报告 复刻背景 本报告记录了我复刻VAE-LSTM异常检测模型的完整过程。原论文提出了一种结合变分自编码器(VAE)和长短期记忆网络(LSTM)的异常检测方法&#xff0c;用于时间序列数据。 环境配置 复刻过程中使用的环境配置如下&#xff1a; Python 3.…...

学习笔记—C++—string(一)

目录 string 为什么学习string的类 string类的常用接口 string类对象的常见构造 string类对象的访问及遍历操作 operator[] 迭代器 范围for auto 迭代器&#xff08;二&#xff09; string类对象的容量操作 size,length,max_size,capacity,clear基本用法 reserve 提…...

OpenCV 图形API(55)颜色空间转换-----将图像从 RGB 色彩空间转换为 I420 格式函数RGB2I420()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从 RGB 色彩空间转换为 I420 色彩空间。 该函数将输入图像从 RGB 色彩空间转换为 I420。R、G 和 B 通道值的常规范围是 0 到 255。 输出图…...

GPLT-2025年第十届团体程序设计天梯赛总决赛题解(共计266分)

今天偶然发现天梯赛的代码还保存着&#xff0c;于是决定写下这篇题解&#xff0c;也算是复盘一下了 L1本来是打算写的稳妥点&#xff0c;最后在L1-6又想省时间&#xff0c;又忘记了insert&#xff0c;replace这些方法怎么用&#xff0c;也不想花时间写一个文件测试&#xff0c…...

MySQL数据库精研之旅第十期:打造高效联合查询的实战宝典(一)

专栏&#xff1a;MySQL数据库成长记 个人主页&#xff1a;手握风云 目录 一、简介 1.1. 为什么要使用联合查询 1.2. 多表联合查询时的计算 1.3. 示例 二、内连接 2.1. 语法 2.2. 示例 三、外连接 4.1. 语法 4.2. 示例 一、简介 1.1. 为什么要使用联合查询 一次查询需…...

zkPass案例实战之合约篇

目录 一、contracts/contracts/ProofVerifier.sol 1. License 和 Solidity 版本 2. 导入依赖 3. 合约声明和默认分配器地址 4. 验证证明 5. 验证分配器签名 6. 验证验证者签名 7. 签名前缀处理 8. 签名恢复 总结 二、contracts/contracts/SampleAttestation.sol 1. …...

15.FineReport动态展示需要的列

1.首先连接自带的sqlite数据库&#xff0c;具体方法参考下面的链接 点击查看连接sqlite数据库 2.文件 – 新建普通报表 3.新建数据库查询 4.查询自带的销售明细表 5.把数据添加到格子中&#xff0c;并设置边框颜色等格式 6.查询新的数据集&#xff1a;column 7.点笔 8.全部添…...

Windows云主机远程连接提示“出现了内部错误”

今天有人反馈说有个服务器突然连不上了&#xff0c;让我看下什么问题&#xff0c;我根据他给的账号密码试了下发现提示“出现了内部错误”&#xff0c;然后就是一通排查 先是查看安全组&#xff0c;没发现特别的问题&#xff0c;因为也没有调过这块的配置 然后通过控制台登录进…...

最新扣子(Coze)案例教程:Excel数据生成统计图表,自动清洗数据+转换可视化图表+零代码,完全免费教程

大家好&#xff0c;我是斜杠君。 知识星球群有同学和我说每天的工作涉及很多数据表的重复操作&#xff0c;想学习Excel数据表通过大模型自动转数据图片的功能。 今天斜杠君就带大家一起搭建一个智能体&#xff0c;以一个销售行业数据为例&#xff0c;可以快速实现自动清洗Exc…...

如何安装Visio(win10)

首先下载下面这些文件 HomeStudent2021Retail.img officedeploymenttool_17531-20046.exe office中文语言包.exe 确保这些文件都在一个文件夹内&#xff08;我已经上传这些资源&#xff0c;这些资源都是官网下载的&#xff09; 官网资源下载教程 1.下载Office镜像&#xff0…...

建筑安全员 A 证与 C 证:差异决定职业方向

在建筑行业的职业发展道路上&#xff0c;安全员 A 证和 C 证就像两条不同的岔路&#xff0c;它们之间的差异&#xff0c;在很大程度上决定了从业者的职业方向。 从证书性质和用途来看&#xff0c;A 证是从业资格证书&#xff0c;更像是一把开启安全管理高层岗位的 “金钥匙”。…...

Java Arrays工具类解析(Java 8-17)

一、Arrays工具类概述 java.util.Arrays是Java集合框架中提供的数组操作工具类&#xff0c;包含各种静态方法用于操作数组&#xff08;排序、搜索、比较、填充、复制等&#xff09;。自Java 8到17版本&#xff0c;Arrays类不断增强了功能&#xff0c;特别是引入了并行操作和St…...

(19)VTK C++开发示例 --- 分隔文本读取器

文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;VTK开发 &#x1f448; 1. 概述 本例采用坐标和法线&#xff08;x y z nx ny nz&#xff09;的纯文本文件&#xff0c;并将它们读入vtkPolyData并显示…...

Redis从入门到实战先导篇

前言&#xff1a;本节内容包括虚拟机VMware的安装&#xff0c;Linux系统的配置&#xff0c;FinalShell的下载与配置&#xff0c;Redis与其桌面客户端的安装指导,便于后续黑马Redis从入门到实战的课程学习 目录 主要内容 0.相关资源 1.VMware安装 2.Linux与CentOS安装 3.Fi…...

WebSocket是h5定义的,双向通信,节省资源,更好的及时通信

浏览器和服务器之间的通信更便利&#xff0c;比http的轮询等效率提高很多&#xff0c; WebSocket并不是权限的协议&#xff0c;而是利用http协议来建立连接 websocket必须由浏览器发起请求&#xff0c;协议是一个标准的http请求&#xff0c;格式如下 GET ws://example.com:3…...

uniapp中使用<cover-view>标签

文章背景&#xff1a; uniapp中遇到了原生组件(canvas)优先级过高覆盖vant组件 解决办法&#xff1a; 使用<cover-view>标签 踩坑&#xff1a; 我想实现的是一个vant组件库中动作面板的效果&#xff0c;能够从底部弹出框&#xff0c;让用户进行选择&#xff0c;我直…...

JavaScript 防抖和节流

方法一&#xff1a;使用lodash库的debounce方法 方法二&#xff1a;手写防抖函数 function debounce(fn,t){// 1.声明一个定时器变量 因为需要多次赋值 使用let声明let timer // 返回一个匿名函数return function(){if(timer){// 如果定时器存在清除之前的定时器 clearTimeout(…...

Spring Boot 启动时 `converting PropertySource ... to ...` 日志详解

Spring Boot 启动时 converting PropertySource ... to ... 日志详解 1. 日志背景 在 Spring Boot 应用启动过程中&#xff0c;会加载并处理多种 配置源&#xff08;如 application.properties、系统环境变量、命令行参数等&#xff09;。这些配置源会被封装为 PropertySource…...

分割数据集中.json格式标签转化成伪彩图图像

一、前言 图像分割任务中&#xff0c;分割数据集的转换和表示方式对于模型训练至关重要。目前主要有两种常见的分割结果表示方法&#xff1a; 1. 转化为TXT文件 这种方式通常使用一系列的点&#xff08;坐标&#xff09;来表示图像中每个像素的类别标签。每个点通常包含像素…...