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

【PmHub后端篇】PmHub Gateway全局过滤器:接口调用耗时统计及黑白名单配置技术深度解析

在微服务架构日益成为现代应用开发主流模式的背景下,网关作为微服务架构前端的关键组件,肩负着路由请求、负载均衡、安全认证、流量控制、监控和日志记录等多项重要任务。本文将围绕PmHub项目中Gateway全局过滤器实现接口调用耗时统计的相关技术进行深入剖析,帮助开发者更好地理解和应用这些技术。

1 网关基础理论

在微服务架构中,单体应用被拆分为多个小型微服务,每个微服务可独立部署、扩展和维护。然而,这也带来了服务间通信管理的挑战,网关因此成为不可或缺的组件。网关是一个位于微服务架构前端的组件,它充当了所有微服务的入口。网关负责路由请求、负载均衡、安全认证、流量控制、监控和日志记录等任务。网关还可以将多个微服务组合成一个统一的 API,从而简化客户端与微服务之间的通信

在这里插入图片描述

常见的微服务网关包括Spring Cloud NetflixZuulSpring Cloud Gateway以及KongKong基于OpenResty + Lua开发,具有高性能、丰富的插件生态、多语言支持、跨平台支持和企业版等优势。但由于其学习成本较高,且对Java开发者不太友好,在实际项目中使用并不普遍。SpringCloud Gateway则是原zuul1.x版的替代品,更适合新项目使用。

以下是Spring Cloud GatewayZuul的详细对比:

对比点Spring Cloud GatewayZuul
架构与设计基于Spring 5Spring Boot 2Project Reactor,采用响应式编程模型基于Servlet,为阻塞模型
性能具备高吞吐量、低延迟的特点,适用于高并发场景性能相对较差,在高并发场景下可能出现瓶颈
功能特性支持动态路由、WebSocket,拥有丰富的过滤器工厂,可与Spring Security集成,具备限流、重试、熔断等功能仅具备基本的路由和过滤功能,支持前置和后置过滤器
易用性能够与Spring生态无缝集成,开发体验一致,拥有良好的文档和社区支持配置和扩展相对简单,但功能有限
维护与社区支持VMware积极维护,更新频繁,社区活跃,文档丰富Zuul 1已被归档,Zuul 2社区支持较少
插件与扩展性提供丰富的内置功能和插件,扩展性良好插件生态相对薄弱,功能扩展性较差
学习曲线需要学习响应式编程模型,对不熟悉响应式编程的开发者有一定挑战相对简单,适合小型和中型项目
典型使用场景适用于高性能、高并发且需要丰富功能和扩展性的企业级应用适用于小型和中型项目,无需处理高并发场景

2 Spring Cloud Gateway的核心组件

Spring Cloud Gateway主要包含三大核心组件:路由(Route)、断言(Predicate)、过滤器(Filter)
在这里插入图片描述

2.1 路由(Route)

路由是构建网关的基础模块,由ID、目标URI、一系列断言和过滤器组成。当断言为true时,请求将被匹配到相应的路由。

spring:redis:host: localhostport: 6379password:cloud:gateway:discovery:locator:lowerCaseServiceId: trueenabled: trueroutes:# 认证中心- id: pmhub-authuri: lb://pmhub-authpredicates:- Path=/auth/**filters:# 验证码处理- CacheRequestFilter# - ValidateCodeFilter- StripPrefix=1

