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

Spring Boot集成Redis与Lua脚本:构建高效的分布式多规则限流系统

文章目录

  • Redis多规则限流和防重复提交
    • 记录访问次数
    • 解决临界值访问问题
    • 实现多规则限流
      • 先确定最终需要的效果
      • 编写注解(RateLimiter,RateRule)
      • 拦截注解 RateLimiter
    • 编写lua脚本
      • UUID
      • 时间戳
      • 编写 AOP 拦截
    • 总结

Redis多规则限流和防重复提交

市面上很多介绍redis如何实现限流的,但是大部分都有一个缺点,就是只能实现单一的限流,比如1分钟访问1次或者60分钟访问10次这种,但是如果想一个接口两种规则都需要满足呢,我们的项目又是分布式项目,应该如何解决,下面就介绍一下redis实现分布式多规则限流的方式。

  • 如何一分钟只能发送一次验证码,一小时只能发送10次验证码等等多种规则的限流?
  • 如何防止接口被恶意打击(短时间内大量请求)?
  • 如何限制接口规定时间内访问次数?

记录访问次数

使用 String 结构,记录固定时间段内某用户IP访问某接口的次数
RedisKey = prefix : className : methodName
RedisVlue = 访问次数

拦截请求:

  1. 初次访问时设置 [RedisKey] [RedisValue=1] [规定的过期时间]
  2. 获取 RedisValue 是否超过规定次数,超过则拦截,未超过则对 RedisKey 进行加1

分析: 规则是每分钟访问 1000 次

  1. 考虑并发问题
    • 假设目前 RedisKey => RedisValue 为 999
    • 目前大量请求进行到第一步( 获取Redis请求次数 ),那么所有线程都获取到了值为999,进行判断都未超过限定次数则不拦截,导致实际次数超过 1000 次
    • 解决办法: 保证方法执行原子性(加锁、lua)
  2. 考虑在临界值进行访问
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IL4u0jaY-1721999915731)(https://i-blog.csdnimg.cn/direct/1eacf46030b6471e91ce43d1e5eae900.png)]
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import com.ruoyi.common.annotation.RateLimiter;
import com.ruoyi.common.enums.LimitType;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.ip.IpUtils;/*** 限流处理*/
@Aspect
@Component
public class RateLimiterAspect
{private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);private RedisTemplate<Object, Object> redisTemplate;private RedisScript<Long> limitScript;@Autowiredpublic void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate){this.redisTemplate = redisTemplate;}@Autowiredpublic void setLimitScript(RedisScript<Long> limitScript){this.limitScript = limitScript;}@Before("@annotation(rateLimiter)")public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable{int time = rateLimiter.time();int count = rateLimiter.count();String combineKey = getCombineKey(rateLimiter, point);List<Object> keys = Collections.singletonList(combineKey);try{Long number = redisTemplate.execute(limitScript, keys, count, time);if (StringUtils.isNull(number) || number.intValue() > count){throw new ServiceException("访问过于频繁,请稍候再试");}log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);}catch (ServiceException e){throw e;}catch (Exception e){throw new RuntimeException("服务器限流异常,请稍候再试");}}public String getCombineKey(RateLimiter rateLimiter, JoinPoint point){StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());if (rateLimiter.limitType() == LimitType.IP){stringBuffer.append(IpUtils.getIpAddr()).append("-");}MethodSignature signature = (MethodSignature) point.getSignature();Method method = signature.getMethod();Class<?> targetClass = method.getDeclaringClass();stringBuffer.append(targetClass.getName()).append("-").append(method.getName());return stringBuffer.toString();}
}

解决临界值访问问题

