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

java每日精进 4.26【多租户之过滤器及请求处理流程】

一月没更,立誓以后断更三天我就是狗!!!!!!!!

研究多租户框架中一条请求的处理全流程

@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserService userService;@PostMapping("/save")public boolean save(@RequestBody User user) {return userService.save(user);}@GetMapping("/get")public List<User> getAll() {return userService.list();}@GetMapping("/getById")public User getById(@RequestParam Long id) {return userService.getById(id);}
}

以getById接口为例

1. 请求接收

  • 客户端请求:假设客户端发送以下 GET 请求:

  • GET /users/getById?id=123 HTTP/1.1 Host: localhost:8080 tenant-id: 1 Authorization: Bearer <token>

  • Tomcat 接收:Spring Boot 嵌入的 Tomcat 服务器监听端口(默认 8080),接收请求并解析 HTTP 报文。
  • DispatcherServlet:Tomcat 将请求交给 Spring 的 DispatcherServlet,它负责路由和处理所有 HTTP 请求。

2. 执行顺序

  1. TenantContextWebFilter (Order = WebFilterOrderEnum.TENANT_CONTEXT_FILTER)

  2. Spring Security 过滤器链:

    • DisableEncodeUrlFilter

    • WebAsyncManagerIntegrationFilter

    • SecurityContextPersistenceFilter

    • HeaderWriterFilter

    • LogoutFilter

    • RequestCacheAwareFilter

    • SecurityContextHolderAwareRequestFilter

    • AnonymousAuthenticationFilter

    • SessionManagementFilter

  3. TenantSecurityWebFilter (继承自 ApiRequestFilter)

  4. ExceptionTranslationFilter

  5. FilterSecurityInterceptor

阶段一:TenantContextWebFilter 处理

public class TenantContextWebFilter extends OncePerRequestFilter {protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {System.out.println("+++++tenant-id:"+request.getHeader("tenant-id")+"+++++");// 从请求头获取租户IDLong tenantId = WebFrameworkUtils.getTenantId(request);if (tenantId != null) {TenantContextHolder.setTenantId(tenantId); // 设置到线程局部变量}try {chain.doFilter(request, response); // 继续过滤器链} finally {TenantContextHolder.clear(); // 清理线程局部变量}}
}
  • 从请求头中提取 tenant-id 并设置到 TenantContextHolder 线程局部变量中

  • 确保请求处理完成后清理线程局部变量,避免内存泄漏

阶段二:Spring Security 基础过滤器

这些过滤器主要处理安全相关的基础功能:

  • SecurityContextPersistenceFilter: 从Session中加载安全上下文

  • AnonymousAuthenticationFilter: 如果用户未认证,创建一个匿名身份

  • 其他过滤器处理会话、头信息等基础安全功能

+-------------------------------+
| DisableEncodeUrlFilter         |
| 禁用URL编码过滤器:用于禁用对URL的编码处理 |
+-------------------------------+|V
+-------------------------------+
| WebAsyncManagerIntegrationFilter |
| 异步管理器集成过滤器:将Spring的异步管理与安全上下文集成 |
+-------------------------------+|V
+-------------------------------+
| SecurityContextPersistenceFilter |
| 安全上下文持久化过滤器:在请求处理前后管理安全上下文的持久化 |
+-------------------------------+|V
+-------------------------------+
| HeaderWriterFilter             |
| 头部写入过滤器:在响应中添加安全相关的HTTP头部信息 |
+-------------------------------+|V
+-------------------------------+
| LogoutFilter                   |
| 注销过滤器:处理用户的注销请求,清除相关的安全信息 |
+-------------------------------+|V
+-------------------------------+
| RequestCacheAwareFilter        |
| 请求缓存感知过滤器:处理请求的缓存,用于重定向后恢复请求 |
+-------------------------------+|V
+-------------------------------+
| SecurityContextHolderAwareRequestFilter |
| 安全上下文持有者感知请求过滤器:包装请求对象,使其能访问安全上下文 |
+-------------------------------+|V
+-------------------------------+
| AnonymousAuthenticationFilter  |
| 匿名认证过滤器:在没有认证信息时,为请求提供匿名身份 |
+-------------------------------+|V
+-------------------------------+
| SessionManagementFilter        |
| 会话管理过滤器:管理用户会话,处理会话过期等问题 |
+-------------------------------+|V
+-------------------------------+
| ExceptionTranslationFilter     |
| 异常转换过滤器:将安全异常转换为Spring Security能处理的异常 |
+-------------------------------+|V
+-------------------------------+
| FilterSecurityInterceptor      |
| 过滤器安全拦截器:对请求进行最终的安全检查和授权控制 |
+-------------------------------+
阶段三:TenantSecurityWebFilter 处理

作用