以PmHub项目中的认证服务pmhub-auth为例,通过配置,请求网关的URL中带有「 /auth/** 」的请求会被转发到认证中心服务。

Gateway中,URI 有三种方式,包括:

  • Websocket配置方式
spring:cloud:gateway:routes:- id: pmhub-apiuri: ws://localhost:9090/predicates:- Path=/api/**
  • http地址配置方式
spring:cloud:gateway:routes:- id: pmhub-apiuri: http://localhost:9090/predicates:- Path=/api/**
  • Nacos注册中心配置方式
spring:cloud:gateway:routes:- id: pmhub-apiuri: lb://pmhub-authpredicates:- Path=/api/**

PmHub 采用的是第三种。

2.2 断言(Predicate)

断言可理解为匹配规则,用于确定请求是否符合特定条件,从而找到对应的Route进行处理。

Spring Cloud Gateway包含多种内置的Route Predicate Factories,例如根据日期时间、请求的远端地址、路由权重、请求头、Host地址、请求方法、请求路径和请求参数等进行断言。多个断言可以通过逻辑与(and)组合使用。

以下是一些常用的断言

  • Weight-匹配权重
spring: application:name: pmhub-gatewaycloud:gateway:routes:- id: pmhub-system-auri: http://localhost:9201/predicates:- Weight=group1, 8- id: pmhub-system-buri: http://localhost:9201/predicates:- Weight=group1, 2
  • Datetime-匹配日期时间之后发生的请求
spring: application:name: pmhub-gatewaycloud:gateway:routes:- id: pmhub-systemuri: http://localhost:9201/predicates:- After=2021-02-23T14:20:00.000+08:00[Asia/Shanghai]
  • Query-匹配查询参数
spring: application:name: pmhub-gatewaycloud:gateway:routes:- id: pmhub-systemuri: http://localhost:9201/predicates:- Query=username, abc.
  • Path-匹配请求路径
spring: application:name: pmhub-gatewaycloud:gateway:routes:- id: pmhub-systemuri: http://localhost:9201/predicates:- Path=/system/**
  • Header-匹配具有指定名称的请求头,\d+值匹配正则表达式
spring: application:name: pmhub-gatewaycloud:gateway:routes:- id: pmhub-systemuri: http://localhost:9201/predicates:- Header=X-Request-Id, \d+

如果内置断言无法满足需求,开发者还可以通过继承AbstractRoutePredicateFactory抽象类或实现lRoutePredicateFactory接口来自定义断言规则,自定义类需以RoutePredicateFactory后缀结尾。

  • 继承 AbstractRoutePredicateFactory 抽象类
@Component
public class MyRoutePredicateFactory extends AbstractRoutePredicateFactory<MyRoutePredicateFactory.Config>
{public MyRoutePredicateFactory(){super(MyRoutePredicateFactory.Config.class);}@Validatedpublic static class Config{@Setter@Getter@NotEmptyprivate String userType; //钻、金、银等用户等级}@Overridepublic Predicate<ServerWebExchange> apply(MyRoutePredicateFactory.Config config){return new Predicate<ServerWebExchange>(){@Overridepublic boolean test(ServerWebExchange serverWebExchange){//检查request的参数里面,userType是否为指定的值,符合配置就通过String userType = serverWebExchange.getRequest().getQueryParams().getFirst("userType");if (userType == null) return false;//如果说参数存在,就和config的数据进行比较if(userType.equals(config.getUserType())) {return true;}return false;}};}
}

2.3 过滤器(Filter)

网关中的过滤器类似于SpringMVC中的拦截器InterceptorServlet过滤器,分为全局默认过滤器、单一内置过滤器和自定义过滤器。
在这里插入图片描述

  • 全局过滤器:作用于所有路由,无需单独配置,可实现权限认证、IP访问限制等统一化处理的业务需求。在PmHub项目中,AuthFilter.java就是通过实现GlobalFilterOrdered接口来实现的全局过滤器。
  • 单一内置过滤器:主要作用于单一路由或某个路由。常见的单一过滤器功能包括过滤指定请求头的路径、过滤特定请求参数、添加响应头信息、对前缀和路径进行过滤以及路径重定向等。
  • 自定义过滤器:例如,在统计接口调用耗时时,可以创建一个全局Filter,实现GlobalFilterOrdered接口,并在filter方法中进行接口访问耗时统计。具体实现步骤为:记录接口访问的开始时间;在请求处理完成后,执行异步任务记录日志。
//先记录下访问接口的开始时间
exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());// Mono.fromRunnable 是非阻塞的,适合在 then 中处理后续的日志逻辑。
return chain.filter(exchange).then(Mono.fromRunnable(() -> {try {// 记录接口访问日志Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);if (beginVisitTime != null) {URI uri = exchange.getRequest().getURI();Map<String, Object> logData = new HashMap<>();logData.put("host", uri.getHost());logData.put("port", uri.getPort());logData.put("path", uri.getPath());logData.put("query", uri.getRawQuery());logData.put("duration", (System.currentTimeMillis() - beginVisitTime) + "ms");log.info("访问接口信息: {}", logData);log.info("我是美丽分割线: ###################################################");}} catch (Exception e) {log.error("记录日志时发生异常: ", e);}
}));

3 Gateway的相关配置

3.1 Gateway限流配置

限流是为了对流量进行限制,保护系统不被过高的流量冲击。

常见的限流算法包括:计数器算法、漏桶算法(Leaky Bucket)、以及令牌桶算法(Token Bucket)

Spring Cloud Gateway中,通过结合RedisLua脚本,利用RequestRateLimiterGatewayFilterFactory过滤器工厂实现基于令牌桶的限流方式。

  • 添加依赖
<!-- spring data redis reactive 依赖 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>
  • 限流规则,根据URI限流
spring:redis:host: localhostport: 6379password: cloud:gateway:routes:# 系统模块- id: pmhub-systemuri: lb://pmhub-systempredicates:- Path=/system/**filters:- StripPrefix=1- name: RequestRateLimiterargs:redis-rate-limiter.replenishRate: 1 # 令牌桶每秒填充速率redis-rate-limiter.burstCapacity: 2 # 令牌桶总容量key-resolver: "#{@pathKeyResolver}" # 使用 SpEL 表达式按名称引用 bean

在配置时,需要注意StripPrefix=1表示网关转发到业务模块时会自动截取前缀,可根据实际情况进行配置。

  • 限流规则配置类
/*** 限流规则配置类*/
@Configuration
public class KeyResolverConfiguration
{@Beanpublic KeyResolver pathKeyResolver(){return exchange -> Mono.just(exchange.getRequest().getURI().getPath());}
}