使用 Zset 进行存储,解决临界值访问问题。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-frPzmAdy-1721999915734)(https://i-blog.csdnimg.cn/direct/1ce98a4076d343f69e7ed880eff292bf.png)]

实现多规则限流

先确定最终需要的效果

  • 能实现多种限流规则
  • 能实现防重复提交
    通过以上要求设计注解(先想象出最终实现效果)
@RateLimiter(rules = {// 60秒内只能访问10次@RateRule(count = 10, time = 60, timeUnit = TimeUnit.SECONDS),// 120秒内只能访问20次@RateRule(count = 20, time = 120, timeUnit = TimeUnit.SECONDS)},// 防重复提交 (5秒钟只能访问1次)preventDuplicate = true
)

编写注解(RateLimiter,RateRule)

编写 RateLimiter 注解

/*** @Description: 请求接口限制*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RateLimiter {/*** 限流key*/String key() default RedisKeyConstants.RATE_LIMIT_CACHE_PREFIX;/*** 限流类型 ( 默认 Ip 模式 )*/LimitTypeEnum limitType() default LimitTypeEnum.IP;/*** 错误提示*/ResultCode message() default ResultCode.REQUEST_MORE_ERROR;/*** 限流规则 (规则不可变,可多规则)*/RateRule[] rules() default {};/*** 防重复提交值*/boolean preventDuplicate() default false;/*** 防重复提交默认值*/RateRule preventDuplicateRule() default @RateRule(count = 1, time = 5);
}

编写 RateRule 注解

@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface RateRule {/*** 限流次数*/long count() default 10;/*** 限流时间*/long time() default 60;/*** 限流时间单位*/TimeUnit timeUnit() default TimeUnit.SECONDS;
}

拦截注解 RateLimiter

  • 确定redis存储方式
    • RedisKey = prefix : className : methodName
    • RedisScore = 时间戳
    • RedisValue = 任意分布式不重复的值即可
  • 编写生成 RedisKey 的方法
/*** 通过 rateLimiter 和 joinPoint 拼接  prefix : ip / userId : classSimpleName - methodName** @param rateLimiter 提供 prefix* @param joinPoint   提供 classSimpleName : methodName* @return*/
public String getCombineKey(RateLimiter rateLimiter, JoinPoint joinPoint) {StringBuffer key = new StringBuffer(rateLimiter.key());// 不同限流类型使用不同的前缀switch (rateLimiter.limitType()) {// XXX 可以新增通过参数指定参数进行限流case IP:key.append(IpUtil.getIpAddr(((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest())).append(":");break;case USER_ID:SysUserDetails user = SecurityUtil.getUser();if (!ObjectUtils.isEmpty(user)) key.append(user.getUserId()).append(":");break;case GLOBAL:break;}MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();Class<?> targetClass = method.getDeclaringClass();key.append(targetClass.getSimpleName()).append("-").append(method.getName());return key.toString();
}

编写lua脚本

两种将时间添加到Redis的方法。

UUID

UUID(可用其他有相同的特性的值)为Zset中的value值

  • 参数介绍
    • KEYS[1] = prefix : ? : className : methodName
    • KEYS[2] = 唯一ID
    • KEYS[3] = 当前时间
    • ARGV = [次数,单位时间,次数,单位时间, 次数, 单位时间 ...]
  • java传入分布式不重复的 value
-- 1. 获取参数
local key = KEYS[1]
local uuid = KEYS[2]
local currentTime = tonumber(KEYS[3])
-- 2. 以数组最大值为 ttl 最大值
local expireTime = -1;
-- 3. 遍历数组查看是否超过限流规则
for i = 1, #ARGV, 2 dolocal rateRuleCount = tonumber(ARGV[i])local rateRuleTime = tonumber(ARGV[i + 1])-- 3.1 判断在单位时间内访问次数local count = redis.call('ZCOUNT', key, currentTime - rateRuleTime, currentTime)-- 3.2 判断是否超过规定次数if tonumber(count) >= rateRuleCount thenreturn trueend-- 3.3 判断元素最大值,设置为最终过期时间if rateRuleTime > expireTime thenexpireTime = rateRuleTimeend
end
-- 4. redis 中添加当前时间
redis.call('ZADD', key, currentTime, uuid)
-- 5. 更新缓存过期时间
redis.call('PEXPIRE', key, expireTime)
-- 6. 删除最大时间限度之前的数据,防止数据过多
redis.call('ZREMRANGEBYSCORE', key, 0, currentTime - expireTime)
return false

时间戳

根据时间戳作为Zset中的value值

  • 参数介绍
    • KEYS[1] = prefix : ? : className : methodName
    • KEYS[2] = 当前时间
    • ARGV = [次数,单位时间,次数,单位时间, 次数, 单位时间 ...]
  • 根据时间进行生成value值,考虑同一毫秒添加相同时间值问题
    • 以下为第二种实现方式,在并发高的情况下效率低,value是通过时间戳进行添加,但是访问量大的话会使得一直在调用 redis.call('ZADD', key, currentTime, currentTime),但是在不冲突value的情况下,会比生成 UUID
-- 1. 获取参数
local key = KEYS[1]
local currentTime = KEYS[2]
-- 2. 以数组最大值为 ttl 最大值
local expireTime = -1;
-- 3. 遍历数组查看是否越界
for i = 1, #ARGV, 2 dolocal rateRuleCount = tonumber(ARGV[i])local rateRuleTime = tonumber(ARGV[i + 1])-- 3.1 判断在单位时间内访问次数local count = redis.call('ZCOUNT', key, currentTime - rateRuleTime, currentTime)-- 3.2 判断是否超过规定次数if tonumber(count) >= rateRuleCount thenreturn trueend-- 3.3 判断元素最大值,设置为最终过期时间if rateRuleTime > expireTime thenexpireTime = rateRuleTimeend
end
-- 4. 更新缓存过期时间
redis.call('PEXPIRE', key, expireTime)
-- 5. 删除最大时间限度之前的数据,防止数据过多
redis.call('ZREMRANGEBYSCORE', key, 0, currentTime - expireTime)
-- 6. redis 中添加当前时间  ( 解决多个线程在同一毫秒添加相同 value 导致 Redis 漏记的问题 )
-- 6.1 maxRetries 最大重试次数 retries 重试次数
local maxRetries = 5
local retries = 0
while true dolocal result = redis.call('ZADD', key, currentTime, currentTime)if result == 1 then-- 6.2 添加成功则跳出循环breakelse-- 6.3 未添加成功则 value + 1 再次进行尝试retries = retries + 1if retries >= maxRetries then-- 6.4 超过最大尝试次数 采用添加随机数策略local random_value = math.random(1, 1000)currentTime = currentTime + random_valueelsecurrentTime = currentTime + 1endend
endreturn false

编写 AOP 拦截

@Autowired
private RedisTemplate<String, Object> redisTemplate;@Autowired
private RedisScript<Boolean> limitScript;/*** 限流* XXX 对限流要求比较高,可以使用在 Redis中对规则进行存储校验 或者使用中间件** @param joinPoint   joinPoint* @param rateLimiter 限流注解*/
@Before(value = "@annotation(rateLimiter)")
public void boBefore(JoinPoint joinPoint, RateLimiter rateLimiter) {// 1. 生成 keyString key = getCombineKey(rateLimiter, joinPoint);try {// 2. 执行脚本返回是否限流Boolean flag = redisTemplate.execute(limitScript,ListUtil.of(key, String.valueOf(System.currentTimeMillis())),(Object[]) getRules(rateLimiter));// 3. 判断是否限流if (Boolean.TRUE.equals(flag)) {log.error("ip: '{}' 拦截到一个请求 RedisKey: '{}'",IpUtil.getIpAddr(((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest()),key);throw new ServiceException(rateLimiter.message());}} catch (ServiceException e) {throw e;} catch (Exception e) {e.printStackTrace();}
}/*** 获取规则** @param rateLimiter 获取其中规则信息* @return*/
private Long[] getRules(RateLimiter rateLimiter) {int capacity = rateLimiter.rules().length << 1;// 1. 构建 argsLong[] args = new Long[rateLimiter.preventDuplicate() ? capacity + 2 : capacity];// 3. 记录数组元素int index = 0;// 2. 判断是否需要添加防重复提交到redis进行校验if (rateLimiter.preventDuplicate()) {RateRule preventRateRule = rateLimiter.preventDuplicateRule();args[index++] = preventRateRule.count();args[index++] = preventRateRule.timeUnit().toMillis(preventRateRule.time());}RateRule[] rules = rateLimiter.rules();for (RateRule rule : rules) {args[index++] = rule.count();args[index++] = rule.timeUnit().toMillis(rule.time());}return args;
}

总结

为了实现多规则限流和防止重复提交,我们可以采用Redis作为后端存储,结合Lua脚本来确保原子性和准确性。下面是基于你的需求和提供的示例代码的详细总结:

设计目标

  • 多规则限流:实现多种不同时间范围内的访问频率控制。
  • 防止重复提交:在一定时间内限制同一请求的重复提交。

方案概述

  1. 使用String结构记录访问次数:适用于简单限流,但容易遇到并发问题。
  2. 使用ZSet结构:解决并发问题,并支持多规则限流。
  3. 编写Lua脚本:用于高效地处理多规则限流逻辑。
  4. AOP拦截器:在Spring框架中使用AspectJ进行请求拦截。

限流规则

  • 规则定义:通过自定义注解@RateLimiter@RateRule来指定限流规则和防重复提交的策略。
  • 规则应用:通过AspectJ切面编程在方法执行前进行检查。

Redis键值设计

  • prefix : ? : className : methodName
  • 分值:时间戳
  • 成员:唯一标识符(如UUID)或时间戳

Lua脚本实现

  • 使用UUID:解决并发问题的同时避免数据冗余。

  • 使用时间戳:简化脚本实现,但需要解决同一毫秒内多个请求的问题。

  • 多规则限流:通过使用ZSet结构和Lua脚本实现。

  • 防重复提交:通过在规则中添加额外的限流规则实现。

  • 并发安全:Lua脚本确保了限流逻辑的原子性。

  • 性能优化:通过预先计算过期时间,减少不必要的Redis命令调用。

这样,你可以有效地在分布式系统中实现多规则限流和防止重复提交。

相关文章:

Spring Boot集成Redis与Lua脚本:构建高效的分布式多规则限流系统

文章目录 Redis多规则限流和防重复提交记录访问次数解决临界值访问问题实现多规则限流先确定最终需要的效果编写注解&#xff08;RateLimiter&#xff0c;RateRule&#xff09;拦截注解 RateLimiter 编写lua脚本UUID时间戳编写 AOP 拦截 总结 Redis多规则限流和防重复提交 市面…...

四、单线程多路IO复用+多线程业务工作池

文章目录 一、前言1 编译方法 二、单线程多路IO复用多线程业务工作池结构三、重写Client_Context类四、编写Server类 一、前言 我们以及讲完单线程多路IO复用 以及任务调度与执行的C线程池&#xff0c;接下来我们就给他结合起来。 由于项目变大&#xff0c;尝试解耦项目&#…...

单元测试--Junit

Junit是Java的单元测试框架提供了一些注解方便我们进行单元测试 1. 常用注解 常用注解&#xff1a; TestBeforeAll&#xff0c;AfterAllBeforeEach&#xff0c;AfterEach 使用这些注解需要先引入依赖&#xff1a; <dependency><groupId>org.junit.jupiter<…...

达梦数据库系列—30. DTS迁移Mysql到DM

目录 1.MySQL 源端信息 2.DM 目的端信息 3.迁移评估 4.数据库迁移 4.1源端 MySQL 准备 4.2目的端达梦准备 初始化参数设置 兼容性参数设置 创建迁移用户和表空间 4.3迁移步骤 创建迁移 配置迁移对象及策略 开始迁移 对象补迁 5.数据校验 统计 MySQL 端对象及数…...

随记0000——从0、1 到 C语言

C语言的发展历程是计算机科学史上的一个重要里程碑。 下面是从最早的机器语言到汇编语言&#xff0c;再到高级语言如 C 语言的简化演进过程&#xff1a; 1. 机器语言 定义与特点 机器语言是最底层的编程语言&#xff0c;由一系列二进制代码组成。直接被CPU执行&#xff0c;…...

C++ | Leetcode C++题解之第264题丑数II

题目&#xff1a; 题解&#xff1a; class Solution { public:int nthUglyNumber(int n) {vector<int> dp(n 1);dp[1] 1;int p2 1, p3 1, p5 1;for (int i 2; i < n; i) {int num2 dp[p2] * 2, num3 dp[p3] * 3, num5 dp[p5] * 5;dp[i] min(min(num2, num3…...

前端系列-8 集中式状态管理工具pinia

集中式状态管理工具—pinia vue3中使用pinia作为集中式状态管理工具&#xff0c;替代vue2中的vuex。 pinia文档可参考: https://pinia.web3doc.top/introduction.html 1.项目集成pinia 安装pinia依赖: npm install pinia在main.ts中引入pinia import { createApp } from vu…...

pytest使用

主要技术内容 1.pytest设计 接口测试 框架设想 common—公共的东西封装 1.request请求 2.Session 3.断言 4.Log 5.全局变量 6.shell命令 ❖ config---配置文件及读取 ❖ Log— ❖ payload—请求参数—*.yaml及读取 ❖ testcases—conftest.py; testcase1.py…….可…...

单表查询总结与多表查询概述

1. 单表查询总结 执行顺序&#xff1a; 从一张表&#xff0c;过滤数据&#xff0c;进行分组&#xff0c;对分组后的数据再过滤&#xff0c;查询出来所需数据&#xff0c;排序之后输出&#xff1b; from > where > group by > having > select > order by 2. …...

redis的使用场景和持久化方式

redis的使用场景 热点数据的缓存。热点&#xff1a;频繁读取的数据。限时任务的操作&#xff1a;短信验证码。完成session共享的问题完成分布式锁。 redis的持久化方式 什么是持久化&#xff1a;把内存中的数据存储到磁盘的过程&#xff0c;同时也可以把磁盘中的数据加载到内存…...

嵌入式Linux学习: 设备树实验

设备树&#xff08;DeviceTree&#xff09;是一种硬件描述机制&#xff0c;用于在嵌入式系统和操作系统中描述硬件设备的特性、连接关系和配置信息。它提供了一种与平台无关的方式来描述硬件&#xff0c;使得内核与硬件之间的耦合度降低&#xff0c;提高了系统的可移植性和可维…...

eqmx上读取数据处理以后添加到数据库中

目录 定义一些静态变量 定时器事件的处理器 订阅数据的执行器 处理json格式数据和将处理好的数据添加到数据库中 要求和最终效果 总结一下 定义一些静态变量 // 在这里都定义成全局的 一般都定义成静态的private static MqttClient mqttClient; // mqtt客户端 private s…...

【中项】系统集成项目管理工程师-第5章 软件工程-5.3软件设计

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…...

C++学习笔记-内联函数使用和含义

引言 内联函数是C为了优化在函数的调用带来的性能开销而设计的&#xff0c;特别是当函数体很小且频繁调用时&#xff0c;内联函数可以让编译器在调用点直接展开函数体&#xff0c;从而避免了函数调用的开销。 一、内联函数的定义与含义 1.1 定义 内联函数是通过在函数声明或…...

数据库(MySQL)-视图、存储过程、触发器

一、视图 视图的定义、作用 视图是从一个或者几个基本表&#xff08;或视图&#xff09;导出的表。它与基本表不同&#xff0c;是一个虚表。但是视图只能用来查看表&#xff0c;不能做增删改查。 视图的作用&#xff1a;①简化查询 ②重写格式化数据 ③频繁访问数据库 ④过…...

js 优雅的实现模板方法设计模式

在JavaScript中&#xff0c;优雅地实现模板方法设计模式通常意味着我们要遵循一些最佳实践&#xff0c;如清晰地定义算法的骨架&#xff08;模板方法&#xff09;&#xff0c;并确保子类能够灵活地扩展或修改这些算法中的特定步骤。由于JavaScript是一种动态语言&#xff0c;我…...

C语言——输入输出

C语言——输入输出 输入输出函数的类型getcharputcharprintf占位符的分类 scanf 什么是输入输出呢&#xff1f; 所谓输入输出是以计算机为主机而言的&#xff0c;往内存中输入数据为输入&#xff0c;反之从内存中输出数据为输出。 输入输出的功能 C语言本身是不提供输入输出功能…...

【微软蓝屏】微软Windows蓝屏问题汇总与应对解决策略

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…...

OpenCV图像滤波(2)均值平滑处理函数blur()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 在OpenCV中&#xff0c;blur()函数用于对图像应用简单的均值模糊&#xff08;mean blur&#xff09;。这种模糊效果可以通过将图像中的每个像素替…...

Android lmkd机制详解

目录 一、lmkd介绍 二、lmkd实现原理 2.1 工作原理图 2.2 初始化 2.3 oom_adj获取 2.4 监听psi事件及处理 2.5 进程选取与查杀 2.5.1 进程选取 2.5.2 进程查杀 三、关键系统属性 四、核心数据结构 五、代码时序 一、lmkd介绍 Android lmkd采用epoll方式监听linux内…...

linux shell(中)

结构化命令 if语句 if-then 最基本的结构化命令是 if-then 语句。if-then 语句的格式如下&#xff1a; if command thencommands ifif command; then # 通过把分号&#xff08;;&#xff09;放在待求值的命令尾部&#xff0c;可以将 then 语句写在同一行commands ifbash sh…...

VMware三种网络模式---巨细

文章目录 目录 ‘一.网络模式概述 二.桥接模式 二.NAT模式 三.仅主机模式 四.案例演示 防火墙配置&#xff1a; 虚拟电脑配置 前言 本文主要介绍VMware的三种网络模式 ‘一.网络模式概述 VMware中分为三种网络模式&#xff1a; 桥接模式&#xff1a;默认与宿主机VMnet0绑…...

力扣高频SQL 50 题(基础版)第一题

文章目录 力扣高频SQL 50 题&#xff08;基础版&#xff09;第一题1757.可回收且低脂的产品题目说明思路分析实现过程准备数据&#xff1a;实现方式&#xff1a;结果截图&#xff1a; 力扣高频SQL 50 题&#xff08;基础版&#xff09;第一题 1757.可回收且低脂的产品 题目说…...

2.1.卷积层

卷积 ​ 用MLP处理图片的问题&#xff1a;假设一张图片有12M像素&#xff0c;那么RGB图片就有36M元素&#xff0c;使用大小为100的单隐藏层&#xff0c;模型有3.6B元素&#xff0c;这个数量非常大。 识别模式的两个原则&#xff1a; 平移不变性&#xff08;translation inva…...

网易《永劫无间》手游上线,掀起游戏界狂潮

原标题&#xff1a;网易《永劫无间》手游上线&#xff0c;网友&#xff1a;发烧严重 易采游戏网7月26日消息&#xff1a;自网易宣布《永劫无间》手游即将上线以来&#xff0c;广大游戏玩家的期待值就不断攀升。作为一款拥有丰富内容和极高自由度的游戏&#xff0c;《永劫无间》…...

RNN(一)——循环神经网络的实现

文章目录 一、循环神经网络RNN1.RNN是什么2.RNN的语言模型3.RNN的结构形式 二、完整代码三、代码解读1.参数return_sequences2.调参过程 一、循环神经网络RNN 1.RNN是什么 循环神经网络RNN主要体现在上下文对理解的重要性&#xff0c;他比传统的神经网络&#xff08;传统的神…...

php 根据位置的经纬度计算距离

在开发中,我们要经常和位置打交道,要计算附近的位置、距离什么的。如下: 一.sql语句 SELECT houseID,title,location,chamber,room,toward,area,rent,is_verify,look_type,look_time, traffic,block_name,images,tag,create_time,update_time, location->&g…...

17 Python常用内置函数——基本输入输出

input() 和 print() 是 Python 的基本输入输出函数&#xff0c;前者用来接收用户的键盘输入&#xff0c;后者用来把数据以指定的格式输出到标准控制台或指定的文件对象。无论用户输入什么内容&#xff0c;input() 一律作为字符串对待&#xff0c;必要时可以使用内置函数 int()、…...

【Web】LitCTF 2024 题解(全)

目录 浏览器也能套娃&#xff1f; 一个....池子&#xff1f; 高亮主题(划掉)背景查看器 百万美元的诱惑 SAS - Serializing Authentication exx 浏览器也能套娃&#xff1f; 随便试一试&#xff0c;一眼ssrf file:///flag直接读本地文件 一个....池子&#xff1f; {…...

家政项目小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;家政人员管理&#xff0c;家政服务管理&#xff0c;咨询信息管理&#xff0c;咨询服务管理&#xff0c;家政预约管理&#xff0c;留言板管理&#xff0c;系统管理 微信端账号功能…...

electron TodoList网页应用打包成linux deb、AppImage应用

这里用的是windows的wsl的ubuntu环境 electron应用打包linux应用需要linux下打包&#xff0c;这里用windows的wsl的ubuntu环境进行操作 1&#xff09;linux ubuntu安装nodejs、electron 安装nodejs&#xff1a; sudo apt update sudo apt upgrade ##快捷安装 curl -fsSL http…...

【C语言】 使用fgets和fputs完成两个文件的拷贝

目录 1、使用fgets和fputs完成两个文件的拷贝 2、使用fgets统计给定文件的行号 fgets和fputs的使用方法函数原型&#xff1a;int fputs&#xff08;const char *s,FILE *stream)&#xff1b; char *fgets(char *s,int size,FILE *stream)&#xff1b;fupts…...

使用PyTorch导出JIT模型:C++ API与libtorch实战

PyTorch导出JIT模型并用C API libtorch调用 本文将介绍如何将一个 PyTorch 模型导出为 JIT 模型并用 PyTorch 的 CAPI libtorch运行这个模型。 Step1&#xff1a;导出模型 首先我们进行第一步&#xff0c;用 Python API 来导出模型&#xff0c;由于本文的重点是在后面的部署…...

Python——异常捕获,传递及其抛出操作

01. 异常的概念 1. 程序在运行时&#xff0c;如果 python解释器遇到一个错误&#xff0c;会停止程序的执行&#xff0c;并且提示一些错误信息&#xff0c;这就是异常。 2. 程序停止执行并且提示错误信息这个动作&#xff0c;我们通常称之为&#xff1a;抛出&#xff08;raise…...

【Maven】 的继承机制

Maven是一个强大的项目管理工具&#xff0c;主要用于Java项目的构建和管理。它以其项目对象模型&#xff08;POM&#xff09;为基础&#xff0c;允许开发者定义项目的依赖、构建过程和插件。Maven的继承机制是其核心特性之一&#xff0c;它允许子项目继承和复用父项目的配置&am…...

微信小程序结合后端php发送模版消息

前端&#xff1a; <view class"container"><button bindtap"requestSubscribeMessage">订阅消息</button> </view> // index.js Page({data: {tmplIds: [UTgCUfsjHVESf5FjOzls0I9i_FVS1N620G2VQCg1LZ0] // 使用你的模板ID},requ…...

sqlalchemy报错sqlalchemy.orm.exc.DetachedInstanceError

解决方案&#xff1a; 在初始化数据库的代码中&#xff0c;将 maker sessionmaker(bindeng)修改为 maker sessionmaker(bindeng, expire_on_commitFalse)为什么要添加 expire_on_commitFalse 参数&#xff1f; expire_on_commit 可以用来更改 SQLAlchemy 的对象刷新机制&…...

华为网络模拟器eNSP安装部署教程

eNSP是图形化网络仿真平台&#xff0c;该平台通过对真实网络设备的仿真模拟&#xff0c;帮助广大ICT从业者和客户快速熟悉华为数通系列产品&#xff0c;了解并掌握相关产品的操作和配置、提升对企业ICT网络的规划、建设、运维能力&#xff0c;从而帮助企业构建更高效&#xff0…...

【React】详解样式控制:从基础到进阶应用的全面指南

文章目录 一、内联样式1. 什么是内联样式&#xff1f;2. 内联样式的定义3. 基本示例4. 动态内联样式 二、CSS模块1. 什么是CSS模块&#xff1f;2. CSS模块的定义3. 基本示例4. 动态应用样式 三、CSS-in-JS1. 什么是CSS-in-JS&#xff1f;2. styled-components的定义3. 基本示例…...

【ROS2】高级:安全-理解安全密钥库

目标&#xff1a;探索位于 ROS 2 安全密钥库中的文件。 教程级别&#xff1a;高级 时间&#xff1a;15 分钟 内容 背景安全工件位置 公钥材料 私钥材料域治理政策 安全飞地 参加测验&#xff01; 背景 在继续之前&#xff0c;请确保您已完成设置安全教程。 sros2 包可以用来创…...

C语言 ——— 数组指针的定义 数组指针的使用

目录 前言 数组指针的定义 数组指针的使用 前言 之前有编写过关于 指针数组 的相关知识 C语言 ——— 指针数组 & 指针数组模拟二维整型数组-CSDN博客 指针数组 顾名思义就是 存放指针的数组 那什么是数组指针呢&#xff1f; 数组指针的定义 何为数组指针&#xf…...

opencascade AIS_ManipulatorOwner AIS_MediaPlayer源码学习

前言 AIS_ManipulatorOwner是OpenCascade中的一个类&#xff0c;主要用于操纵对象的交互控制。AIS_ManipulatorOwner结合AIS_Manipulator类&#xff0c;允许用户通过可视化工具&#xff08;如旋转、平移、缩放等&#xff09;来操纵几何对象。 以下是AIS_ManipulatorOwner的基…...

如何防止用户通过打印功能复制页面文字

简单防白嫖&#xff0c;要让打印出来的页面是空白&#xff0c;通常的做法是在打印时隐藏页面上的所有内容。这可以通过CSS的媒体查询&#xff08;Media Queries&#xff09;来实现&#xff0c;特别是针对media print的查询。 在JavaScript中&#xff0c;你通常不会直接控制打印…...

Python3网络爬虫开发实战(3)网页数据的解析提取

文章目录 一、XPath1. 选取节点2. 查找某个特定的节点或者包含某个指定的值的节点3. XPath 运算符4. 节点轴5. 利用 lxml 使用 XPath 二、CSS三、Beautiful Soup1. 信息提取2. 嵌套选择3. 关联选择4. 方法选择器5. css 选择器 四、PyQuery1. 初始化2. css 选择器3. 信息提取4. …...

基于 HTML+ECharts 实现监控平台数据可视化大屏(含源码)

构建监控平台数据可视化大屏&#xff1a;基于 HTML 和 ECharts 的实现 监控平台的数据可视化对于实时掌握系统状态、快速响应问题至关重要。通过直观的数据展示&#xff0c;运维团队可以迅速发现异常&#xff0c;优化资源配置。本文将详细介绍如何利用 HTML 和 ECharts 实现一个…...

立创梁山派--移植开源的SFUD和FATFS实现SPI-FLASH文件系统

本文主要是在sfud的基础上进行fatfs文件系统的移植&#xff0c;并不对sfud的移植再进行过多的讲解了哦&#xff0c;所以如果想了解sfud的移植过程&#xff0c;请参考我的另外一篇文章&#xff1a;传送门 正文开始咯 首先我们需要先准备资料准备好&#xff0c;这里对于fatfs的…...

MySQL之视图和索引实战

1.新建数据库 mysql> create database myudb5_indexstu; Query OK, 1 row affected (0.01 sec) mysql> use myudb5_indexstu; Database changed 2.新建表 1.学生表student&#xff0c;定义主键&#xff0c;姓名不能重名&#xff0c;性别只能输入男或女&#xff0c;所在…...

快速参考:用C# Selenium实现浏览器窗口缩放的步骤

背景介绍 在现代网络环境中&#xff0c;浏览器自动化已成为数据抓取和测试的重要工具。Selenium作为一个强大的浏览器自动化工具&#xff0c;能够与多种编程语言结合使用&#xff0c;其中C#是非常受欢迎的选择之一。在实际应用中&#xff0c;我们常常需要调整浏览器窗口的缩放…...

MyBatis 插件机制、分页插件如何实现的

MyBatis 插件机制允许开发者在 SQL 执行的各个阶段&#xff08;如预处理、执行、结果处理等&#xff09;中插入自定义逻辑&#xff0c;从而实现对 MyBatis 行为的扩展和增强。以下是 MyBatis 插件运行原理的详细介绍&#xff1a; 插件接口 MyBatis 插件通过实现 org.apache.i…...

CentOS6.0安装telnet-server启用telnet服务

CentOS6.0安装telnet-server启用telnet服务 一步到位 fp"/etc/yum.repos.d" ; cp -a ${fp} ${fp}.$(date %0y%0m%0d%0H%0M%0S).bkup echo [base] nameCentOS-$releasever - Base baseurlhttp://mirrors.163.com/centos-vault/6.0/os/$basearch/http://mirrors.a…...