  1. 检查登录用户是否有权限访问请求的租户

  2. 对于非忽略URL,必须包含有效的租户ID

  3. 校验租户状态(是否禁用、过期等)

public class TenantSecurityWebFilter extends ApiRequestFilter {protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {Long tenantId = TenantContextHolder.getTenantId();// 1. 检查登录用户租户权限User user = SecurityFrameworkUtils.getLoginUser();if (user != null) {if (tenantId == null) {// 使用登录用户的租户IDtenantId = user.getTenantId();TenantContextHolder.setTenantId(tenantId);} else if (!user.getTenantId().equals(tenantId)) {// 租户不匹配,越权访问log.error("越权访问");ServletUtils.writeJSON(response, CommonResult.error(...));return;}}// 2. 非忽略URL需校验租户if (!isIgnoreUrl(request)) {if (tenantId == null) {// 未传递租户IDlog.error("未传递租户编号");ServletUtils.writeJSON(response, CommonResult.error(...));return;}// 3. 校验租户状态try {tenantFrameworkService.validTenant(tenantId);} catch (Throwable ex) {CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, ex);ServletUtils.writeJSON(response, result);return;}} else {// 忽略URL处理if (tenantId == null) {TenantContextHolder.setIgnore(true); // 标记忽略租户}}chain.doFilter(request, response);}
}
阶段四:Controller 处理
  1. MyBatis-Plus 会调用 TenantLineInnerInterceptor

  2. 拦截器检查 TenantDatabaseInterceptor 的规则:

    • 检查表是否在忽略列表中

    • 如果没有忽略,自动添加租户条件 WHERE tenant_id = ?

1.多租户配置类YudaoTenantAutoConfiguration:
@AutoConfiguration
@ConditionalOnProperty(prefix = "moyun.tenant", value = "enable", matchIfMissing = true)
@EnableConfigurationProperties(TenantProperties.class)
public class YudaoTenantAutoConfiguration {@Beanpublic TenantLineInnerInterceptor tenantLineInnerInterceptor(TenantProperties properties) {return new TenantLineInnerInterceptor(new TenantDatabaseInterceptor(properties));}@Beanpublic FilterRegistrationBean<TenantContextWebFilter> tenantContextWebFilter() {FilterRegistrationBean<TenantContextWebFilter> registrationBean = new FilterRegistrationBean<>();registrationBean.setFilter(new TenantContextWebFilter());registrationBean.setOrder(WebFilterOrderEnum.TENANT_CONTEXT_FILTER);return registrationBean;}
}

作用

  • 条件化装配多租户相关组件

  • 注册两个核心组件:

    • TenantLineInnerInterceptor: MyBatis Plus SQL拦截器,自动拼接租户条件或判断是否跳过租户判断拼接;

    • TenantContextWebFilter: 租户上下文过滤器,将租户id设置到上下文;

2. TenantContextHolder (租户上下文持有者)
/*** 多租户上下文 Holder** @author 芋道源码*/
public class TenantContextHolder {/*** 当前租户编号*/private static final ThreadLocal<Long> TENANT_ID = new TransmittableThreadLocal<>();/*** 是否忽略租户*/private static final ThreadLocal<Boolean> IGNORE = new TransmittableThreadLocal<>();/*** 获得租户编号** @return 租户编号*/public static Long getTenantId() {return TENANT_ID.get();}/*** 获得租户编号。如果不存在,则抛出 NullPointerException 异常** @return 租户编号*/public static Long getRequiredTenantId() {Long tenantId = getTenantId();if (tenantId == null) {throw new NullPointerException("TenantContextHolder 不存在租户编号!可参考文档:"+ DocumentEnum.TENANT.getUrl());}return tenantId;}public static void setTenantId(Long tenantId) {TENANT_ID.set(tenantId);}public static void setIgnore(Boolean ignore) {IGNORE.set(ignore);}/*** 当前是否忽略租户** @return 是否忽略*/public static boolean isIgnore() {return Boolean.TRUE.equals(IGNORE.get());}public static void clear() {TENANT_ID.remove();IGNORE.remove();}}

TenantContextHolder 是一个用于管理多租户系统中租户信息的工具类,它使用 ThreadLocal 来存储当前线程的租户上下文信息。

主要作用

