基于Quartz的分布式调度任务管理WebUI组件设计与实践
我搞调度系统也有些年头了从最早的单机cron脚本到后来用Quartz做任务调度再到把它拆成一个带WebUI的分布式组件踩过的坑不算少。今天想把这套基于Quartz的分布式调度任务管理WebUI组件好好拆开聊一聊讲讲它到底是怎么设计的、怎么一步步落地、又解决了哪些实际问题。如果你正在负责某个系统的定时任务或者想给自己项目的Quartz任务加一个管理界面再或者纯粹对“怎么把调度能力做成可复用组件”这件事感兴趣这篇文章应该对你有用。我会尽量把设计思路、关键配置、实操细节都摊开来说。1. 分布式调度到底难在哪很多团队用Quartz一开始都是单机模式跑一跑任务量不大逻辑也不复杂Debug也方便。但等到实例变多、任务变多问题就来了多个节点同时跑同一个任务数据重复处理某个节点挂了任务也跟着停了想看一下任务执行情况只能翻日志非常难受。1.1 Quartz集群模式的底层逻辑先理清一个基础认知Quartz本身支持集群模式而且实现方式比想象中朴素——通过数据库表抢占锁。多个实例指向同一个数据库调度器启动时往QRTZ_LOCKS表写锁记录谁抢到锁谁就能触发对应的任务。这个过程不需要额外的中间件用的是数据库行锁Quartz源码里叫Semaphore的东西在起作用。这个机制带来的一个直接好处不用改业务代码把org.quartz.jobStore.isClustered设成true多个节点就能协同工作负载均衡和故障转移都有了。但它也引入一个新的运维负担QRTZ_开头的那些表比如QRTZ_JOB_DETAILS、QRTZ_TRIGGERS、QRTZ_CRON_TRIGGERS、QRTZ_FIRED_TRIGGERS、QRTZ_SIMPROP_TRIGGERS等等要求表结构必须一致字段不能乱改。很多项目出问题都是从“手动改库表结构想存点自定义字段”开始的改完以后Quartz反序列化和字段映射就乱了。1.2 为什么调度管理需要一个WebUI单靠Quartz提供的默认能力你可以通过API把JobDetail、Trigger塞进调度器然后任务就跑起来了。但实际运维有多繁琐做过的人都懂要手动拼Cron表达式拼错了还不知道想临时停掉一个任务得写一段Java代码重新部署想看某个任务上次跑成没成功得去翻业务日志想立刻触发一次补数据又要写临时接口。所以当时我给自己定的目标是做一整套Web管理界面把任务的创建、删除、暂停、恢复、立即执行、执行记录查询、Cron校验生成这些东西全部封装起来让同事可以不用碰代码就能管理线上任务。这个组件可以被不同项目引入改改配置就能贴合各自的业务不用每个项目都重复造一套轮子。2. 组件设计的整体思路做组件和做一个页面最大的区别在于你必须把通用性和特异性分清楚。通用部分放组件里特异性部分留给使用方。2.1 先定边界组件应该管什么、不管什么我一开始就明确了边界。组件负责的是“调度这件事本身”任务的注册、调度、触发、状态管理、历史记录。组件不负责的是具体执行逻辑任务里要处理什么数据、调哪个接口、写哪张表那是业务方通过实现接口来完成的。这个边界划清楚以后很多设计就顺了。组件的核心抽象是两个接口一个是CommonJob业务方的任务逻辑实现它组件负责按调度时间调用它另一个是JobInfo承载任务元数据包括任务名称、分组、Cron表达式、Job实现类全路径、参数Map等。WebUI操作的就是JobInfo和调度器之间的映射关系不关心任务内部做什么。这样还有一个好处任务的执行逻辑和调度逻辑解耦。业务方想改任务内容不用动调度配置想调整调度频率也不用重新部署整个业务系统。2.2 模块划分与数据流组件的模块划分我分成了四块第一块是调度核心层封装Quartz的SchedulerFactoryBean负责Scheduler实例的创建和维护所有对Quartz的裸操作都收敛在这一层不对外暴露。第二块是任务管理层提供任务增删改查、暂停恢复、触发一次、获取执行日志等接口这一层主要跟任务元数据打交道。第三块是WebAPI层把任务管理能力封装成RESTful接口供前端调用。第四块是前端资源提供一个基于Vue或React的单页应用通过接口反向代理或直连可以快速嵌入宿主项目。数据流是这样的前端发起请求WebAPI层处理后通过任务管理层调用Quartz API去操作调度器同时把任务的变更记录同步到数据库表中。任务执行时Quartz回调Job实现类执行完以后将状态、耗时、异常信息写回一张执行记录表可以有专门的清理任务定期归档。一句话总结核心思路Quartz管触发组件管元数据和展示业务Job管实际逻辑。3. 核心实操任务管理的WebUI要怎么落地这一部分是我觉得最有价值的我把实际操作中从设计到实现的关键点逐一梳理一遍每个点都标出了为什么这么做。3.1 任务列表与状态同步任务列表页面看起来简单真正做起来有个容易翻车的地方数据库里存的任务元数据和运行内存中Quartz调度器的状态不一定一致。比如任务A明明已经被删除但因为删的时候没用Quartz的unscheduleJob只在库里删了记录重启后Quartz又从数据库恢复了这个任务导致“僵尸任务”。所以我的做法是任务列表的主数据源以数据库为准但每一行的状态、下次触发时间、上次触发时间都以Quartz运行时数据为准。前端展示时先查数据库拿任务清单再调Quartz的getTrigger、getTriggerState、getNextFireTime等方法拿实时状态。状态枚举有NONE、NORMAL、PAUSED、COMPLETE、ERROR、BLOCKED这几个测下来NORMAL和PAUSED对应了绝大多数场景。列表页还做了一些考核性功能支持按分组筛选、按任务名称模糊搜索、按状态筛选。这些看似基础但在任务数量超过一百个以后没有这些功能根本没法用。3.2 几个必须覆盖的运维操作页面上必须有这么几个操作缺一不可。新建任务。表单里最核心的两个字段是Cron表达式和Job实现类完整类名。Cron表达式我做了个小工具直接在界面上选秒、分、时、日、月、周自动生成表达式也支持手动输入输入后立即做语法校验并解析出最近五次触发时间给人看。这个功能特别实用因为Cron表达式太容易写错了尤其是星期和日期的配置经常互相冲突。立即执行。说白了就是手动触发一次任务主要用于补数据、联调、验证逻辑。这个操作其实对Quartz来说有一个容易踩的坑如果任务还没执行完再次手动触发可能造成并发执行。所以我在这一块加了一个开关允许任务开启或关闭并发执行关闭并发时用的注解是DisallowConcurrentExecution但它锁的是同一个JobDetail实例只对同一个key生效这是Quartz的机制约束。暂停与恢复。暂停动作可以细分为暂停JobDetail和暂停Trigger我选择暂停Trigger。原因很简单如果暂停JobDetail所有关联Trigger都会失效恢复的时候容易漏掉部分触发器状态。暂停Trigger保留JobDetail恢复的时候把对应的Trigger还是原来那把Trigger恢复颗粒度更容易掌控。删除任务。这个操作做的时候就比较谨慎了因为删除是不可逆的。我要求页面上二次确认后端执行的顺序是先暂停Trigger再移除Trigger最后删除JobDetail。如果顺序反了可能触发Quartz内部状态异常提示虽然不影响主流程但日志里会有一堆警告排查问题的时候非常干扰。拷贝与迁移。这个是我额外加的功能实际用起来频率很高把某个任务复制一份生成新任务或者把一个任务从一个分组批量迁移到另一个分组。很多临时任务的生命周期就几天用复制功能可以少填一大半的表单字段。3.3 前端这边的交互细节前端的核心页面就三个任务列表页、任务编辑页、执行日志页。但交互细节上有几个点值得专门说说。第一个是Cron表达式的可视化。我把Quartz的Cron完整语法做成了配置化表单用户不熟的同学也不用记忆那套星号斜杠问号的规则直接表单配置即可出结果同时配一个实时解析显示区展示未来5次执行时间。这块对小白用户太友好了几乎一教就会。第二个是状态实时刷新。我给列表页做了轮询刷新30秒一次拉取成功状态和运行状态不是只有手动刷新按钮。线上问题排查的时候30秒其实是一个很合理的间隔不会给后端制造太大压力又能及时反馈。第三个是全屏模式支持前端页面用iframe嵌入宿主项目时有些父页面用了安全策略限制iframe的高度导致内容显示不全。我让Web页面在感知到自己以iframe方式被嵌入时自动切换成自适应高度模式独立部署页面时则保持全屏布局。4. 工具选型与关键配置组件要真正做到可复用工具选型比功能实现还重要。我重点说两个点后端封装到了什么程度以及前端框架怎么选。4.1 后端框架怎么选后端我选用Spring Boot核心原因在于Quartz的SchedulerFactoryBean和Spring Boot结合得太顺了配置项只要能统一管理后期集成成本就很低。Spring Boot环境下我只需要在配置文件里声明quartz的properties包括调度器实例名、线程池大小、JobStore类型、数据源信息等。其中线程池大小要单独说明默认值是10但实际业务建议根据任务并发量调整。如果某天有大批消息推送任务同时触发线程池不够就会产生任务排队虽然任务不会丢但执行时间会被拉长。我习惯把Quartz的JobStore配置成JobStoreTX因为它能更好地配合Spring管理的事务。任务执行过程中如果业务方自己的操作抛了异常JobStoreTX能保障Quartz触发记录的更新和业务操作在同一事务边界内避免状态不一致。4.2 Quartz集群模式下必须改的配置项几个关键的配置项我列在实际项目中验证过的一组org.quartz.jobStore.isClusteredtrue开启集群模式org.quartz.jobStore.clusterCheckinInterval15000默认就是这个值是调度器节点互相感知心跳的间隔org.quartz.scheduler.instanceIdAUTO让每个节点自动生成唯一实例ID这个必须设成AUTO否则多个节点同名时会冲突org.quartz.threadPool.threadCount20根据任务量调整。还有org.quartz.jobStore.tablePrefixQRTZ_如果数据库里表前缀改了这里也要对应改。最容易被忽略的是org.quartz.jobStore.driverDelegateClass不同的数据库要选不同的Delegate比如MySQL用org.quartz.impl.jdbcjobstore.StdJDBCDelegate而Oracle建议用org.quartz.impl.jdbcjobstore.oracle.OracleDelegate选错了会有锁和序列化方面的问题。集群模式下还有一个仓库容易踩的坑多个节点的系统时间必须通过NTP做同步。Quartz靠时间戳判断节点是否存活如果某个节点时钟快了五分钟它抢锁时会认为自己才是有效节点造成调度器权限飘移。4.3 前端组件与接口约定前端部分设计成可嵌入的单页应用方式有两种第一种是打包成静态资源独立部署宿主项目通过Nginx反向代理或者直接iframe引入第二种是发布成npm包宿主项目按需引入需要的视图组件。我实际推荐第二种因为第一种的iframe在遇到跨域Cookie、登录态透传时会有一堆破事。接口层面我定义了这样一组约定任务列表、任务详情、新建任务、更新任务、删除任务、暂停、恢复、立即执行、获取Cron解析结果、分页拉取执行日志。每个接口都做了权限注解操作类接口要校验当前用户有没有任务管理权限查看类接口只校验登录态。还有一个比较细节的点接口统一使用POST不搞花里胡哨的请求类型。因为这类运维管理接口的参数往往比较复杂用GET还得拼查询串而且有些参数会包含Cron表达式里的特殊字符造成转义错误。统一用POST带JSON结构体接口风格统一前端也省心。5. 常见问题与排查技巧实录我把这套组件在实际运行中遇到的典型问题和解决方法整理成了一张速查表方便大家遇到类似问题时快速对照。现象常见原因排查路径任务没有被执行Cron表达式时区问题检查Quartz的时区配置确认是TimeZone.getDefault()还是指定时区任务重复执行多个节点共用同一套定时触发逻辑但没开集群模式检查isClustered是否为true再看instanceId是否唯一任务暂停后又被执行只改了数据库状态没有调用Quartz的暂停API查看日志里是否有UnscheduleJob调用记录任务执行时间异常变长线程池大小不足导致任务排队增加threadCount同时分析任务本身的耗时界面显示任务已被删除但实际还在执行数据库状态和Quartz运行时状态不一致比较库表记录和Scheduler.getJobKeys结果手动清理孤儿任务集群模式下A节点宕机B节点长时间不接管心跳checkin配置太长调小clusterCheckinInterval同时确认网络连通性5.1 任务不执行或重复执行的排查这个是最常见的求助场景。先说“不执行”我遇到过非常多例都是因为Cron表达式时区问题。Quartz中的CronTrigger可以通过setTimeZone指定时区如果不指定会用服务器默认时区。如果服务器时区是UTC你本地算的Cron时间是北京时间那就会出现“我明明设置了每天凌晨两点跑结果下午两点跑”的诡异现象。排查方式很简单把任务详情里的触发时间字段和进程的TimeZone打印出来对比一下。再说“重复执行”部分团队以为把任务代码里加上分布式锁就万事大吉了但这是治标不治本。重复执行的本质是多个调度器实例同时认为自己是有效调度者。最朴素也最有效的排查第一步确认isClusteredtrue第二步确认所有节点的instanceId不一样第三步检查数据库的QRTZ_LOCKS表中锁记录是否在正常更新。这个表里的锁记录行数一般只有几行如果长时间不更新大概率是某个节点挂了没释放锁Quartz会通过checkin机制等一个周期再接管。5.2 节点故障引发的调度漂移所谓“调度漂移”是指原本绑定在A节点的某个任务在A节点宕机后B节点接管以后任务的下一次执行时间与原先计划时间不一致。这个问题排查时非常迷惑因为看起来就是任务错乱了。我后来定位到的原因Quartz在集群模式下任务的下次触发时间是基于NEXT_FIRE_TIME字段计算的节点接管时会基于当前时间去计算锁定和触发窗口。如果B节点和A节点之间的时间差太大“漂移”就会很明显。这也是我前面专门强调NTP时钟同步的原因。所以在组件文档里我明确要求使用方的所有调度节点必须加入统一的时钟同步策略这也是一个生产环境的基本功。5.3 数据权限与多人协作WebUI上线以后最大的争议点就是权限谁可以新建任务谁可以修改任务谁只能看任务。我在这块采用了简单的三级角色模型管理员可以操作一切操作员可以新建和更新任务但不能删除访客只能查看列表和日志。这个模型没有做到按任务分组去控制权限因为维度一多前端和后端的复杂度都会翻倍。对于大多数内部系统来说三级角色已经够用。逻辑上需要注意的点是后端必须做同样的校验不能只依赖前端隐藏按钮。有一些内部系统被人绕过前端直接调后端接口把别人的任务停掉了这种事故很伤信任。所以我在后端的每个操作接口上都做了切面鉴权用注解标记操作级别。6. 写在最后几个让组件更好用的小技巧组件的基本盘做出来以后要让它真正好用还有几个细节值得注意。一个是Cron表达式的“最近五次执行时间”解析。不要自己写解析函数Quartz自带CronExpression.getNextValidTimeAfter方法循环迭代五次就能拿到连续最近五次执行时间。这个方法比网上不少自己攒的实现可靠得多毕竟Quartz自己就是用它来算触发时间的保持同一套算法不会出现UI给他看的时间与实际调度时间不一致的问题。另一个是执行日志表的设计。我在记录执行历史时加了两列triggered_by用来记录是定时触发还是手动触发execution_ip记录具体是哪个节点执行的这个任务。这两列在排查“某次任务怎么没跑”和“为什么跑了两遍”的问题时作用巨大。还有一个小技巧是做了一个Group级别的统计页按分组展示任务总数、启用数、暂停数、当日执行次数、当日失败次数。运维复盘的时候一个组一张图比看明细列表直观得多。虽然Quartz本身不提供这种聚合统计但只要执行记录表做得好SQL聚合起来很简单。这套组件从开发到上线前后迭代了三个版本核心目标一直没变让任务调度变得透明、可控、可维护而不是大家线上出问题了大半夜爬起来翻日志。如果你也在搞类似的东西希望这篇文章里的思路和踩过的坑能帮你少走几步弯路。

