Spring MVC HandlerMapping源码深度解析:请求映射原理与实战
1. 为什么每个Spring开发者都该啃一次HandlerMapping源码做Java Web开发的朋友Spring MVC那套东西天天在用RequestMapping、GetMapping、RestController这些注解闭着眼睛都能敲出来。但真要问一句“一个HTTP请求进来Spring到底是怎么找到对应方法的”能说清楚的人其实不多。我见过不少工作三四年的开发者写业务代码没问题一旦遇到请求404、映射冲突、拦截器不生效这类问题就只能靠猜和试效率极低。HandlerMapping就是Spring MVC里负责“请求到处理器映射”的核心接口。它做的事情听起来很简单给定一个HttpServletRequest返回一个HandlerExecutionChain。但这个简单接口背后牵扯出的是整个Spring MVC最精妙的设计之一——策略模式、适配器模式、责任链模式在这里交织RequestMappingHandlerMapping、SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping这些实现类各有各的适用场景。这篇文章我会从源码级别把HandlerMapping拆开讲透。不是那种贴一段源码翻译一遍的流水账而是结合我这些年排查线上问题的真实经验把“为什么这么设计”“什么时候会踩坑”“怎么自定义扩展”这些真正有价值的东西讲清楚。适合已经会用Spring MVC、想往深里走一步的开发者也适合正在准备面试、想把Spring底层原理讲明白的朋友。读完你至少能搞清楚请求映射的完整链路、getHandler方法的执行逻辑、映射注册的时机、以及几个高频踩坑点的根因。2. HandlerMapping接口的整体设计与思路拆解2.1 接口定义里藏着的设计哲学先看HandlerMapping接口本身Spring 5.x之后的定义非常简洁public interface HandlerMapping { HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }就一个方法。但别小看这一个方法它把“请求怎么找到处理器”这件事完全抽象出来了。接口只关心输入request和输出HandlerExecutionChain中间怎么找、用什么策略找全部交给实现类。这就是典型的策略模式——不同的映射策略可以自由替换互不干扰。为什么Spring要这么设计因为请求到处理器的映射方式实在太多了。早期有基于Bean名称的、基于URL的后来有了注解驱动的还有函数式端点的。如果把这些逻辑全塞在一个类里用if-else判断代码会烂到没法维护。抽象成接口之后每种映射方式一个实现类各管各的新增一种映射方式只需要加一个实现类符合开闭原则。HandlerExecutionChain这个返回值也值得说道。它不是单纯返回一个Handler对象而是返回了一个“执行链”里面包含handler本身和一堆拦截器Interceptor。这意味着映射的过程不只是“找到方法”还要把跟这个请求相关的拦截器组装好。这个设计把“映射”和“拦截”两个关注点优雅地结合在了一起后面讲getHandler执行流程时会详细展开。2.2 继承体系一张图看清所有实现类HandlerMapping的直接实现和间接实现类不少我按功能把它们分成几类这样理解起来更清晰实现类类型核心用途是否默认启用RequestMappingHandlerMapping注解驱动处理RequestMapping系列注解是SimpleUrlHandlerMappingURL匹配手动配置URL到Bean的映射否需手动配置BeanNameUrlHandlerMappingBean名称匹配Bean名称以/开头则作为URL是默认RouterFunctionMapping函数式处理函数式端点路由是WebFlux/新版本MVCWelcomePageHandlerMapping特殊处理欢迎页是这里有个容易混淆的点AbstractHandlerMapping是抽象基类它实现了HandlerMapping接口把拦截器管理、默认处理器、路径匹配器这些公共逻辑都封装好了。上面那些具体实现类基本都继承自它。所以真正读源码的时候AbstractHandlerMapping.getHandler()才是重头戏子类主要覆写的是getHandlerInternal()方法。提示很多人读源码时直接跳到RequestMappingHandlerMapping结果发现找不到核心逻辑就是因为核心逻辑在父类AbstractHandlerMapping里。先读父类再读子类顺序不能反。2.3 为什么默认注册了这么多HandlerMappingSpring MVC启动时会自动注册多个HandlerMapping它们有优先级顺序通过Order接口控制。请求进来后会按顺序遍历所有HandlerMapping第一个能返回非null结果的就被采用。这个设计的好处是职责分离。比如RequestMappingHandlerMapping的order是0优先级最高专门处理注解映射BeanNameUrlHandlerMapping的order是2兜底处理那些用Bean名称做URL的老式配置。这样注解映射和传统配置可以共存互不冲突。但这也带来一个坑如果你自定义了一个HandlerMapping但没设置order它可能被排到最后导致永远不生效。我见过有同事自定义映射器排查了半天最后发现是order没设对。这个后面在常见问题里会详细讲。3. 核心细节解析与实操要点3.1 AbstractHandlerMapping.getHandler的执行链路这是整个映射过程的主干我把它拆成几个关键步骤public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 第一步调用子类实现的getHandlerInternal拿到handler Object handler getHandlerInternal(request); if (handler null) { handler getDefaultHandler(); } if (handler null) { return null; } // 第二步如果handler是字符串说明是Bean名称去容器里取 if (handler instanceof String) { String handlerName (String) handler; handler obtainApplicationContext().getBean(handlerName); } // 第三步组装执行链把拦截器加进去 HandlerExecutionChain executionChain getHandlerExecutionChain(handler, request); // 第四步处理CORS配置 if (CorsUtils.isCorsRequest(request)) { // ... CORS相关处理 } return executionChain; }第一步的getHandlerInternal是抽象方法由子类实现。RequestMappingHandlerMapping在这里做的事情是从request里取出URL路径然后去它维护的映射注册表MappingRegistry里查找匹配的HandlerMethod。这个查找过程涉及路径匹配、HTTP方法匹配、参数条件匹配、请求头条件匹配等一系列复杂逻辑。第二步处理字符串类型的handler这是为了兼容BeanNameUrlHandlerMapping这种用Bean名称做映射的场景。SimpleUrlHandlerMapping返回的也是Bean名称字符串。第三步组装执行链会把所有匹配的拦截器按顺序加进去。拦截器的匹配也是基于路径的MappedInterceptor会根据URL模式判断是否应用。3.2 RequestMappingHandlerMapping的映射注册时机RequestMappingHandlerMapping的映射关系不是请求来了才建立的而是在Spring容器启动、Bean初始化完成后就注册好了。具体时机是afterPropertiesSet()方法被调用时实现了InitializingBean接口。注册过程大致是这样的扫描所有Bean找出带有Controller或RequestMapping注解的类然后解析类级别和方法级别的RequestMapping注解把每个方法封装成一个RequestMappingInfo对象存到MappingRegistry里。RequestMappingInfo是映射条件的封装它包含了PathPatternsRequestConditionURL路径条件RequestMethodsRequestConditionHTTP方法条件GET/POST等ParamsRequestCondition请求参数条件HeadersRequestCondition请求头条件ConsumesRequestConditionContent-Type条件ProducesRequestConditionAccept条件这些条件组合起来构成了一个完整的映射规则。请求进来时会拿request的各项属性去跟这些条件逐一匹配。注意MappingRegistry内部用的是MultiValueMapkey是RequestMappingInfovalue是对应的MappingRegistration列表。这意味着同一个映射条件可以对应多个处理方法虽然实际开发中很少这么干查找时会返回第一个匹配的。3.3 路径匹配的演进从AntPathMatcher到PathPatternSpring 5.3之前路径匹配用的是AntPathMatcher支持*、**、?这些通配符。5.3引入了PathPattern性能更好而且解析后的路径模式可以复用不用每次请求都重新解析。两者的主要区别特性AntPathMatcherPathPattern性能每次匹配都要解析模式模式预解析匹配更快语法支持**匹配多级路径同样支持但语义更严格尾部斜杠默认匹配默认不匹配需显式配置使用场景传统MVCWebFlux及新版MVC这个变化带来的一个实际影响是升级到Spring 5.3后如果URL末尾多了个斜杠可能突然就404了。因为PathPattern默认不匹配尾部斜杠。解决办法是配置PathMatchConfigurer设置setUseTrailingSlashMatch(true)。3.4 拦截器是怎么被组装进执行链的getHandlerExecutionChain方法负责把拦截器加进HandlerExecutionChain。逻辑不复杂但有几个细节值得注意protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); for (Interceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor (MappedInterceptor) interceptor; if (mappedInterceptor.matches(request)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; }关键点MappedInterceptor会根据路径判断是否应用普通的HandlerInterceptor则无条件加入。这意味着如果你直接实现HandlerInterceptor接口并注册为Bean它会对所有请求生效如果用MappedInterceptor包装就可以控制生效范围。实操心得很多人在拦截器里做权限校验结果发现静态资源请求也被拦截了导致页面加载异常。正确做法是用MappedInterceptor或者重写preHandle方法时排除静态资源路径。我一般建议用WebMvcConfigurer.addInterceptors来注册它内部会自动包装成MappedInterceptor可以精确控制路径。4. 实操过程与核心环节实现4.1 手写一个自定义HandlerMapping光看源码不够自己动手写一个才能真理解。下面我实现一个简单的HandlerMapping功能是所有以/api/time开头的请求都返回当前时间戳。public class TimeHandlerMapping extends AbstractHandlerMapping { Override protected Object getHandlerInternal(HttpServletRequest request) throws Exception { String path request.getRequestURI(); if (path.startsWith(/api/time)) { return new TimeHandler(); } return null; } static class TimeHandler implements HttpRequestHandler { Override public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType(application/json;charsetUTF-8); response.getWriter().write({\timestamp\: System.currentTimeMillis() }); } } }然后注册到Spring容器Configuration public class WebConfig implements WebMvcConfigurer { Bean public TimeHandlerMapping timeHandlerMapping() { TimeHandlerMapping mapping new TimeHandlerMapping(); mapping.setOrder(1); // 设置优先级在RequestMappingHandlerMapping之后 return mapping; } }这里有几个关键点第一继承AbstractHandlerMapping而不是直接实现HandlerMapping接口。因为父类帮我们处理了拦截器、CORS、默认处理器这些逻辑只需要实现getHandlerInternal就行。第二setOrder(1)很重要。RequestMappingHandlerMapping的order是0我们的自定义映射器设为1意味着注解映射优先匹配不到才走我们的逻辑。如果设为-1就会抢在注解映射前面可能导致RequestMapping失效。第三返回的handler实现了HttpRequestHandler接口。Spring MVC对不同类型的handler有不同的适配器HandlerAdapterHttpRequestHandler有专门的HttpRequestHandlerAdapter来处理。如果返回的是普通对象就需要SimpleControllerHandlerAdapter或者RequestMappingHandlerAdapter来适配。4.2 调试映射注册过程想搞清楚映射到底是怎么注册的最直接的办法是打断点。在RequestMappingHandlerMapping.afterPropertiesSet()里下断点启动应用你会看到它遍历所有Bean解析注解构建RequestMappingInfo的完整过程。如果不想打断点也可以写个测试类注入RequestMappingHandlerMapping然后调用getHandlerMethods()方法它会返回所有已注册的映射关系SpringBootTest public class MappingDebugTest { Autowired private RequestMappingHandlerMapping handlerMapping; Test public void printAllMappings() { MapRequestMappingInfo, HandlerMethod methods handlerMapping.getHandlerMethods(); methods.forEach((info, method) - { System.out.println(info method); }); } }这个输出在排查映射冲突时特别有用。我曾经遇到过一个线上问题某个接口偶尔404偶尔正常。用这个方法打印出所有映射后发现有两个Controller定义了相同的URL路径但HTTP方法条件不同导致请求路由到了错误的处理器。这种问题光看代码很难发现打印映射表一目了然。4.3 映射冲突的检测与处理Spring在注册映射时会检测冲突。如果两个方法映射到完全相同的条件启动时会直接抛异常。但如果条件部分重叠比如一个匹配/user/*一个匹配/user/listSpring不会报错运行时按优先级选择。优先级规则大致是路径越具体优先级越高。/user/list比/user/*更具体所以会优先匹配前者。但这个规则不是绝对的还跟注册顺序有关。踩坑记录有一次我在一个老项目里加了个GetMapping(/user/{id})结果发现原来GetMapping(/user/list)的接口不生效了。原因是/user/{id}被注册在了/user/list前面而{id}这种路径变量在匹配时优先级判断比较复杂。解决办法是调整方法在类中的顺序或者用更精确的路径。最稳妥的方式是避免这种模糊匹配路径设计上就区分开。5. 常见问题与排查技巧实录5.1 请求404的排查思路404是映射问题里最常见的症状。排查时按这个顺序来确认URL是否正确包括大小写、尾部斜杠、上下文路径。Spring 5.3对尾部斜杠敏感/user和/user/可能结果不同。确认HTTP方法是否匹配GetMapping只接受GET用POST请求会返回405而不是404但有些配置下可能表现为404。确认映射是否注册成功用上面说的getHandlerMethods()打印映射表。确认HandlerMapping的order自定义映射器如果order设得太小可能拦截了本该由注解映射处理的请求。确认拦截器是否放行拦截器的preHandle返回false会导致请求被中断表现可能像404。5.2 映射冲突速查表症状可能原因排查方法解决方案启动报错“Ambiguous mapping”两个方法映射条件完全相同看异常信息里的方法签名修改其中一个的路径或方法接口偶尔404路径模糊匹配冲突打印映射表检查重叠路径使用更精确的路径新加接口不生效映射器order问题检查自定义HandlerMapping的order调整order值静态资源404静态资源映射被覆盖检查addResourceHandlers配置调整资源路径或映射器order尾部斜杠导致404PathPattern默认不匹配测试带斜杠和不带斜杠的URL配置setUseTrailingSlashMatch(true)5.3 几个容易忽略的细节细节一RequestMapping在类级别和方法级别的组合。类级别定义基础路径方法级别定义子路径最终路径是两者拼接。如果类级别没写路径方法级别直接写完整路径。这个大家都知道但有个坑类级别和方法级别的produces、consumes条件也会合并如果冲突会导致映射不生效。细节二params条件的匹配。GetMapping(value/user, paramstypeadmin)表示只有请求参数typeadmin时才匹配。如果请求里没有type参数或者值不是admin这个映射就不会被选中。这个特性在做接口版本控制时很有用但容易忘记。细节三headers条件的匹配。类似params可以基于请求头做映射。比如根据Accept头返回不同格式的数据。但要注意如果请求头不匹配会直接404而不是返回默认格式。细节四组合注解的解析。GetMapping、PostMapping这些组合注解本质上是被RequestMapping元注解标注的。Spring在解析时会递归查找元注解所以自定义组合注解也能被正确识别。但自定义注解时要注意AliasFor的使用否则属性覆盖会出问题。5.4 性能相关的注意事项HandlerMapping的查找是在每次请求时都会执行的所以性能很关键。RequestMappingHandlerMapping内部用了缓存机制第一次查找某个路径时会把匹配结果缓存起来后续相同路径直接走缓存。但这个缓存有个前提路径必须是“直接匹配”的也就是没有路径变量、没有通配符。如果路径里包含{id}这种变量每次请求的URL都不同缓存就无法命中每次都要走完整的匹配流程。实操建议对于高频接口尽量避免在路径中使用路径变量或者把路径变量放在最后。比如/user/{id}/detail比/user/detail/{id}的缓存命中率更低因为前者在{id}之前的部分是固定的但整体路径仍然不同。如果性能要求极高可以考虑用SimpleUrlHandlerMapping手动配置精确路径它的查找是O(1)的。6. 从源码到实战的几点个人体会聊了这么多源码和实操最后说几个我自己的体会。HandlerMapping这套设计最值得学习的地方是它把“变化”和“不变”分离得很彻底。不变的流程获取handler、组装执行链、处理CORS放在抽象基类里变化的逻辑怎么找handler留给子类实现。这种模板方法模式的应用在Spring里随处可见理解了这一套再看其他模块的源码会轻松很多。另外读源码不要追求一次读懂所有细节。我第一遍读RequestMappingHandlerMapping的时候被MappingRegistry、RequestMappingInfo、各种RequestCondition绕得头晕。后来换个思路先搞清楚主干流程再逐个击破细节反而豁然开朗。建议你也这样先跑通一个简单请求的完整链路打断点跟一遍比死磕代码有效得多。还有一个实用技巧遇到映射相关的问题别急着改代码先把getHandlerMethods()的输出打出来看看。很多问题看一眼映射表就清楚了比瞎猜快得多。这个习惯帮我省了大量排查时间。