  1. 存储当前租户ID:在同一个线程中共享租户ID

  2. 控制租户过滤:可以临时忽略租户过滤条件

  3. 线程安全:使用 TransmittableThreadLocal 保证线程安全且支持线程池场景

核心功能说明

  • getTenantId(): 获取当前租户ID(可能为null)

  • getRequiredTenantId(): 获取当前租户ID(如果不存在则抛出异常)

  • setTenantId(Long): 设置当前租户ID

  • isIgnore(): 检查是否忽略租户过滤

  • setIgnore(Boolean): 设置是否忽略租户过滤

  • clear(): 清理当前线程的租户上下文

为什么用 TransmittableThreadLocal?

与普通ThreadLocal的区别:

特性ThreadLocalTransmittableThreadLocal
线程隔离
线程池支持❌(会丢失上下文)✅(自动传递)
异步任务支持
性能开销略高(需注册TTL修饰的线程池)

实际工作流程示例

// 主线程设置值
TenantContextHolder.setTenantId(1L);  // TENANT_ID线程变量=1
TenantContextHolder.setIgnore(false); // IGNORE线程变量=false// 当新线程/线程池任务执行时:
// 普通ThreadLocal会丢失这两个值
// TransmittableThreadLocal会自动传递这两个值// 子线程中仍然可以获取:
Long tenantId = TenantContextHolder.getTenantId(); // 得到1
boolean ignore = TenantContextHolder.isIgnore();  // 得到false

为什么要这样设计?

  1. 线程安全:避免使用全局变量导致的多线程冲突

  2. 调用链透明:在方法调用链中无需显式传递tenantId参数

  3. 灵活控制:可以通过IGNORE临时绕过租户隔离

  4. 兼容异步:支持线程池、异步任务等复杂场景

注意事项

  1. 必须成对使用:set后必须clear/remove,否则会导致:

    • 内存泄漏(特别是线程池场景)

    • 租户信息错乱(后续请求可能读到错误的tenantId)

  2. 默认值规则

    • TENANT_ID.get() 未设置时返回null

    • IGNORE.get() 未设置时返回null,isIgnore()做了null安全处理(返回false)

  3. 性能影响

    • TransmittableThreadLocal比普通ThreadLocal稍慢

    • 在极高并发场景需要考虑性能损耗

3. TenantDatabaseInterceptor (数据库拦截器)
  • 实现MyBatis Plus的多租户SQL改写

  • 根据配置决定哪些表需要忽略租户条件

public class TenantDatabaseInterceptor implements TenantLineHandler {private final Set<String> ignoreTables = new HashSet<>();@Overridepublic Expression getTenantId() {return new LongValue(TenantContextHolder.getRequiredTenantId());}@Overridepublic boolean ignoreTable(String tableName) {return TenantContextHolder.isIgnore() || ignoreTables.contains(SqlParserUtils.removeWrapperSymbol(tableName));}
}
阶段五:响应返回
  • 响应通过过滤器链反向返回

  • TenantContextWebFilter 的 finally 块清理租户上下文

完整请求处理流程(以/users/getById为例)

阶段一:过滤器初始化

  1. YudaoTenantAutoConfiguration 被Spring加载

    • 创建 TenantLineInnerInterceptor 并注册到MyBatis

    • 注册 TenantContextWebFilter 到Servlet容器

阶段二:请求处理

  1. TenantContextWebFilter

    • 从请求头提取 tenant-id

    • 设置到 TenantContextHolder

    • System.out.println("+++++tenant-id:"+request.getHeader("tenant-id")+"+++++");

  2. Spring Security 过滤器链

    • 执行基础安全处理(认证、会话管理等)

  3. TenantSecurityWebFilter

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) {// 1. 检查登录用户权限// 2. 校验租户ID是否存在(非忽略URL)// 3. 通过tenantFrameworkService校验租户状态
    }
  4. Controller处理