同时,启动网关服务PmHubGatewayApplication和系统服务PmHubSystemApplication进行验证,因为网关服务有认证鉴权,可以在 gateway 配置中增加一下白名单/system/**再进行测试,多次请求可能会返回HTTP ERROR 429,并且在Redis中会存在两个key,表明限流成功。

request_rate_limiter.{xxx}.timestamp
{xxx}.tokens

也可以根据其他限流规则来配置,如参数限流,IP限流:

//参数限流
@Bean
public KeyResolver parameterKeyResolver()
{return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
}// ip限流
@Bean
public KeyResolver ipKeyResolver()
{return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
}

3.2 Gateway黑名单配置

黑名单是一个禁止访问的URL列表。通过创建自定义过滤器BlackListUrlFilter,并配置黑名单列表blacklistUrl,可以实现对特定URL的访问限制。如有其他特殊需求,还可以实现自定义规则的过滤器来满足特定的过滤要求。

  • 过滤器核心逻辑 (apply方法)
public GatewayFilter apply(Config config) {return (exchange, chain) -> {// 获取请求路径String url = exchange.getRequest().getURI().getPath();// 检查是否命中黑名单if (config.matchBlacklist(url)) {// 返回拒绝访问响应return ServletUtils.webFluxResponseWriter(exchange.getResponse(), "请求地址不允许访问");}// 放行合法请求return chain.filter(exchange);};
}
  • 配置处理逻辑 (Config内部类)
public static class Config {// 存储配置的黑名单路径(支持**通配符)private List<String> blacklistUrl;// 存储编译后的正则表达式模式private List<Pattern> blacklistUrlPattern = new ArrayList<>();// 路径匹配逻辑public boolean matchBlacklist(String url) {return !blacklistUrlPattern.isEmpty() && blacklistUrlPattern.stream().anyMatch(p -> p.matcher(url).find());}// 配置注入时自动转换通配符为正则public void setBlacklistUrl(List<String> blacklistUrl) {this.blacklistUrl = blacklistUrl;this.blacklistUrlPattern.clear();this.blacklistUrl.forEach(url -> {this.blacklistUrlPattern.add(Pattern.compile(url.replaceAll("\\*\\*", "(.*?)"),  // 将**转换为正则表达式Pattern.CASE_INSENSITIVE  // 忽略大小写匹配));});}
}
  • 工作流程

    • 初始化:通过构造函数注册配置类
    • 配置加载:Spring Boot将application.yml中的blacklistUrl配置注入到Config对象
    • 模式转换:setBlacklistUrl()将通配符路径转换为正则表达式(如/auth/** ^/auth/(.*?)$
    • 请求过滤:每个请求经过网关时检查URL是否匹配黑名单模式
  • 典型配置示例

spring:cloud:gateway:routes:# 系统模块- id: pmhub-systemuri: lb://pmhub-systempredicates:- Path=/system/**filters:- StripPrefix=0- name: BlackListUrlFilterargs:blacklistUrl:- /user/list

3.3 Gateway白名单配置

白名单是允许访问的URL地址列表,例如登录、注册接口等无需登录即可访问的接口可以放在白名单中。在全局过滤器中添加相应逻辑,在ignore中设置whites,实现对匿名访问的支持。

  • 在全局过滤器中添加以下逻辑
// 跳过不需要验证的路径
if (StringUtils.matches(url, ignoreWhite.getWhites())) {return chain.filter(exchange);
}
  • 白名单配置
# 不校验白名单
ignore:whites:- /auth/logout- /auth/login

4 在PmHub中整合Gateway实战

4.1 编写全局过滤器

  • 新建AuthFilter
    在网关服务pmhub-gateway的filter下新建AuthFilter类,实现GlobalFilterOrdered接口。
/*** 网关鉴权*/
@Component
public class AuthFilter implements GlobalFilter, Ordered {private static final Logger log = LoggerFactory.getLogger(AuthFilter.class);private static final String BEGIN_VISIT_TIME = "begin_visit_time";//开始访问时间// 排除过滤的 uri 地址,nacos自行添加@Autowiredprivate IgnoreWhiteProperties ignoreWhite;@Autowiredprivate RedisService redisService;...@Overridepublic int getOrder() {return -200; // 设置过滤器优先级(数值越小优先级越高)}}
  • 在filter接口的实现中,主要完成以下几个方面的操作
    • 白名单过滤,即过滤掉不需要验证的请求路径;
    • 进行token鉴权,确保令牌不能为空且未过期,并将用户信息放在请求头中,方便服务调用传递;
    • 记录访问接口的开始时间,用于统计接口调用的耗时情况。
    @Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();ServerHttpRequest.Builder mutate = request.mutate();// 1. 请求路径检查String url = request.getURI().getPath();// 跳过白名单路径if (StringUtils.matches(url, ignoreWhite.getWhites())) {return chain.filter(exchange);}// 2. Token校验流程String token = getToken(request);if (StringUtils.isEmpty(token)) { // 令牌空校验return unauthorizedResponse(exchange, "令牌不能为空");}Claims claims = JwtUtils.parseToken(token); // JWT解析if (claims == null) { // 令牌有效性校验return unauthorizedResponse(exchange, "令牌已过期或验证不正确!");}// 3. Redis登录状态验证String userkey = JwtUtils.getUserKey(claims); boolean islogin = redisService.hasKey(getTokenKey(userkey));if (!islogin) { // 检查是否已登录return unauthorizedResponse(exchange, "登录状态已过期");}// 4. 用户信息提取与注入String userid = JwtUtils.getUserId(claims);String username = JwtUtils.getUserName(claims);if (StringUtils.isEmpty(userid) || StringUtils.isEmpty(username)) {return unauthorizedResponse(exchange, "令牌验证失败");}// 5. 请求头信息处理addHeader(mutate, SecurityConstants.USER_KEY, userkey); // 注入用户标识addHeader(mutate, SecurityConstants.DETAILS_USER_ID, userid); // 注入用户IDaddHeader(mutate, SecurityConstants.DETAILS_USERNAME, username); // 注入用户名// 移除内部请求标识(防止网关携带内部请求标识,造成系统安全风险)removeHeader(mutate, SecurityConstants.FROM_SOURCE);// 6. 接口访问日志记录exchange.getAttributes().put(BEGIN_VISIT_TIME, System.currentTimeMillis());// Mono.fromRunnable 是非阻塞的,适合在 then 中处理后续的日志逻辑。return chain.filter(exchange).then(Mono.fromRunnable(() -> {try {// 记录接口耗时和访问信息Long beginVisitTime = exchange.getAttribute(BEGIN_VISIT_TIME);if (beginVisitTime != null) {URI uri = exchange.getRequest().getURI();Map<String, Object> logData = new HashMap<>();logData.put("host", uri.getHost());logData.put("port", uri.getPort());logData.put("path", uri.getPath());logData.put("query", uri.getRawQuery());logData.put("duration", (System.currentTimeMillis() - beginVisitTime) + "ms");log.info("访问接口信息: {}", logData);log.info("我是美丽分割线: ###################################################");}} catch (Exception e) {log.error("记录日志时发生异常: ", e);}}));}
  • bootstrap.yml配置
    完成上述操作后,通过bootstrap.yml配置文件对应用名称、环境等信息进行配置,实现PmHub网关的自定义过滤器。
# Spring
spring: application:# 应用名称name: pmhub-gatewayprofiles:# 环境配置active: dev

5 总结

本文围绕 PmHub 项目,介绍微服务架构下网关的重要任务,对比 Spring Cloud Gateway 与 Zuul 的特点,阐述其核心组件,如路由、断言、过滤器,还说明了限流、黑白名单等配置及在 PmHub 中编写全局过滤器的实践,利于提升系统性能和安全性。

6 参考链接