相关新闻

uC/OS移植到Cortex-M:os_cpu三件套与上下文切换核心解析

uC/OS移植到Cortex-M:os_cpu三件套与上下文切换核心解析

/* 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 1:28:39 阅读更多 →
Python+Tushare量化分析实战:从数据获取到策略回测的完整指南

Python+Tushare量化分析实战:从数据获取到策略回测的完整指南

/* 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 1:28:39 阅读更多 →
基于MP2642与PIC18F45K42的两串磷酸铁锂电池主动均衡方案详解

基于MP2642与PIC18F45K42的两串磷酸铁锂电池主动均衡方案详解

/* 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 1:28:39 阅读更多 →

最新新闻

Windows高DPI缩放导致软件模糊的完整排查与修复指南

Windows高DPI缩放导致软件模糊的完整排查与修复指南

1. 模糊问题的根源:高DPI缩放下,程序到底发生了什么你现在很可能正遇到这样一个场景:刚换上 2K 或 4K 显示器,系统为了让界面看得清,把缩放比例调到了 125% 或 150%。Windows 自带的设置界面很锐利,可双击某…

2026/10/16 6:49:57 阅读更多 →
Linux pthread线程控制实战:生命周期、同步与死锁排查

Linux pthread线程控制实战:生命周期、同步与死锁排查

编写 Thread 的目的,绝不只是"让函数并行跑起来"。实际开发中,真正让人头疼的往往是:线程怎么退出才安全?主线程怎么知道子线程干完了?栈空间设多大不死锁?多线程访问同一份数据时怎么保证不出错…

2026/10/16 6:49:57 阅读更多 →
CMake 中将 .c 文件当 C++ 编译:方法、链接坑与迁移建议

CMake 中将 .c 文件当 C++ 编译:方法、链接坑与迁移建议

Windows 上用 CMake 做 C/C 混合项目,这个问题隔三岔五就会有人问一次:.c文件到底能不能在 CMake 里直接编译成 C 代码。我最初遇到它,是接手一个遗留算法库的时候,核心文件全是一堆.c,主程序却早就全面 C 化了&#x…

2026/10/16 6:49:57 阅读更多 →
CAT12+SPM实战:VBM灰质体积分析全流程与避坑指南

CAT12+SPM实战:VBM灰质体积分析全流程与避坑指南

简介:这是基于MATLAB的CAT12工具箱,专为神经影像领域的体素形态计量学(VBM)分析设计,面向需要处理结构磁共振数据、比较不同个体或群体脑灰质/白质形态差异的研究者。压缩包共518个文件,约124MB&#xff0c…

2026/10/16 6:49:57 阅读更多 →
Linux用户与组管理实战:从配置文件到权限联动全解析

Linux用户与组管理实战:从配置文件到权限联动全解析

做Linux运维这些年,Linux用户与组管理是让我觉得最基础、也最容易被忽视的一块。很多新手一上来就折腾各种服务部署,等碰到权限报错、用户冲突、文件归属混乱时,才发现当初没把这套体系吃透。这篇文章不打算讲虚的,就当作一次完整…

2026/10/16 6:49:57 阅读更多 →
卡牌随机生成方案:加权随机算法与词缀池设计实战(含Java示例)

卡牌随机生成方案:加权随机算法与词缀池设计实战(含Java示例)

最近在做一个卡牌玩法原型时,遇到一个挺有意思的需求:能不能让卡牌真正意义上“全部随机生成”,而不是靠策划手动一张张配数值?于是我把整套逻辑拆成了卡牌词缀池、随机算法、稀有度权重、生成校验四层结构来设计。本文整理了一套…

2026/10/16 6:48:57 阅读更多 →

日新闻

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

个人 AI Agent 平台接入 TaoToken:统一 Key 与 API 通道的配置大纲

/* 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 0:00:05 阅读更多 →
信号与系统频域分析作业解题指南

信号与系统频域分析作业解题指南

1. 作业背景与核心要求解析信号与系统作为电子信息类专业的核心基础课,其作业设计往往直接关联课程的核心知识框架。2026年春季第六次作业的布置,通常对应着课程进展到频域分析的关键阶段。根据常规教学进度推测,本次作业可能涉及以下核心内容…

2026/10/16 0:00:05 阅读更多 →
Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

Django MVT实战:从零构建图书借阅系统,彻底搞懂Model-View-Template分层

1. 从一个"四不像"的练手项目说起如果你已经看完了Django的官方教程前几章,跟着敲完了投票应用,大概会有一种"我好像会了,又好像什么都不会"的割裂感。教程里每个知识点都是拆开的——这一章讲模型,下一章讲视…

2026/10/16 0:00:05 阅读更多 →

周新闻

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

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

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

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

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

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

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

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

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

2026/10/15 13:48:15 阅读更多 →

月新闻

我发现了一个新思路:用 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/15 0:14:36 阅读更多 →
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/15 9:49:14 阅读更多 →