    @GetMapping("/getById")
    public User getById(@RequestParam Long id) {return userService.getById(id);
    }
  5. MyBatis Plus拦截器

    • TenantLineInnerInterceptor 拦截SQL执行

    • 调用 TenantDatabaseInterceptor:

      • 检查 ignoreTable() 决定是否添加租户条件

      • 如需添加,调用 getTenantId() 获取当前租户ID

  6. 响应返回

    • 过滤器链反向执行

    • TenantContextWebFilter 清理线程局部变量

关键顺序解析

  1. 租户上下文设置必须最先执行

    • TenantContextWebFilter 设置了最高优先级(最早执行)

    • 确保后续过滤器能获取正确的租户信息

  2. 安全校验在上下文设置之后

    • TenantSecurityWebFilter 依赖已设置的租户上下文

    • 在Spring Security基础过滤器之后执行

  3. SQL拦截最后执行

    • MyBatis拦截器不是Servlet Filter

    • 在Service层执行SQL时触发

相关文章:

java每日精进 4.26【多租户之过滤器及请求处理流程】

一月没更&#xff0c;立誓以后断更三天我就是狗&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 研究多租户框架中一条请求的处理全流程 RestController RequestMapping("/users") public class UserControlle…...

【学习笔记】Stata

一、Stata简介 Stata 是一种用于数据分析、数据管理和图形生成的统计软件包&#xff0c;广泛应用于经济学、社会学、政治科学等社会科学领域。 二、Stata基础语法 2.1 数据管理 Stata 支持多种数据格式的导入&#xff0c;包括 Excel、CSV、文本文件等。 从 Excel 文件导入…...

[MySQL数据库] 事务与锁

&#x1f338;个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 &#x1f3f5;️热门专栏: &#x1f9ca; Java基本语法(97平均质量分)https://blog.csdn.net/2301_80050796/category_12615970.html?spm1001.2014.3001.5482 &#x1f355; Collection与…...

Rule.issuer(通过父路径配置loader处理器)

说明 正常在设置loader配置规则时&#xff0c;都是通过文件后缀来配置的 issuer的作用是可以通过父级的路径&#xff0c;设置生效的匹配规则 与rule的差别 test: 匹配当前模块的路径&#xff08;如 .css 文件&#xff09; issuer: 匹配引入当前模块的父模块的路径&#xff0…...

MyBatis 插件开发的完整详细例子

MyBatis 插件开发的完整详细例子 MyBatis 插件&#xff08;Interceptor&#xff09;允许开发者在已映射语句执行过程中的某一点进行拦截调用&#xff0c;从而实现自定义逻辑。以下是一个完整的 MyBatis 插件开发示例&#xff0c;涵盖所有使用场景&#xff0c;并附有详细注释和总…...

树状数组底层逻辑探讨 / 模版代码-P3374-P3368

目录 功能 实现 Q:但是&#xff0c;c[x]左端点怎么确定呢&#xff1f; Q:那么为什么要以二进制为基础呢&#xff1f; Q:为什么是补码 - &#xff1f; 区间查询 树形态 性质1.对于x<y,要么c[x]和c[y]不交&#xff0c;要么c[x]包含于c[y] 性质2.c[x] 真包含 于c[x l…...

Eigen库入门

Eigen是一个C模板库&#xff0c;用于线性代数运算&#xff0c;包括矩阵、向量、数值求解和相关算法。它以其高性能、易用性和丰富的功能而闻名。 安装与配置 Eigen是一个纯头文件库&#xff0c;无需编译&#xff0c;只需包含头文件即可使用。 下载Eigen&#xff1a;从官方网站…...

力扣HOT100——102.二叉树层序遍历

给你二叉树的根节点 root &#xff0c;返回其节点值的 层序遍历 。 &#xff08;即逐层地&#xff0c;从左到右访问所有节点&#xff09;。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;[[3],[9,20],[15,7]] /*** Definition for a bi…...

客户案例 | 光热+数智双驱动!恒基能脉的数字化协同与技术创新实践

光热先锋 智领未来 恒基能脉新能源科技有限公司: 创新驱动&#xff0c;智造光热未来行业领航者 恒基能脉新能源科技有限公司是一家立足于光热发电核心技术产品&#xff0c;专注于“光热” 多能互补项目的国家高新技术企业&#xff0c;其核心产品定日镜广泛应用于光热发电、储…...

第十六周蓝桥杯2025网络安全赛道

因为只会web&#xff0c;其他方向都没碰过&#xff0c;所以只出了4道 做出来的&#xff1a; ezEvtx 找到一个被移动的文件&#xff0c;疑似被入侵 提交flag{confidential.docx}成功解出 flag{confidential.docx} Flowzip 过滤器搜索flag找到flag flag{c6db63e6-6459-4e75-…...

构造函数有哪些种类?

构造函数用于对象的初始化。 1.默认构造函数&#xff1a;没有参数&#xff0c;执行默认的初始化操作&#xff1b; 2.参数化构造函数&#xff1a;传入参数的构造函数&#xff0c;允许构造函数初始化成员变量&#xff1b; 3.拷贝构造函数&#xff1a;将同一类型的实例化对象作…...

第十六届蓝桥杯大赛软件赛省赛 C/C++ 大学B组 [京津冀]

由于官方没有公布题目的数据, 所以代码仅供参考 1. 密密摆放 题目链接&#xff1a;P12337 [蓝桥杯 2025 省 AB/Python B 第二场] 密密摆放 - 洛谷 题目描述 小蓝有一个大箱子&#xff0c;内部的长宽高分别是 200、250、240&#xff08;单位&#xff1a;毫米&#xff09;&…...

关于调度策略的系统性解析与物流机器人应用实践

关于调度策略的系统性解析与物流机器人应用实践 一、调度策略的定义与核心目标 调度策略是用于在复杂环境中协调资源分配、任务排序及路径规划的决策框架,旨在通过优化资源利用率和任务执行效率,实现系统整体性能的最优解。其核心目标包括: 动态适应性:应对实时变化(如订…...

探索具身智能协作机器人:技术、应用与未来

具身智能协作机器人&#xff1a;概念与特点 具身智能协作机器人&#xff0c;简单来说&#xff0c;就是将人工智能技术与机器人实体相结合&#xff0c;使其能够在与人类共享的空间中进行安全、高效协作的智能设备。它打破了传统机器人只能在预设环境中执行固定任务的局限&#…...

毕业项目-Web入侵检测系统

1. 项目简介 系统主要分为两大板块&#xff1a;靶标站点和入侵检测系统。靶标站点是系统的被监测对象&#xff0c;而入侵检测系统则是用于检测靶标站点的流量是否存在异常&#xff0c;以及在检测到异常时进行告警。 入侵检测系统的实现过程简述如下&#xff1a; 数据获取与分…...

【分布式系统中的“瑞士军刀”_ Zookeeper】二、Zookeeper 核心功能深度剖析与技术实现细节

在分布式系统的复杂生态中&#xff0c;Zookeeper 凭借其强大的核心功能&#xff0c;成为保障系统稳定运行的关键组件。上篇文章我们了解了 Zookeeper 的基础概念与安装配置&#xff0c;本文将继续深入剖析 Zookeeper 的核心功能&#xff0c;包括分布式锁、配置管理、命名服务和…...

前端学习笔记(四)自定义组件控制自己的css

1、前言及背景 自己写的一个组件有至少3个页面在使用&#xff0c;组件中的部分文字颜色需要统一修改需要根据一个状态字段来显示不同颜色且不希望受父组件影响 注意&#xff1a;博主学习vue截止目前也就半年&#xff0c;如有知识错误之处还请指出不胜感激&#xff0c;祝学习开…...

从描述语言,非功能性需求,需求和架构的一致性三个方面,说明软件需求到架构的映射存在哪些难点

软件需求到架构的映射是软件工程中的关键环节&#xff0c;其难点主要体现在描述语言差异、非功能性需求的复杂性以及需求与架构的一致性维护三个方面。以下是具体分析&#xff1a; 1. 描述语言的差异 难点&#xff1a;需求与架构使用不同的抽象语言描述&#xff0c;导致语义鸿…...

linux blueZ 第五篇:高阶优化与性能调优——蓝牙吞吐、延迟与功耗全攻略

本篇面向已有实战经验的读者,深入探讨 Classic Bluetooth 与 BLE 在 BlueZ 平台上的性能优化和调优方法,包括连接参数、MTU 调整、PHY 选择、缓存管理、并发策略,以及 HCI 抓包、功耗测量与自动化基准测试,助你打造高吞吐、低延迟、超低功耗的蓝牙应用。 目录 为何要做性能…...

linux的例行性工作(at)

使用场景&#xff1a; 生活中&#xff0c;我们有太多场景需要使用到闹钟&#xff0c;比如早上 7 点起床&#xff0c;下午 4 点开会&#xff0c;晚上 8 购物&#xff0c;等等 在 Linux 系统里&#xff0c;我们同样也有类似的需求。比如我们想在凌晨 1 点将文件上传服务器&#…...

JVM考古现场(二十六):执剑人·降维打击的终极审判

楔子&#xff1a;二向箔的颤动——当修真文明遭遇降维打击 "警告&#xff01;老年代发生维度坍缩&#xff01;"我腰间悬挂的昆仑镜突然迸发幽蓝光芒&#xff0c;终南山巅的河图洛书大阵中&#xff0c;GC日志正以《奇门遁甲》的格局疯狂演化&#xff1a; // 降维打击…...

腾讯云物联网平台

文档&#xff1a;物联网开发平台 MQTT.fx 快速接入物联网开发平台_腾讯云...

Unity之基于MVC的UI框架-含案例

Unity之基于MVC的UI框架-含案例 使用案例&#xff1a;类《双人成行》3D动作益智冒险类双人控制游戏开发教程 资源地址&#xff1a;https://learn.u3d.cn/tutorial/3d-adventure-william-anna 一、MVC框架概览 本框架以MVC的方式搭建&#xff0c;以View视口的方式展现数据&am…...

【Token系列】01 | Token不是词:GPT如何切分语言的最小单元

文章目录 01 | Token不是词&#xff1a;GPT如何切分语言的最小单元&#xff1f;一、什么是 Token&#xff1f;二、Token 是怎么来的&#xff1f;——BPE算法原理BPE核心步骤&#xff1a; 三、为什么不直接用词或字符&#xff1f;四、Token切分的实际影响五、中文Token的特殊性六…...

C++学习之路,从0到精通的征途:List类的模拟实现

目录 一.list的介绍 二.list的接口实现 1.结点 2.list结构 3.迭代器 &#xff08;1&#xff09;begin &#xff08;2&#xff09;end 4.修改 &#xff08;1&#xff09;insert &#xff08;2&#xff09;push_back &#xff08;3&#xff09;push_front &#xff0…...

Java大师成长计划之第4天:Java中的泛型

&#x1f4e2; 友情提示&#xff1a; 本文由银河易创AI&#xff08;https://ai.eaigx.com&#xff09;平台gpt-4o-mini模型辅助创作完成&#xff0c;旨在提供灵感参考与技术分享&#xff0c;文中关键数据、代码与结论建议通过官方渠道验证。 在现代软件开发中&#xff0c;类型安…...

计算机学报 2024年 区块链论文 录用汇总 附pdf下载

计算机学报 Year&#xff1a;2024 1 Title: 区块链中的公钥密码&#xff1a;设计、分析、密评与展望 Authors: Key words: 区块链&#xff1b;公钥密码算法&#xff1b;算法设计&#xff1b;复杂性分析&#xff1b;密评 Abstract: 比特币的成功&#xff0c;吸引了人们研…...

【Castle-X机器人】三、紫外消杀模块安装与调试

持续更新。。。。。。。。。。。。。。。 【Castle-X机器人】紫外消杀模块安装与调试 三、紫外消杀模块安装与调试2.1 安装2.2 调试2.2.1 紫外消杀模块话题2.2.2 测试 三、紫外消杀模块安装与调试 2.1 安装 使用相应工具将紫外消杀模块固定在Castle-X机器人底盘 2.2 调试 2.2…...

精益数据分析(29/126):深入剖析电子商务商业模式

精益数据分析&#xff08;29/126&#xff09;&#xff1a;深入剖析电子商务商业模式 在创业和数据分析的学习道路上&#xff0c;我们始终在探索如何更精准地把握商业规律&#xff0c;提升业务的竞争力。今天&#xff0c;我们依旧怀揣着共同进步的愿望&#xff0c;深入解读《精…...

AI图像编辑器 Luminar Neo 便携版 Win1.24.0.14794

如果你对图像编辑有兴趣&#xff0c;但又不想花费太多时间学习复杂的软件操作&#xff0c;那么 Luminar Neo 可能就是你要找的完美工具。作为一款基于AI技术的创意图像编辑器&#xff0c;Luminar Neo简化了复杂的编辑流程&#xff0c;即使是没有任何图像处理经验的新手&#xf…...

在Mybatis中为什么要同时指定扫描mapper接口和 mapper.xml 文件,理论单独扫描 xml 文件就可以啊

设计考虑因素 历史兼容性&#xff1a; MyBatis早期版本主要依赖XML配置&#xff0c;后来才引入接口绑定方式同时支持两种方式可以保证向后兼容 明确性&#xff1a; 显式指定两种路径可以使映射关系更加明确减少因命名不一致导致的潜在问题 性能考虑&#xff1a; 同时扫描可…...

MyBatis XML 配置完整示例(含所有核心配置项)

MyBatis XML 配置完整示例&#xff08;含所有核心配置项&#xff09; 1. 完整 mybatis-config.xml 配置文件 <?xml version"1.0" encoding"UTF-8" ?> <!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""htt…...

【数据结构入门训练DAY-24】美国大选

文章目录 前言一、题目二、解题思路结语 前言 本次训练内容 训练STL中sort的操作方法。训练解题思维。 一、题目 美国大选是按各州的投票结果来确定最终的结果的&#xff0c;如果得到超过一半的州的支 持就可以当选&#xff0c;而每个州的投票结果又是由该州选民投票产生…...

stm32L4R5ZI Nucleo-144 GPIO点灯及按键中断

文章目录 前言一、CubeMx环境配置二、GPIO点灯操作三、按键中断点灯总结 前言 STM32L4R5ZI Nucleo-144是STMicroelectronics推出的一款基于ARM Cortex-M4内核的微控制器芯片。它是STM32L4系列中的一员&#xff0c;针对低功耗和高性能的应用而设计。以下是一些关键特点和技术规格…...

访问Redis时遇到 unknown command ‘FT.INFO‘, with args beginning with 错误的解决方案

在B站学习 图灵程序员-诸葛 的LangChain入门课程《基于Redis保存历史聊天信息》。在实践代码时遇到了一些问题&#xff0c;在这里记录一下&#xff0c;希望能帮助到也在学习的同学。话不多说&#xff0c;上代码&#xff0c;这段代码使用langchain_redis来持久化大模型对话的聊天…...

Swift与iOS内存管理机制深度剖析

前言 内存管理是每一位 iOS 开发者都绕不开的话题。虽然 Swift 的 ARC&#xff08;自动引用计数&#xff09;极大简化了开发者的工作&#xff0c;但只有深入理解其底层实现&#xff0c;才能写出高效、健壮的代码&#xff0c;避免各种隐蔽的内存问题。本文将从底层原理出发&…...

数据库系统概论(五)关系模型的数据结构及形式化

数据库系统概论&#xff08;五&#xff09;关系模型的数据结构及形式化 前言一、关系&#xff1a;从“表格”说起1.1 关系数据模型中的“关系”是什么&#xff1f;1.2 域&#xff08;Domain&#xff09;&#xff1a;数据的“类型限定”1.3 笛卡尔积&#xff08;Cartesian Produ…...

Python类和对象四(十三)

魔法方法&#xff1a; 按位运算 按位于运算 只要相同才是1 或运算&#xff1a; 只要某个位是1结果就是1 、 按位非 将结果取反 按位异或&#xff1a; 左移和右移运算符&#xff1a; 右移两位 右移动n位&#xff0c;就是除以2的n次方 左移两位&#xff1a; 左移n位就是乘…...

Go 1.24 中的弱指针包 weak 使用介绍

在 Go 语言中&#xff0c;“弱指针”指的是不会阻止垃圾回收器&#xff08;GC&#xff09;回收目标对象的引用。 当一个对象只剩弱指针指向它&#xff0c;而没有任何强引用时&#xff0c;GC 仍会把该对象当作不可达对象并回收&#xff1b;随后&#xff0c;所有指向它的弱指针会…...

毕业项目-基于深度学习的入侵检测系统

选题背景与意义 随着互联网技术的飞速发展&#xff0c;网络在各个领域中的作用日益重要。然而&#xff0c;伴随着技术的进步&#xff0c;网络安全问题也愈加严峻&#xff0c;网络攻击事件频繁发生&#xff0c;给个人、企业乃至国家带来了巨大的经济损失与安全威胁。入侵检测系…...

Github 2025-04-26 Rust开源项目日报Top10

根据Github Trendings的统计,今日(2025-04-26统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero General Public Li…...

【Hive入门】Hive分桶表深度解析:从哈希分桶到Join优化的完整指南

目录 引言 1 分桶表基础概念 1.1 什么是分桶表 1.2 分桶与分区的区别 2 分桶表设计与创建 2.1 创建分桶表语法 2.2 分桶键选择原则 2.3 桶数确定策略 3 分桶表数据加载 3.1 标准数据加载流程 3.2 分桶表数据验证 4 分桶Join优化原理 4.1 Map端Join优化 4.2 Sort-…...

django之优化分页功能(利用参数共存及封装来实现)

优化分页功能 目录 1.封装分页代码 2.解决分页时覆盖搜索参数的bug 3.优化分页功能 上一篇文章我们讲到了搜索功能和分页展示数据功能。那这篇文章, 在上篇文章的基础上, 会去优化这些功能并解决搜索功能和分页功能不能一起使用的bug。 一、封装分页代码 原本我们的asse…...

linux blueZ 第四篇:BLE GATT 编程与自动化——Python 与 C/C++ 实战

本篇聚焦 BLE(Bluetooth Low Energy)GATT 协议层的编程与自动化实践,涵盖 GATT 基础、DBus API 原理、Python(dbus-next/bleak)示例、C/C++ (BlueZ GATT API)示例,以及自动发现、读写特征、订阅通知、安全配对与脚本化测试。 目录 BLE GATT 基础概念 BlueZ DBus GATT 模…...

前端面试每日三题 - Day 16

这是我为准备前端/全栈开发工程师面试整理的第16天每日三题练习&#xff0c;涵盖事件循环深入解析 、Vue3 响应式系统原理 &#xff0c;以及 多租户系统设计实践。每道题附带 详细解析、示例代码与脑图建议&#xff0c;助你全面掌握底层原理与架构设计思维。 ✅ 题目 1&#xf…...

使用PyTorch实现简单图像识别(基于MNIST手写数字数据集)的完整代码示例,包含数据加载、模型定义、训练和预测全流程

以下是一个使用PyTorch实现简单图像识别&#xff08;基于MNIST手写数字数据集&#xff09;的完整代码示例&#xff0c;包含数据加载、模型定义、训练和预测全流程&#xff1a; import torch import torch.nn as nn import torch.optim as optim import torchvision import torc…...

【Android】四大组件之Activity

目录 一、什么是Activity 二、如何创建和配置Activity 三、Activity 跳转与数据传递 四、数据保存与恢复 五、Activity 启动模式 六、自定义返回行为 七、复杂界面布局 你可以把Activity想象成手机屏幕上的一个“页面”。比如&#xff0c;当你打开一个App时&#xff0c;…...

数据库原理(1)

第一章 概论 一、基本概念 数据&#xff08;Data&#xff09;是数据库中存储的基本对象&#xff0c;描述事物的符号记录。例如学生的学号、姓名等信息都是数据。 数据库&#xff08;Database&#xff0c;DB&#xff09;长期存储在计算机内、有组织的、可共享的大量数据的集合。…...

SQL盲注问题深度解析与防范策略

引言 在当今互联网时代,Web应用程序的安全性是重中之重。SQL注入作为一种常见且极具威胁性的攻击手段,而其中的SQL盲注更是因其隐蔽性强、难以察觉而备受关注。攻击者借助SQL盲注,在无法直接获取数据库返回结果的情况下,通过精心构造特殊的SQL语句,利用页面的不同响应来逐…...

Android JIT( ART即时编译器),Just In Time Compiler,即时编译技术

Android JIT&#xff08; ART即时编译器&#xff09;,Just In Time Compiler&#xff0c;即时编译技术 Android Runtime (ART) 包含一个具备代码分析功能的即时 (JIT) 编译器&#xff0c;该编译器可以在 Android 应用运行时持续提高其性能。JIT是Just In Time Compiler&#xf…...