相关新闻

Hyperledger Fabric核心架构与源码解析:从交易流程到实战踩坑

Hyperledger Fabric核心架构与源码解析:从交易流程到实战踩坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 1:18:19 阅读更多 →
基于阿里云OpenAPI自建DDNS:RAM最小权限与PowerShell实战

基于阿里云OpenAPI自建DDNS:RAM最小权限与PowerShell实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 1:18:19 阅读更多 →
Timeline编辑器:数据驱动的交互式流程可视化系统

Timeline编辑器:数据驱动的交互式流程可视化系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 1:17:19 阅读更多 →

最新新闻

【共创稿事节】HarmonyOS 7 Agent 开发实战 09:Agent 测试评测集

【共创稿事节】HarmonyOS 7 Agent 开发实战 09:Agent 测试评测集

做 Agent 应用最怕的不是「写不出第一版」,而是「改了第三版之后,发现第一版明明答对的题现在答错了」。大模型有随机性、提示词有耦合、工具调用有边界,靠人肉聊天抽查既覆盖不全又无法回放。这一篇我们给 Agent 配上一套离线评测集&#xf…

2026/10/17 7:41:11 阅读更多 →
智能体密钥管理实战:Hermes与Agent Vault凭据注入与安全审计

智能体密钥管理实战:Hermes与Agent Vault凭据注入与安全审计