  1. PmHub Gateway全局过滤器统计接口调用耗时
  2. 项目仓库(GitHub)
  3. 项目仓库(码云)

相关文章:

【PmHub后端篇】PmHub Gateway全局过滤器:接口调用耗时统计及黑白名单配置技术深度解析

在微服务架构日益成为现代应用开发主流模式的背景下&#xff0c;网关作为微服务架构前端的关键组件&#xff0c;肩负着路由请求、负载均衡、安全认证、流量控制、监控和日志记录等多项重要任务。本文将围绕PmHub项目中Gateway全局过滤器实现接口调用耗时统计的相关技术进行深入…...

国产激光二极管厂家

中国在激光二极管&#xff08;Laser Diode&#xff09;领域已有多家厂商布局&#xff0c;涵盖从低功率到高功率、不同波长的产品&#xff0c;应用于工业、医疗、通信、消费电子等领域。以下是部分国产激光二极管厂家及相关信息&#xff0c;供参考&#xff1a; 1. 武汉锐科光纤…...

安卓基础(XML)

123 属性​​​​行为​​​​适用场景​​​​注意事项​​match_parent填满父容器可用空间全屏视图、占满剩余空间父容器需有固定尺寸wrap_content根据内容自适应尺寸动态文本、图标、浮动按钮内容过长时可能超出父容器需处理 123 ​​属性​​​​作用​​​​常用值​​…...

uniapp|获取当前用户定位、与系统设定位置计算相隔米数、实现打卡签到(可自定义设定位置、位置有效范围米数)

基于UniApp阐述移动应用开发中定位功能的实现全流程,涵盖实时定位获取、动态距离计算与自定义位置、有效范围设定等功能。文章提供完整的代码示例与适配方案,适用于社交签到、课堂教室打卡等场景。 目录 引言定位功能在移动应用中的价值(社交、导航、O2O等场景)UniApp跨平台…...

matlab稳定求解高精度二维对流扩散方程

利用MATLAB稳定求解高精度二维对流扩散方程 Diffusion_1D.m , 2310 Diffusion_2D.m , 3813 license.txt , 1334...

【最新版】likeshop连锁点餐系统-PHP版+uniapp前端全开源

一.系统介绍 likeshop外卖点餐系统适用于茶饮类的外卖点餐场景&#xff0c;搭建自己的一点点、奈雪、喜茶点餐系统。 系统基于总部多门店的连锁模式&#xff0c;拥有门店独立管理后台&#xff0c;支持总部定价和门店定价LBS定位点餐&#xff0c;可堂食可外卖。无论运营还是二开…...

Redis 重回开源怀抱:开源精神的回归与未来展望

在开源软件的广袤天地里&#xff0c;Redis 一直是备受瞩目的明星项目。近期&#xff0c;Redis 宣布重新回归开源&#xff0c;这一消息犹如一颗石子投入平静的湖面&#xff0c;在技术社区激起层层涟漪。今天&#xff0c;就让我们深入了解 Redis 这一重大转变背后的故事、意义以及…...

mac运行java文件提示 错误: 缺少 JavaFX 运行时组件, 需要使用该组件来运行此应用程序

1、问题如上 双击java文件打不开&#xff0c;命令行报错。查找了下文章说java8之后&#xff0c;高版本jdk不自带javafx&#xff0c;需要自己下载 2、解决办法 首先查看自己的java版本&#xff0c;我是17.0.10 访问 JavaFX - Gluon 下载对应的版本&#xff0c;如果没有对应的 …...

pimpl与unique_ptr的问题

PImpl与std::unique_ptr组合 pimpl(Pointer to Implementation)是C程序开发中非常常用的技巧之一&#xff0c;它的好处有&#xff1a; 节省程序编译时间保持程序/库的二进制兼容性隐藏实现细节 举例一个常见的pimpl的使用示例&#xff1a; // a.h class Impl; //前置声明 c…...

Opencv进阶操作:图像拼接

文章目录 前言一、图像拼接的原理1. 特征提取与匹配2. 图像配准3. 图像变换与投影4. 图像融合5. 优化与后处理 二、图像拼接的简单实现&#xff08;案例实现&#xff09;1.引入库2.定义cv_show()函数3.创建特征检测函数detectAndDescribe()4.读取拼接图片5.计算图片特征点及描述…...

记录Token反序列化OAuth2Authentication(主要是直接存储用户信息的UserDetails )

项目场景&#xff1a; 本地开发环境部署了多套系统&#xff0c;并且使用了同一套登入鉴权组件&#xff0c;存入的TokenStore也是相同的Redis库&#xff1b; 问题描述&原因分析 由于是做的不同项目&#xff0c;group等组织机构不同&#xff0c;导致多系统若是有存储相同用…...

【QT】深入理解 Qt 中的对象树:机制、用途与最佳实践

深入理解 Qt 中的对象树&#xff1a;机制、用途与最佳实践 在使用 Qt 编程时&#xff0c;你是否注意到很多对象可以设置“父对象”&#xff1f;比如&#xff1a; QPushButton* btn new QPushButton(parentWidget);这不是简单的层级结构&#xff0c;而是 Qt 强大而优雅的 对象…...

基于FPGA的血氧和心率蓝牙监测系统设计-max30102

文章目录 前言一、芯片手册分析二、串口接口的血氧模块使用讲解三、仿真时序分析四、代码分析1.蓝牙数据发送2.心率数据采集 总结 前言 本产品的核心是基于心率传感器的智能心率监测系统&#xff0c;通过硬件端的心率传感器获取人体的心率和血氧浓度等信息&#xff0c;并进行实…...

华为首款鸿蒙电脑正式亮相,开启国产操作系统新篇章

5 月 8 日&#xff0c;华为在深圳举办鸿蒙电脑技术与生态沟通会&#xff0c;正式推出了备受瞩目的首款鸿蒙电脑&#xff0c;这一重大举措标志着国产操作系统在个人电脑&#xff08;PC&#xff09;领域实现了关键突破&#xff0c;为行业发展注入了新的活力。​ 历经五年打磨&…...

Docker部署常见应用之Superset

文章目录 使用 Docker 部署使用 Docker Compose 部署参考文章 以下是使用 Docker 部署 Superset 并将存储配置为 MySQL 的详细步骤&#xff1a; 使用 Docker 部署 获取Superset镜像: 使用Docker从官方仓库拉取Superset镜像&#xff1a;docker pull apache/superset:4.0.0创建 …...

触想CX-3588工控主板应用于移动AI数字人,赋能新型智能交互

一、行业发展背景 随着AI智能、自主导航和透明屏显示等技术的不断进步&#xff0c;以及用户对“拟人化”、“沉浸式”交互体验的期待&#xff0c;一种新型交互终端——“移动AI数字人”正在加速实现规模化商用。 各大展厅展馆、零售导购、教学政务甚至家庭场景中&#xff0c;移…...

关系代数操作之复杂扩展操作

除&#xff08;Division&#xff09; 定义&#xff1a;关系R为n度关系&#xff0c;关系S为m度关系&#xff0c;m<n,记作RS&#xff0c;关系是K&#xff08;n-m&#xff09;度关系 数学描述&#xff1a; 相当于&#xff08;RS&#xff09;*S在R中的元组 外连接&#xff08…...

STM32G070xx将Flash页分块方式存储,固定数据块存储,实现一次擦除多次写入

STM32G070xx将Flash页分块方式存储&#xff0c;固定数据块存储&#xff0c;实现一次擦除多次写入 参考例程例程说明一、存储区数据结构二、读取存储区数据三、写入存储区数据四、测试函数五、测试结果 参考例程 STM32G0xx使用LL库将Flash页分块方式存储数据实现一次擦除可多次…...

V4L2应用程序开发-- 控制流程

使用摄像头时&#xff0c;我们可以调整很多参数&#xff0c;比如&#xff1a; 对于视频流本身&#xff1a; 设置格式&#xff1a;比如V4L2_PIX_FMT_YUYV、V4L2_PIX_FMT_MJPEG、V4L2_PIX_FMT_RGB565 设置分辨率&#xff1a;1024*768等 对于控制部分&#xff1a; 调节亮度 调…...

《大数据技术之Scala》

这是一篇关于大数据技术中Scala语言的基础教程文章&#xff0c;主要介绍了Scala语言的发展历史、与Java的关系、语言特点、环境搭建、插件安装、编程基础、变量和数据类型、运算符、流程控制、函数式编程、面向对象编程、集合操作、模式匹配、异常处理、隐式转换和泛型等核心内…...

使用thymeleaf模版导出swagger3的word格式接口文档

1.pom配置 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.8.RELEASE</version></parent><properties><skipTests>true</skipTests&g…...

Android RecyclerView自带的OnFlingListener,Kotlin

Android RecyclerView自带的OnFlingListener&#xff0c;Kotlin Android启动应用时屏蔽RecyclerView滑动&#xff0c;延时后再允许滑动&#xff0c;Kotlin-CSDN博客 使用了GestureDetectorRecyclerView的setOnTouchListener检测用户的快滑fling事件。发现RecyclerView也自带了监…...

STM32+安信可Ai-WB2-12F连接阿里云物联网平台

第一步&#xff1a;在阿里云物联网平台创建设备 具体操作流程如下 第二步&#xff1a;生成个人client_id,用户名和密码 打开该软件sign.html 将刚才复制的信息粘贴进去 生成自己的client_id,用户名和密码 第三步&#xff1a;打开MQTTfx软件 电机connect旁边的配置&#xff0…...

Python实现中文数字与阿拉伯数字映射生成器(支持0-9999)

文章目录 1. 引言2. 需求分析‌3. 核心实现思路‌4. 完整代码实现‌ 1. 引言 在中文文本处理和自然语言处理(NLP)应用中&#xff0c;经常需要将中文数字转换为阿拉伯数字。本文将介绍如何使用Python根据用户从控制台输入的数字范围&#xff0c;生成相应的中文数字到阿拉伯数字…...

链表的面试题4之合并有序链表

这篇文章我们继续来讲链表中很经典的面试题&#xff1a;合并有序链表。 目录 迭代 递归 我们首先来看一下这张图片里面的要求&#xff0c;给你两个链表&#xff0c;要求把他们按照从小到大的方式排列。 这里涉及到几个问题&#xff0c;首先&#xff0c;我们的头节点是不是要…...

CTF - PWN之ORW记录

CTF - Pwn之ORW记录https://mp.weixin.qq.com/s/uiRtqCSopn6U6NqyKJ8I7Q...

mission planner烧录ardupilot固件报错死机

问题 烧录自己编译的固件&#xff0c;upload done成功后&#xff0c;又跳出以下提示 &#xff0c;返回重新烧录仍然报错 解决 先烧录官方稳定的固件然后使用mission planner连接&#xff0c;此时可能会反复识别串口&#xff0c;因为会死机反复重启&#xff0c;导致灯闪烁又…...

单片机嵌入式滤波算法库

kw_ucFiltering库说明 本科针对常用的滤波算法进行汇总&#xff0c;主要包括&#xff1a; 一阶滤波算法 平滑滤波 中位值滤波 限幅 卡尔曼滤波 截至目前&#xff08;20250508&#xff09;滤波算法持续更新中。 本库开源连接地址&#xff1a;gitee连接 一阶滤波算法实现 原理…...

CAS、CAS自旋、CAS自旋锁、CLH锁与Java AQS:深入理解并发编程核心机制

CAS、CAS自旋、CAS自旋锁、CLH锁与Java AQS&#xff1a;深入理解并发编程核心机制 1. CAS&#xff08;Compare and Swap&#xff09; 什么是CAS&#xff1f; CAS&#xff08;Compare and Swap&#xff09;是一种无锁&#xff08;Lock-Free&#xff09;的原子操作&#xff0c;…...

《运维那些事儿》专栏总目录(持续更新)

《运维那些事儿》专栏以Linux系统为基础&#xff0c;分享作者十年运维生涯中运用到的关键技术要点。本专栏涵盖消息中间件、数据中间件、数据库、虚拟化、Web服务器、高可用架构等运维工作中涉及到的相关内容&#xff0c;每周持续交叉更新一篇高质量技术博文。学生可用于了解、…...

鸿蒙NEXT开发动画案例4

1.创建空白项目 2.Page文件夹下面新建Spin.ets文件&#xff0c;代码如下&#xff1a; /*** TODO SpinKit动画组件 - 双粒子旋转缩放动画* author: CSDN-鸿蒙布道师* since: 2025/05/08*/ ComponentV2 export struct SpinFour {// 参数定义Require Param spinSize: number 36…...

【Linux学习笔记】基础IO之理解文件

【Linux学习笔记】基础IO之理解文件 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;Linux学习笔记 前言 哈喽&#xff0c;各位小伙伴大家好!上期我们讲了进程替换 今天我们讲的是基础IO之理解文件。话不多说&#xff0c;我们进入正题&#…...

动态计算el-table高度

form、搜索框、底部导航栏设置class <el-table :height"tableHeight" /> // 计算表格高度的计算属性 const tableHeight ref(0); proxy.toTableHeight((res)>{tableHeight.value res; });tableHeight.js import { nextTick } from vue;export fun…...

【Linux系列】目录大小查看

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

数据结构*二叉树

树 树是一种非线性数据结构。 这就是抽象的树的结构。 对于一棵树来说&#xff0c;有N个结点&#xff0c;就有N-1条边 其中有许多概念&#xff1a; 根结点&#xff1a;对于上图来说就是A 子树&#xff1a;就是结点下面分开的部分。例如&#xff1a;A的子树就是以B为根结点的…...

RESTful

一&#xff1a;简介 定义 &#xff08;1&#xff09;访问网络资源的格式 &#xff08;2&#xff09;优点 &#xff08;3&#xff09;区分操作 &#xff08;4&#xff09;注意事项...

人工智能的自动驾驶新纪元:端到端智能系统挑战与前沿探索方案

一、引言:从模块化到端到端的范式革命 (一)自动驾驶技术演进的三个时代 自动驾驶技术自诞生以来,经历了从机械化辅助到智能化决策的漫长演进。早期,以定速巡航为代表的 1.0 时代,仅实现了简单的速度控制,车辆仍需驾驶员全程主导操控。随着传感器与算法发展,进入 2.0 时…...

第四章 OpenCV篇—图像梯度与边缘检测—Python

目录 一.Sobel算子 二.Scharr算子与laplacian算子 三.Canny边缘检测 1.高斯滤波器 2.梯度和方向 3.非极大值抑制 4.双阈值检测 此章节主要讲解图像梯度计算方法和边缘检测算法&#xff0c;分别主要是&#xff1a;sobel算子、scharr与lapkacian算子、canny边缘检测流程。…...

幂等的几种解决方案以及实践

目录 什么是幂等&#xff1f; 解决幂等的常见解决方案&#xff1a; 唯一标识符案例 数据库唯一约束 案例 乐观锁案例 分布式锁&#xff08;Distributed Locking&#xff09; 实践精选方案 首先 为什么不直接使用分布式锁呢&#xff1f; 自定义实现幂等组件&#xff01…...

拥塞控制 流量控制 区别

对比项拥塞控制流量控制关注对象整个网络 是否过载接收方主机 是否处理不过来控制目标避免网络路由器、链路拥塞避免发送方发太快&#xff0c;接收方来不及处理发生原因网络中有太多数据包&#xff0c;引起排队、丢包接收方缓存能力有限实现方式基于网络状态动态调整发送速率基…...

AWS VPC架构师指南:从零设计企业级云网络隔离方案

一、VPC核心概念解析 1.1 核心组件 VPC&#xff1a;逻辑隔离的虚拟网络&#xff0c;可自定义IPv4/IPv6地址范围&#xff08;CIDR块&#xff09; 子网&#xff08;Subnet&#xff09;&#xff1a; 公有子网&#xff1a;绑定Internet Gateway&#xff08;IGW&#xff09;&#…...

[逆向工程]什么是DLL注入(二十二)

[逆向工程]什么是DLL注入&#xff08;二十二&#xff09; 引言 DLL注入&#xff08;DLL Injection&#xff09; 是Windows系统下一种重要的进程控制技术&#xff0c;广泛应用于软件调试、功能扩展、安全检测等领域。然而&#xff0c;它也是一把“双刃剑”——恶意软件常借此实…...

极简远程革命:节点小宝 — 无公网IP的极速内网穿透远程解决方案

极简远程革命&#xff1a;节点小宝&#xff0c;让家庭与职场无缝互联 ——打破公网桎梏&#xff0c;重塑数字生活新体验 关键词&#xff1a;节点小宝&#xff5c;内网穿透&#xff5c;P2P直连&#xff5c;家庭网络&#xff5c;企业协作&#xff5c;智能组网节点小宝&#xff5…...

Vue生命周期脚手架工程Element-UI

一 Vue2.x生命周期 每个vue实例再被创建时都要经过一系列的初始化过程&#xff1a; 创建实例 装载模板 渲染模板等等 vue为生命周期中的每个状态都设置了钩子函数&#xff08;监听函数&#xff09;。每个vue实例处于不同的生命周期时&#xff0c;对应的函数就会触发调用 https:…...

LeetCode[226] 翻转二叉树

思路&#xff1a; 使用递归&#xff0c;归根结底还是左右节点互相倒&#xff0c;那么肯定需要一个temp节点在中间传递&#xff0c;最后就是递归&#xff0c;没什么说的 代码&#xff1a; /*** Definition for a binary tree node.* public class TreeNode {* int …...

ConcurrentHashMap解析

ConcurrentHashMap解析 以下是对 Java 8 及以后版本 ConcurrentHashMap 源码的深入解析&#xff0c;涵盖其底层数据结构、并发控制机制、核心操作流程、扩容与迁移、树化/退化策略&#xff0c;以及性能特性。总体来说&#xff0c;ConcurrentHashMap 在 JDK 8 中摒弃了原有的 S…...

windows10 系统显示mov文件格式缩略图

最近做视频剪辑&#xff0c;有些mov格式文件&#xff0c;但是尝试用各种播放器默认播放&#xff0c;都没有缩略图可看&#xff0c; 很影响查看。 遂选择了个插件&#xff0c;来在windows10系统显示mov文件的缩略图。 1.下载安装 K-Lite Codec Pack &#xff08;安装时一路Ne…...

力扣智慧思想小题,目录力扣.跳跃游戏(思想很重要)力扣.跳跃游戏II(还是思想)力扣.分发糖果力扣151.反转字符串中的单词力扣.轮转数组

目录 力扣.跳跃游戏(思想很重要) 力扣.跳跃游戏II&#xff08;还是思想) 力扣.分发糖果 力扣151.反转字符串中的单词 力扣.轮转数组 字符 a97 A65; JRE:Java运行时候的环境 JDK: JAVA开发套件(工具包) java原本是.java文件&#xff0c;编译成.class字节码文件 八种基本数据…...

【LangChain基础系列】深入全面掌握文本分类

文本分类是自然语言处理领域中的一个重要任务,旨在将文本数据自动归类到预定义的类别中。它是实现信息检索、智能推荐、情感分析等应用的基础技术之一。 应用场景 1. 垃圾邮件过滤 &#xff1a;自动识别并过滤垃圾邮件。 2. 情感分析 &#xff1a;分析用户评论或社交媒体内容…...

AI赋能高频PCB信号完整性优化

在5G通信、自动驾驶、卫星导航等高频技术快速迭代的今天&#xff0c;**信号完整性&#xff08;SI&#xff09;**已成为高频PCB设计的核心挑战。如何在高密度布线、复杂电磁环境中实现信号的精准传输&#xff1f;猎板PCB通过**AI驱动设计优化**、**材料与工艺创新**以及**智能化…...