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

完整的 .NET 6 分布式定时任务实现(Hangfire + Redis 分布式锁)

完整的 .NET 6 分布式定时任务实现(Hangfire + Redis 分布式锁)

以下是完整的解决方案,包含所有必要组件:

1. 基础设施层

1.1 分布式锁服务

// IDistributedLockService.cs
public interface IDistributedLockService
{ValueTask<IAsyncDisposable?> AcquireLockAsync(string resourceKey, TimeSpan expiryTime);
}// RedisDistributedLockService.cs
public class RedisDistributedLockService : IDistributedLockService
{private readonly IConnectionMultiplexer _redis;private readonly ILogger<RedisDistributedLockService> _logger;public RedisDistributedLockService(IConnectionMultiplexer redis,ILogger<RedisDistributedLockService> logger){_redis = redis;_logger = logger;}public async ValueTask<IAsyncDisposable?> AcquireLockAsync(string resourceKey, TimeSpan expiryTime){var db = _redis.GetDatabase();var lockToken = Guid.NewGuid().ToString();var lockKey = $"distributed-lock:{resourceKey}";try{var acquired = await db.LockTakeAsync(lockKey, lockToken, expiryTime);if (acquired){_logger.LogDebug("成功获取分布式锁 {LockKey}", lockKey);return new RedisLockHandle(db, lockKey, lockToken, _logger);}_logger.LogDebug("无法获取分布式锁 {LockKey}", lockKey);return null;}catch (Exception ex){_logger.LogError(ex, "获取分布式锁 {LockKey} 时发生错误", lockKey);throw;}}private sealed class RedisLockHandle : IAsyncDisposable{private readonly IDatabase _db;private readonly string _lockKey;private readonly string _lockToken;private readonly ILogger _logger;private bool _isDisposed;public RedisLockHandle(IDatabase db,string lockKey,string lockToken,ILogger logger){_db = db;_lockKey = lockKey;_lockToken = lockToken;_logger = logger;}public async ValueTask DisposeAsync(){if (_isDisposed) return;try{var released = await _db.LockReleaseAsync(_lockKey, _lockToken);if (!released){_logger.LogWarning("释放分布式锁 {LockKey} 失败", _lockKey);}else{_logger.LogDebug("成功释放分布式锁 {LockKey}", _lockKey);}}catch (Exception ex){_logger.LogError(ex, "释放分布式锁 {LockKey} 时发生错误", _lockKey);}finally{_isDisposed = true;}}}
}

2. 任务服务层

2.1 定时任务服务

// IPollingService.cs
public interface IPollingService
{Task ExecutePollingTasksAsync();Task ExecuteDailyTaskAsync(int hour);
}// PollingService.cs
public class PollingService : IPollingService
{private readonly IDistributedLockService _lockService;private readonly ILogger<PollingService> _logger;public PollingService(IDistributedLockService lockService,ILogger<PollingService> logger){_lockService = lockService;_logger = logger;}[DisableConcurrentExecution(timeoutInSeconds: 60 * 30)] // 30分钟防并发public async Task ExecutePollingTasksAsync(){await using var lockHandle = await _lockService.AcquireLockAsync("polling-tasks-lock",TimeSpan.FromMinutes(25)); // 锁有效期25分钟if (lockHandle is null){_logger.LogInformation("其他节点正在执行轮询任务,跳过本次执行");return;}try{_logger.LogInformation("开始执行轮询任务 - 节点: {NodeId}", Environment.MachineName);// 执行所有轮询任务await Task.WhenAll(PollingTaskAsync(),PollingExpireTaskAsync(),PollingExpireDelCharactTaskAsync());// 触发后台任务_ = BackgroundTask.Run(() => PollingDelCharactTaskAsync(), _logger);_ = BackgroundTask.Run(() => AutoCheckApiAsync(), _logger);_ = BackgroundTask.Run(() => DelLogsAsync(), _logger);}catch (Exception ex){_logger.LogError(ex, "执行轮询任务时发生错误");throw;}}[DisableConcurrentExecution(timeoutInSeconds: 60 * 60)] // 1小时防并发public async Task ExecuteDailyTaskAsync(int hour){var lockKey = $"daily-task-{hour}:{DateTime.UtcNow:yyyyMMdd}";await using var lockHandle = await _lockService.AcquireLockAsync(lockKey,TimeSpan.FromMinutes(55)); // 锁有效期55分钟if (lockHandle is null){_logger.LogInformation("其他节点已执行今日 {Hour} 点任务", hour);return;}try{_logger.LogInformation("开始执行 {Hour} 点任务 - 节点: {NodeId}", hour, Environment.MachineName);if (hour == 21){await ExecuteNightlyMaintenanceAsync();}else if (hour == 4){await ExecuteEarlyMorningTasksAsync();}}catch (Exception ex){_logger.LogError(ex, "执行 {Hour} 点任务时发生错误", hour);throw;}}// 具体任务实现方法private async Task PollingTaskAsync(){// 实现游戏角色启动/关闭逻辑}private async Task ExecuteNightlyMaintenanceAsync(){// 21点特殊任务逻辑}// 其他方法...
}// BackgroundTask.cs (安全运行后台任务)
public static class BackgroundTask
{public static Task Run(Func<Task> task, ILogger logger){return Task.Run(async () =>{try{await task();}catch (Exception ex){logger.LogError(ex, "后台任务执行失败");}});}
}

3. 任务调度配置层

3.1 任务初始化器

// RecurringJobInitializer.cs
public class RecurringJobInitializer : IHostedService
{private readonly IRecurringJobManager _jobManager;private readonly IServiceProvider _services;private readonly ILogger<RecurringJobInitializer> _logger;public RecurringJobInitializer(IRecurringJobManager jobManager,IServiceProvider services,ILogger<RecurringJobInitializer> logger){_jobManager = jobManager;_services = services;_logger = logger;}public Task StartAsync(CancellationToken cancellationToken){try{using var scope = _services.CreateScope();var pollingService = scope.ServiceProvider.GetRequiredService<IPollingService>();// 每30分钟执行的任务_jobManager.AddOrUpdate<IPollingService>("polling-tasks-30min",s => s.ExecutePollingTasksAsync(),"*/30 * * * *");// 每天21:00执行的任务_jobManager.AddOrUpdate<IPollingService>("daily-task-21:00",s => s.ExecuteDailyTaskAsync(21),"0 21 * * *");// 每天04:00执行的任务_jobManager.AddOrUpdate<IPollingService>("daily-task-04:00",s => s.ExecuteDailyTaskAsync(4),"0 4 * * *");_logger.LogInformation("周期性任务初始化完成");}catch (Exception ex){_logger.LogError(ex, "初始化周期性任务失败");throw;}return Task.CompletedTask;}public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}

4. 应用启动配置

4.1 Program.cs

var builder = WebApplication.CreateBuilder(args);// 添加Redis
builder.Services.AddSingleton<IConnectionMultiplexer>(sp => ConnectionMultiplexer.Connect(builder.Configuration.GetConnectionString("Redis")));// 配置Hangfire
builder.Services.AddHangfire(config =>
{config.UseRedisStorage(builder.Configuration.GetConnectionString("Redis"),new RedisStorageOptions{Prefix = "hangfire:",Db = 1 // 使用单独的Redis数据库});config.UseColouredConsoleLogProvider();
});builder.Services.AddHangfireServer(options =>
{options.ServerName = $"{Environment.MachineName}:{Guid.NewGuid():N}";options.WorkerCount = 1;options.Queues = new[] { "default", "critical" };
});// 注册服务
builder.Services.AddSingleton<IDistributedLockService, RedisDistributedLockService>();
builder.Services.AddScoped<IPollingService, PollingService>();
builder.Services.AddHostedService<RecurringJobInitializer>();var app = builder.Build();// 配置Hangfire仪表盘
app.UseHangfireDashboard("/jobs", new DashboardOptions
{DashboardTitle = "任务调度中心",Authorization = new[] { new HangfireDashboardAuthorizationFilter() },StatsPollingInterval = 60_000 // 60秒刷新一次
});app.Run();// Hangfire仪表盘授权过滤器
public class HangfireDashboardAuthorizationFilter : IDashboardAuthorizationFilter
{public bool Authorize(DashboardContext context){var httpContext = context.GetHttpContext();return httpContext.User.Identity?.IsAuthenticated == true;}
}

5. appsettings.json 配置

{"ConnectionStrings": {"Redis": "localhost:6379,allowAdmin=true","Hangfire": "Server=(localdb)\\mssqllocaldb;Database=Hangfire;Trusted_Connection=True;"},"Hangfire": {"WorkerCount": 1,"SchedulePollingInterval": 5000}
}

关键设计说明

  1. 分布式锁

    • 使用Redis RedLock算法实现
    • 自动处理锁的获取和释放
    • 包含完善的错误处理和日志记录
  2. 任务隔离

    • 使用Hangfire的[DisableConcurrentExecution]防止同一任务重复执行
    • 分布式锁确保跨节点唯一执行
  3. 错误处理

    • 所有关键操作都有try-catch和日志记录
    • 后台任务使用安全包装器执行
  4. 可观测性

    • 详细的日志记录
    • Hangfire仪表盘监控
  5. 扩展性

    • 可以轻松添加新任务
    • 支持动态调整调度策略

这个实现方案完全符合.NET 6的最佳实践,支持分布式部署,确保任务在集群环境中安全可靠地执行。

相关文章:

完整的 .NET 6 分布式定时任务实现(Hangfire + Redis 分布式锁)

完整的 .NET 6 分布式定时任务实现&#xff08;Hangfire Redis 分布式锁&#xff09; 以下是完整的解决方案&#xff0c;包含所有必要组件&#xff1a; 1. 基础设施层 1.1 分布式锁服务 // IDistributedLockService.cs public interface IDistributedLockService {ValueTa…...

人脸识别联合行为检测的办公管理新模式

基于人脸识别与行为检测的办公智能化解决方案 一、背景 在传统办公场景中&#xff0c;员工考勤管理、工位使用情况统计、安全监控等环节存在诸多痛点。例如&#xff0c;传统考勤方式如指纹打卡、刷卡等存在代打卡现象&#xff0c;考勤数据不准确&#xff1b;对于员工是否在工…...

鸿蒙NEXT开发键盘工具类(ArkTs)

export declare type KeyboardCallBack (show: boolean, height: number) > void; import { AppUtil } from ./AppUtil; import { LogUtil } from ./LogUtil; import { ArrayUtil } from ./ArrayUtil;/*** 键盘工具类* author 鸿蒙布道师* since 2025/04/18*/ export class…...

Python爬虫第17节-动态渲染页面抓取之Selenium使用下篇

目录 引言 一、获取节点信息 1.1 获取属性 1.2 获取文本值 1.3 获取ID、位置、标签名、大小 二、切换Frame 三、延时等待 3.1 隐式等待 3.2 显式等待 四、前进后退 五、Cookies 六、选项卡管理 七、异常处理 引言 这一节我们继续讲解Selenium的使用下篇&#xff0…...

【数据结构】第四弹——LinkedList与链表

文章目录 一. ArrayList 的缺陷二.链表2.1 链表的概念及结构2.2 链表的结构2.2.1 单向或者双向2.2.2 带头或者不带头2.2.3 循环非循环 2.3 链表的实现1. IList接口2. MySingleList 类中具体实现(不带头单向非循环链表)1. 节点抽象成内部类手搓一个链表2. 头插法3. 尾插法4. 指定…...

设计模式从入门到精通之(五)观察者模式

观察者模式&#xff1a;实现高效事件通知的秘诀 在日常生活中&#xff0c;我们经常需要同步通知多方的信息变更。比如天气预报系统、股票价格波动提醒、社交媒体的点赞通知等。这些场景中&#xff0c;通知机制需要高效、灵活&#xff0c;而不会因为通知方的变化影响系统整体。 …...

chili3d调试笔记3 加入c++ 大模型对话方法 cmakelists精读

加入 #include <emscripten/bind.h> #include <emscripten/val.h> #include <nlohmann/json.hpp> 怎么加包 函数直接用emscripten::function&#xff0c;如&#xff1a; emscripten::function("send_to_llm", &send_to_llm); set (CMAKE_C…...

使用人工智能大模型kimi,如何免费制作PPT?

使用人工智能大模型kimi&#xff0c;如何免费制作PPT&#xff1f; 手把手操作视频https://edu.csdn.net/learn/40406/666573...

ModbusTCP 转 Profinet 主站网关

一、 功能概述 1.1 设备简介 本产品是 ModbusTCP 和 Profinet(M) 网关&#xff08;以下简称网关&#xff09;&#xff0c;使用数据映射 方式工作。 本产品在 ModbusTCP 侧作为 ModbusTCP 从站&#xff0c;接 PLC 、上位机、 wincc 屏 等&#xff1b;在 Profin…...

进阶篇|CAN FD 与性能优化

引言 1. CAN vs. CAN FD 对比 2. CAN FD 帧结构详解...

6.6 “3步调用ChatGPT打造高可靠Python调度器,零依赖实现定时任务自动化“

3步调用ChatGPT打造高可靠Python调度器,零依赖实现定时任务自动化 关键词:ChatGPT代码生成、Python调度器设计、定时任务自动化、异常处理机制、日志监控系统 需求分析与技术选型 GitHub Sentinel 需要实现两种定时任务模式: #mermaid-svg-prOScv2NNhn6w90N {font-family:…...

HarmonyOS 基础语法概述 UI范式

ArkUI框架 - UI范式 ArkTS的基本组成 装饰器&#xff1a; 用于装饰类、结构、方法以及变量&#xff0c;并赋予其特殊的含义。如上述示例中Entry、Component和State都是装饰器&#xff0c;Component表示自定义组件&#xff0c;Entry表示该自定义组件为入口组件&#xff0c;Stat…...

23种设计模式-创建型模式之建造者模式(Java版本)

Java 建造者模式&#xff08;Builder Pattern&#xff09;详解 &#x1f9f1; 什么是建造者模式&#xff1f; 建造者模式用于将一个复杂对象的构建过程与其表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 适用于创建过程复杂、构造顺序稳定但组件变化的对象。…...

【AI提示词】退休规划顾问专家

提示说明 随着人口老龄化的加剧&#xff0c;越来越多的人开始关注退休规划问题。一个专业的退休规划顾问可以帮助用户合理规划退休生活&#xff0c;确保退休后的生活质量。 提示词 # 角色 退休规划顾问专家## 注意 1. 专家设计应符合退休规划的专业性和可靠性&#xff0c;帮…...

文献总结:NIPS2023——车路协同自动驾驶感知中的时间对齐(FFNet)

FFNet 一、文献基本信息二、背景介绍三、相关研究1. 以自车为中心的3D目标检测2. 车路协同3D目标检测3. 特征流 四、FFNet网络架构1. 车路协同3D目标检测任务定义2. 特征流网络2.1 特征流生成2.2 压缩、传输与解压缩2.3 车辆传感器数据与基础设施特征流融合 3. 特征流网络训练流…...

(二十六)Java观察者模式在Android开发中的应用详解

Java观察者模式在Android开发中的应用 观察者模式&#xff08;Observer Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一种一对多的依赖关系&#xff0c;使得多个观察者对象可以同时监听一个主题对象。当主题对象的状态发生变化时&#xff0c;所有注册的观察者…...

goland做验证码识别时报“undefined: gosseract.NewClient”

gosseract 应该有 和 c 相关的配置库因此需要安装 cgo 并且启用 CGO_ENABLED 在cmd下面输入这个 go env -w CGO_ENABLED1 接着输入 go env 验证是否设置成功 解决了这个问题后 “undefined: gosseract.NewClient” 又出现了 # runtime/cgo …...

ceph weight 和 reweight 的区别

ceph osd df ID CLASS WEIGHT REWEIGHT SIZE RAW USE DATA OMAP META AVAIL %USE VAR PGS STATUS0 nvme 6.98630 0.95508 7.0 TiB 5.0 TiB 4.9 TiB 13 GiB 33 GiB 2.0 TiB 71.10 0.96 83 up1 nvme 6.98630...

# 使用 PyTorch 构建并训练一个简单的 CNN 模型进行图像分类

使用 PyTorch 构建并训练一个简单的 CNN 模型进行图像分类 在深度学习领域&#xff0c;卷积神经网络&#xff08;CNN&#xff09;是处理图像分类任务的强大工具。本文将通过一个简单的示例&#xff0c;展示如何使用 PyTorch 构建、训练和测试一个 CNN 模型&#xff0c;用于对食…...

Linux网络编程 深入解析TFTP协议:基于UDP的文件传输实战

知识点1【TFTP的概述】 学习通信的基本&#xff1a;通信协议&#xff08;具体发送上面样的报文&#xff09;、通信流程&#xff08;按照什么步骤发送&#xff09; 1、TFTP的概述 tftp&#xff1a;简单文件传输协议&#xff0c;**基于UDP&#xff0c;**不进行用户有效性验证 …...

汽车免拆诊断案例 | 2019款大众途观L车鼓风机偶尔不工作

故障现象 一辆2019款大众途观L车&#xff0c;搭载DKV发动机和0DE双离合变速器&#xff0c;累计行驶里程约为8万km。车主进厂反映&#xff0c;鼓风机偶尔不工作。 故障诊断  接车后试车&#xff0c;鼓风机各挡位均工作正常。用故障检测仪检测&#xff0c;空调控制单元&#x…...

编程常见错误归类

上一篇讲了调试&#xff0c;今天通过一个举例回忆一下上一篇内容吧&#xff01; 1. 回顾&#xff1a;调试举例 在VS2022、X86、Debug的环境下&#xff0c;编译器不做任何优化的话&#xff0c;下⾯代码执⾏的结果是啥&#xff1f; #include <stdio.h> int main() {int …...

Python 3.13 support for PyTorch

Python 3.13 support for PyTorch Python 3.13 support for PyTorch 去官网可以查到具体信息&#xff1a;https://pytorch.org/get-started/locally/ 然后选择自己的CUDA版本&#xff0c;下面会显示下载网站&#xff0c;比如我选择12.4&#xff0c;则会出现&#xff1a;pip3 …...

中国联通:《DeepSeek洞察与大模型应用:人工智能技术发展与应用实践》(可下载)

近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术迅猛发展&#xff0c;尤其是大模型技术的崛起&#xff0c;正在深刻改变各行各业的运营模式和创新路径。作为中国通信行业的领军企业之一&#xff0c;中国联通积极拥抱AI技术变革&#xff0c;结合自身在通信网络、大数…...

k8s 调整Node节点 Max_Pods

默认情况下&#xff0c;Kubernetes集群中一个Node最多能起110个Pod。 这是基于性能和资源管理的考虑&#xff0c;以确保Kubernetes集群的稳定性和可靠性。 查看kht125节点上支持的最大pod数量: kubectl describe node kht125 | grep -i “Capacity|Allocatable” -A 6 调整…...

VR拍摄要点与技巧有哪些?有哪些最佳实践?

VR拍摄要点与技巧&#xff1a;最佳实践 VR技术通过模拟环境&#xff0c;使用户能够沉浸在一个完全由计算机生成的虚拟世界中&#xff0c;进行互动体验。在VR拍摄领域&#xff0c;我们主要利用这一技术来创建360度全景视频或图片&#xff0c;让观众能够全方位、无死角地感受拍摄…...

使用 Docker 安装 Elastic Stack 并重置本地密码

Elastic Stack&#xff08;也被称为 ELK Stack&#xff09;是一个非常强大的工具套件&#xff0c;用于实时搜索、分析和可视化大量数据。Elastic Stack 包括 Elasticsearch、Logstash、Kibana 等组件。本文将展示如何使用 Docker 安装 Elasticsearch 并重置本地用户密码。 ###…...

安卓手机万能遥控器APP推荐

软件介绍 安卓手机也能当“家电总控台”&#xff1f;这款小米旗下的万能遥控器APP&#xff0c;直接把遥控器做成“傻瓜式操作”——不用配对&#xff0c;不连蓝牙&#xff0c;点开就能操控电视、空调、机顶盒&#xff0c;甚至其他品牌的电器&#xff01;雷总这波操作直接封神&…...

PLOS ONE:VR 游戏扫描揭示了 ADHD 儿童独特的大脑活动

在孩子的成长过程中&#xff0c;总有那么一些“与众不同”的孩子。他们似乎总是坐不住&#xff0c;课堂上小动作不断&#xff0c;注意力难以集中&#xff0c;作业总是拖拖拉拉……这些行为常常被家长和老师简单地归结为“淘气”“不听话”。然而&#xff0c;他们可能并不只是“…...

Linux 系统编程 day4 进程管道

进程间通信&#xff08;IPC&#xff09; Linux环境下&#xff0c;进程地址空间相互独立&#xff0c;任何一个进程的全局变量在另一个进程中都看不到&#xff0c;所以进程和进程之间不能互相访问&#xff0c;要交换数据必须通过内核&#xff0c;在内核中开辟一块缓冲区&#xf…...

基于DeepSeek的考研暑假日志分析

注&#xff1a;我去年考研时写了日志&#xff0c;大致记录了我每天的主要活动。由于过于琐碎&#xff0c;一直没有翻看。突发奇想&#xff0c;现在利用deepseek总结其中规律。 从你的日志中可以总结出以下规律和活动兴衰起落&#xff1a; ​​一、学习活动规律与演变​​ ​​…...

Python 写生成 应用商店(2025版) 网页 方便收集应用 ,局域网使用

工具【1】&#xff1a;nginx 配置 nginx.conf 文件 server { listen 8080; server_name example.com; location / { root E:/BIT_Soft_2025; index index.html index.htm; } # 定义错误页面 error_page 404 /4…...

LLaMA Factory多模态微调实践:微调Qwen2-VL构建文旅大模型

LLaMA Factory 是一款开源低代码大模型微调框架&#xff0c;集成了业界最广泛使用的微调技术&#xff0c;支持通过 Web UI 界面零代码微调大模型&#xff0c;目前已经成为开源社区内最受欢迎的微调框架之一&#xff0c;GitHub 星标超过 4.7 万。本教程将基于通义千问团队开源的…...

Ubuntu20.04 部署llama-factory问题集

llama3 微调教程之 llama factory 的 安装部署与模型微调过程&#xff0c;模型量化和gguf转换。_llamafactory 部署-CSDN博客 1.跟着教程 llama-factory下载不下来 来&#xff0c;试着换源&#xff0c;多试几次&#xff0c;就可以成功了。。。 2.跟着教程&#xff0c;发现无法…...

鸿蒙语言基础

准备工作 去鸿蒙官网下载开发环境 点击右侧预浏览&#xff0c;刷新和插销按钮&#xff0c;插销表示热更新&#xff0c;常用按钮。 基础语法 string number boolean const常量 数组 let s : string "1111"; console.log("string", s);let n : number …...

每天一道C语言精选编程题之字符串拷贝

题目描述 写⼀个函数my_strcpy&#xff0c;实现拷⻉字符串的功能&#xff0c;假设给定⼀个字符数组a&#xff0c;再给定⼀个字符数组b&#xff0c;将字符串a中的内容拷⻉到字符串b中&#xff0c;拷⻉内容包含字符串末尾的 \0 字符。 解法思路 使⽤ while 循环通过指针的⽅式逐…...

C#中扩展方法和钩子机制使用

1.扩展方法&#xff1a; 扩展方法允许向现有类型 “添加” 方法&#xff0c;而无需创建新的派生类型、重新编译或以其他方式修改原始类型。扩展方法是一种特殊的静态方法&#xff0c;但可以像实例方法一样进行调用。 使用场景&#xff1a; 1.当无法修改某个类的源代码&#…...

基于CNN与VGG16的图像识别快速实现指南

基于CNN与VGG16的图像识别快速实现指南 以下是从零实现代码到原理剖析的完整流程&#xff0c;包含TensorFlow/Keras框架的代码示例与关键优化技巧&#xff0c;满足快速实验需求。 一、核心原理对比 特性CNN&#xff08;基础模型&#xff09;VGG16结构深度5-10层&#xff08;如…...

中间件--ClickHouse-9--MPP架构(分布式计算架构)

1、MPP 架构基础概念 MPP(Massively Parallel Processing 大规模并行处理) 是一种分布式计算架构&#xff0c;专门设计用来高效处理大规模数据集。在这种架构下*&#xff0c;数据库被分割成多个部分&#xff0c;每个部分可以在不同的服务器节点上并行处理*。这意味着&#xff…...

如何在PDF.js中改造viewer.html以实现PDF的动态加载

在PDF.js中改造viewer.html实现PDF动态加载&#xff0c;需结合参数传递、文件流处理及跨域配置等技术。以下是综合多个技术方案的核心实现步骤&#xff1a; ​一、基础参数传递法​ 1. ​URL参数动态加载​ 通过修改viewer.html的URL参数传递PDF路径&#xff0c;适用于静态文…...

Android——动画

帧动画 帧动画就是很多张图片&#xff0c;一帧一帧的播放&#xff0c;形成的一个动画效果。 frame.xml <?xml version"1.0" encoding"utf-8"?> <animation-list xmlns:android"http://schemas.android.com/apk/res/android">&l…...

基于linux 设置无线网卡Monitor模式 sniffer抓包

硬件 TP-WN722N 开源无线网卡 网卡设置成抓包模式&#xff0c;条件是什么&#xff1f; 硬件条件 网卡芯片支持监听模式&#xff0c;外置天线或高增益天线可提升抓包效果驱动与软件条件&#xff1a;正确的驱动程序系统与权限条件 Linux&#xff1a;原生支持&#xff08;Kali …...

Ubuntu18.04安装Qt5.12

本文介绍了在Ubuntu18.04环境下安装QT QT5.12相关安装包下载地址 https://download.qt.io/archive/qt/5.12/ Linux系统下Qt的离线安装包以.run结尾 (sudo apt-get install open-vm-tools open-vm-tools-desktop解决无法paste的问题) 安装 1.cd命令 终端进入对应的文件夹下面 2.…...

克服储能领域的数据处理瓶颈及AI拓展

对于储能研究人员来说&#xff0c;日常工作中经常围绕着一项核心但有时令人沮丧的任务&#xff1a;处理实验数据。从电池循环仪的嗡嗡声到包含电压和电流读数的大量电子表格&#xff0c;研究人员的大量时间都花在了提取有意义的见解上。长期以来&#xff0c;该领域一直受到对专…...

PDF.js 生态中如何处理“添加注释\添加批注”以及 annotations.contents 属性

我们来详细解释一下在 PDF.js 生态中如何处理“添加注释”以及 annotations.contents 属性。 核心要点&#xff1a;PDF.js 本身主要是阅读器&#xff0c;不是编辑器 首先&#xff0c;最重要的一点是&#xff1a;PDF.js 的核心库 (pdfjs-dist) 主要设计用于解析和渲染&#xf…...

L38.【LeetCode题解】四数之和(双指针思想) 从汇编角度分析报错原因

目录 1.题目 2.分析 去重的代码 错误代码 3.完整代码 提交结果 1.题目 四数之和 给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元…...

【第48节】探究汇编使用特性:从基础到混合编程

目录 引言 一、调用约定的奥秘 1.1 . C调用约定&#xff08;_cdecl&#xff09; 1.2 stdcall调用约定&#xff08;_stdcall&#xff09; 1.3 fastcall快速调用约定&#xff08;_fastcall&#xff09; 1.4 thiscall调用约定&#xff08;C类成员函数&#xff09; 二、X64汇…...

【jenkins】首次配置jenkins

第一步&#xff0c;输入管理员密码 cat /var/jenkins_home/secrets/initialAdminPassword第二步&#xff0c;点击安装推荐的插件 第三步&#xff0c;创建管理员用户 第四步&#xff0c;返回实例 第五步&#xff0c; 升级jenkins 第六步&#xff0c; 修复提示 第七步&#xff0c…...

Python 项目文档编写全攻略:从入门到自动化维护

引言 在软件开发领域&#xff0c;完善的文档可提升 40% 的团队协作效率&#xff08;来源&#xff1a;IEEE 2022 年开发者调查报告 ^^1^^&#xff09;。本文将深入探讨 Python 项目文档的最佳实践&#xff0c;涵盖文档生成工具、注释规范、自动化维护等关键环节。 一、Python 文…...

基于 React 和 CodeMirror 实现自定义占位符编辑器

npm git 在前端开发中&#xff0c;我们经常需要实现各种复杂的编辑器功能&#xff0c;比如代码编辑器、富文本编辑器等。本文将介绍如何基于 React 和 CodeMirror 实现一个带有自定义占位符功能的编辑器&#xff0c;这种编辑器在模板系统、表单设计器等场景中非常有用。 一…...