1. 为什么智能体需要一个“管钥匙的保安”做过 Agent 项目的人大概都有过这种体验:功能跑通了,Demo 演示也很顺利,但一旦要往生产环境推,心里就开始发虚。原因往往不是模型不够聪明,也不是编排逻辑有 bug,而…

2026/10/17 7:41:11 阅读更多 →
Flink Operator State 深度解析:从原理到批量 Sink 实战

Flink Operator State 深度解析:从原理到批量 Sink 实战

1. 为什么 Operator State 值得单独拎出来讲Flink 的状态体系里,Keyed State 出镜率极高,几乎每篇讲状态的资料都会先拿 keyBy 之后的 ValueState、ListState 举例。但真正落到生产环境,有一类状态是绕不开的:它不依赖 key&#x…

2026/10/17 7:41:11 阅读更多 →
Flink Operator State 深度解析:非键控状态管理实战指南

Flink Operator State 深度解析:非键控状态管理实战指南

1. 为什么 Operator State 值得单独拎出来讲Flink 的状态管理一直是流计算里最容易被低估的一块。大部分人刚上手的时候,注意力都放在窗口、水位线、Checkpoint 这些"显眼"的机制上,等到真正在生产环境里跑起来,才发现状态才是决定…

2026/10/17 7:41:11 阅读更多 →
RPA+大模型:打造外部群聊专家级自动应答系统

RPA+大模型:打造外部群聊专家级自动应答系统

1. 从一线需求说起:为什么群聊回应也能自动到“专家级”做运营和客户成功的朋友,大概率都经历过这种状态:手机里挂着四五个外部群,每个群都在问问题,有的问报价,有的问故障排查,有的纯粹是闲聊。…

2026/10/17 7:41:11 阅读更多 →
地质工程一体化实战:从地质建模到随钻导向与压裂设计的闭环

地质工程一体化实战:从地质建模到随钻导向与压裂设计的闭环

你要是问一个油气田开发工程师,最怕听到哪句话,十有八九是——“模型是这么说的,但井不是这么钻的。”这种地质和工程互相不认账的场面,在非常规油气、复杂油气藏开发里几乎每隔几天就来一次。模型画得再漂亮,现场不买…

2026/10/17 7:40:11 阅读更多 →

日新闻

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

DeepSeek选型与部署:V3/R1、Ollama、API全攻略

简介:《DeepSeek使用方法.pdf》是一份面向DeepSeek入门及进阶用户的完整使用指南,重点围绕V3与R1两款模型的能力差异与适用场景展开,帮助读者根据任务类型与成本选择合适的模型。资源共1个PDF文件,压缩包大小约311KB,篇…

2026/10/17 0:00:25 阅读更多 →
200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

200+Deepseek润色指令拆解:从底层原理到场景落地的完整指南

简介:这是一份聚焦DeepSeek提示词优化的《200Deepseek润色指令》PDF文档,共收录两百余条可直接套用的润色指令,涵盖语法修正、风格统一、逻辑梳理、表达精炼等维度,并针对商务写作、学术论文、广告文案等场景给出差异化建议。文档…

2026/10/17 0:00:25 阅读更多 →
OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

OpenCV轮廓法物体计数系统:轻量、可控、可落地的工业级实现

简介:本资源是一份基于OpenCV的本科课程设计完整报告,面向计算机视觉初学者、图像处理学习者及高校通信/信息类专业学生,解决物体智能计数与检测结果结构化记录的实际问题。项目覆盖图像预处理、轮廓检测、边界框绘制、轨迹栏交互式参数调节、…

2026/10/17 0:00:25 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/16 21:35:51 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/17 1:44:59 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/16 15:04:24 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 21:54:38 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 3:49:43 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →