news 2026/10/29 1:09:13

JMeter 5.6.2工程化实践:从安装配置到CI/CD压测闭环

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JMeter 5.6.2工程化实践:从安装配置到CI/CD压测闭环

简介:本资源为Apache JMeter 5.6.2官方完整版压力测试工具包,面向软件测试工程师、性能测试初学者及Java技术栈开发者,用于Web应用、数据库、FTP及各类协议服务的高并发负载与稳定性评估。压缩包为RAR格式,大小88.26MB,包含bin(启动脚本jmeter.bat/jmeter.sh)、lib、apache-jmeter-5.6.2.jar等核心可执行文件及完整配置目录,开箱即用,无需额外编译或依赖安装。目前已有328人学习下载,体现了其在实际性能验证场景中的实用价值。用户可直接解压运行,快速构建线程组、HTTP/JDBC/FTP采样器、断言与监听器组成的完整测试流程,并借助内置定时器模拟真实用户行为;同时支持插件扩展,便于后续接入分布式测试或增强可视化分析能力,是开展系统瓶颈定位与性能调优的可靠基础环境。

1. JMeter 5.6.2 不是“点点点就能压”的黑匣子:它是一套可编程、可审计、可嵌入CI/CD的HTTP协议级压力测试引擎,专治接口超时、并发瓶颈、线程泄漏和证书握手失败——适合需要把压测脚本当代码管、把结果当指标看、把报告当交付物交的测试工程师与后端开发

你可能刚在某次上线前被临时拉去“跑个JMeter脚本”,结果发现线程数调到200就OOM,HTTPS请求全标红,JSON提取器死活抓不到token,BeanShell断言里写log.info(vars.get("code"))却只输出null。这不是你手生,是JMeter 5.6.2根本没打算让你当“按钮操作员”。它本质是个基于Java的轻量级协议模拟器:不走浏览器渲染,不加载CSS/JS,只发原始HTTP(S)请求、解析响应头/体、执行预编译逻辑。这意味着你能用它精准复现秒杀场景下的连接池耗尽、用JSR223+Groovy做动态签名验签、用Backend Listener实时推指标到InfluxDB、甚至把.jmx脚本塞进GitLab CI流水线自动回归。它不解决“怎么让页面快”,但能告诉你“为什么第378个请求开始504”——前提是,你得把它当工程来建,而不是当玩具来点。本文拆解的是Apache官方发布的JMeter 5.6.2正式版(2023年10月发布),完全兼容Java 8–17,原生支持HTTP/2、WebSocket采样、OAuth2.0授权管理器,并修复了5.5版本中广受诟病的Windows高DPI界面撕裂、BeanShell类加载冲突、以及HTTPS录制时SNI缺失导致的证书错误。别再搜“jmeter安装教程”然后卡在环境变量配错——我们从源码包结构开始,一砖一瓦搭出可复现、可调试、可交接的压测基线。

2. 从官网二进制包到可执行命令:解压即用背后的JVM参数博弈与Windows/Linux双平台启动逻辑

JMeter 5.6.2不是安装程序,而是一个自包含的Java应用包。它的可移植性来自对JVM运行时的强依赖,而非系统注册表或服务进程。这意味着:你配错的从来不是JMeter,而是JDK的堆内存、GC策略、或SSL上下文初始化方式。下面分平台拆解真实启动链路。

2.1 官网下载与校验:认准apache-jmeter-5.6.2.zip,拒绝镜像站“精简版”

提示:Apache官网(https://jmeter.apache.org/download_jmeter.cgi)提供SHA512校验值。下载后务必执行校验,尤其当你从国内镜像站获取时——部分镜像会替换log4j-core.jar以规避漏洞,但可能破坏JMeter内置的LogViewer功能。

# Linux/macOS下校验示例(Windows可用PowerShell Get-FileHash) wget https://dlcdn.apache.org/jmeter/binaries/apache-jmeter-5.6.2.zip wget https://dlcdn.apache.org/jmeter/binaries/apache-jmeter-5.6.2.zip.sha512 sha512sum -c apache-jmeter-5.6.2.zip.sha512 # 输出应为:apache-jmeter-5.6.2.zip: OK

校验通过后解压,你会看到标准目录结构:

apache-jmeter-5.6.2/ ├── bin/ # 启动脚本、配置文件、图标资源 │ ├── jmeter # Linux/macOS可执行shell │ ├── jmeter.bat # Windows批处理 │ ├── jmeter.properties # 全局配置主文件(关键!) │ └── system.properties # JVM系统属性覆盖(慎改) ├── lib/ # 核心jar包(包括httpcore、groovy-all、commons-math3) ├── lib/ext/ # 插件扩展目录(如jpgc-plugins、CustomSampler) └── docs/ # 离线文档(含usermanual/index.html)

2.2 JDK版本与JVM参数:为什么jmeter.bat双击闪退?根源在jvm.conf的-XX:+UseG1GC

JMeter 5.6.2官方声明支持Java 8–17,但实际生产推荐Java 11或17。Java 8虽兼容,但其默认的Parallel GC在高并发线程创建时易触发Full GC,导致压测过程CPU毛刺;Java 17的ZGC虽未默认启用,但G1GC已足够稳定。关键配置在bin/jvm.conf:

# bin/jvm.conf 关键片段(JMeter 5.6.2默认值) # JVM memory configuration # -Xms512m -Xmx1024m ← 这是默认值,但绝对不够! # -XX:+UseG1GC ← 必须启用,避免CMS GC在Java 11+被移除 # -Dfile.encoding=UTF-8 ← 强制编码,解决上传中文文件名乱码

Windows平台实操修正步骤(解决双击jmeter.bat闪退):

  1. 用记事本打开bin/jmeter.bat,找到set HEAP=-Xms1g -Xmx4g行(约第87行)
  2. 将-Xmx4g改为-Xmx8g(若物理内存≥16GB),并追加-XX:+UseG1GC -Dfile.encoding=UTF-8
  3. 保存后右键以管理员身份运行jmeter.bat(非双击!因Windows UAC限制可能导致JVM参数未生效)

Linux/macOS平台启动命令(避免GUI卡顿):

# 首次启动建议加-nojini参数禁用JINI(减少启动时间) ./jmeter -nojini -t /path/to/test.jmx -n -l result.jtl -e -o report/ # 若需GUI调试,强制指定JVM参数(绕过jvm.conf) JAVA_OPTS="-Xms2g -Xmx8g -XX:+UseG1GC -Dfile.encoding=UTF-8" ./jmeter

参数说明:-Xms2g设初始堆为2GB防频繁扩容;-Xmx8g上限防OOM;-XX:+UseG1GC启用G1垃圾收集器,降低STW停顿;-Dfile.encoding=UTF-8确保中文路径/文件名/响应体正确解析——这是解决“jmeter上传文件中文文件名乱码”的底层钥匙,而非在HTTP请求头里硬加Content-Disposition。

2.3 环境变量陷阱:JMETER_HOME不是必须的,但PATH里混入旧版本jar会直接翻车

JMeter设计上不强制依赖JMETER_HOME环境变量。其启动脚本通过cd "$(dirname "$0")/.."向上追溯定位根目录。但若你的PATH中存在旧版JMeter的lib/路径(如/opt/jmeter-5.4/lib),会导致ClassLoader优先加载老版httpcore.jar,引发NoSuchMethodError。

验证方法:

# Linux/macOS检查CLASSPATH污染 echo $CLASSPATH | grep jmeter # Windows检查 echo %CLASSPATH%

安全做法:彻底清空CLASSPATH,仅靠JMeter自身脚本管理依赖。若需全局调用,将apache-jmeter-5.6.2/bin加入PATH,而非lib目录。

3. HTTPS录制与证书信任:为什么jmeter录制https脚本总失败?根源在Root CA证书未导入系统信任库

JMeter内置HTTP(S)代理服务器(HTTP(S) Test Script Recorder),但其HTTPS录制能力高度依赖证书信任链。很多用户卡在“浏览器提示不安全连接”或“JMeter日志报PKIX path building failed”,本质是JMeter生成的动态证书未被操作系统或浏览器信任。

3.1 动态证书生成机制:jmeter/bin目录下keytool命令才是真相

JMeter 5.6.2使用keytool生成自签名CA证书(ApacheJMeterTemporaryRootCA.crt)和密钥库(proxyserver.jks)。该过程发生在首次启动Recorder时,但证书有效期仅7天(硬编码在org.apache.jmeter.protocol.http.proxy.ProxyControl类中)。过期后录制会静默失败。

手动刷新证书命令(Linux/macOS):

# 进入JMeter根目录 cd apache-jmeter-5.6.2 # 删除旧证书(谨慎!先备份) rm -f bin/ApacheJMeterTemporaryRootCA.crt bin/proxyserver.jks # 重新生成(密码默认为'password') keytool -genkeypair -alias jmeter -keyalg RSA -keysize 2048 -validity 3650 \ -keystore bin/proxyserver.jks -storepass password -keypass password \ -dname "CN=JMeter Proxy, OU=JMeter, O=Apache, L=Unknown, ST=Unknown, C=US" # 导出公钥证书 keytool -exportcert -alias jmeter -keystore bin/proxyserver.jks -storepass password \ -file bin/ApacheJMeterTemporaryRootCA.crt

3.2 浏览器信任配置:Chrome/Firefox/Edge三端差异与永久解决方案

  • Chrome & Edge(Chromium内核):
    证书必须导入操作系统级信任库(Windows:证书管理器 → 受信任的根证书颁发机构;macOS:钥匙串访问 → 系统 → 导入)。Chrome不再读取浏览器自身证书库。

  • Firefox:
    需单独导入:设置 → 隐私与安全 → 证书 → 查看证书 → 证书机构 → 导入,并勾选“信任此CA用于标识网站”。

  • 终极方案(避免每次重装):
    将ApacheJMeterTemporaryRootCA.crt转换为PEM格式并注入系统:

    # Linux(Debian/Ubuntu) sudo cp bin/ApacheJMeterTemporaryRootCA.crt /usr/local/share/ca-certificates/jmeter.crt sudo update-ca-certificates # macOS(需重启Safari/Chrome) sudo security add-trusted-cert -d -k /System/Library/Keychains/SystemRootCertificates.keychain \ bin/ApacheJMeterTemporaryRootCA.crt

3.3 录制配置避坑:端口冲突、目标控制器选择、以及HTTPS SNI缺失的玄学问题

配置项正确值错误示范后果
端口8888(默认)8080(常被Tomcat占用)JMeter启动失败,日志报Address already in use
目标控制器指向一个已存在的Thread Group留空或新建控制器录制请求全部丢失,无采样器生成
HTTPS Domains填写*或具体域名(如api.example.com)留空SNI握手失败,返回ERR_SSL_PROTOCOL_ERROR
GroupingPut each group in a new controllerDon't group大量请求混杂,无法按业务模块归类

注意:若目标站点使用Cloudflare等CDN,需在录制前关闭“Always Use HTTPS”选项,否则JMeter代理无法完成HTTP→HTTPS重定向。

4. BeanShell断言与JSR223 Groovy:从“jmeter beanshell断言”踩坑到性能压测脚本的可维护重构

BeanShell曾是JMeter早期逻辑扩展主力,但JMeter 5.6.2中BeanShell性能开销巨大(比Groovy慢5–10倍),且不支持Java 17新语法。官方文档已明确标注“BeanShell is deprecated”。真正该投入精力的是JSR223 + Groovy——它复用JVM JIT编译,支持闭包、集合操作、JSONPath原生解析,且脚本可热重载。

4.1 BeanShell断言血泪经验:为什么vars.get("code")永远是null?

现象:在HTTP请求后添加BeanShell断言,写log.info(vars.get("code"));,控制台始终输出null。
原因:BeanShell断言执行时机在采样器响应解析之后、但变量作用域未同步更新。vars对象在此处不可写,且props(全局属性)才是跨线程共享的唯一可靠载体。
解决:改用JSR223断言(Groovy),并明确作用域:

// JSR223断言(Groovy)——正确获取响应JSON中的code字段 import groovy.json.JsonSlurper def json = new JsonSlurper().parseText(prev.getResponseDataAsString()) if (json.code != 200) { Failure = true FailureMessage = "API returned code: ${json.code}, expected 200" } // vars.put("token", json.data.token) // 此处可安全写入线程局部变量

4.2 JSR223 Groovy实战:动态签名、Token续期、以及JSON结果生成文件

JMeter 5.6.2的groovy-all-3.0.11.jar已内置,无需额外引入。以下为高频场景代码模板:

场景1:HMAC-SHA256动态签名(替代BeanShell低效循环)

// JSR223 PreProcessor(放在HTTP请求前) import javax.crypto.Mac import javax.crypto.spec.SecretKeySpec import java.util.Base64 def secret = "your_api_secret" def message = "${vars.get('timestamp')}${vars.get('nonce')}${prev.getSampler().getEndpoint()}" def hmac = Mac.getInstance("HmacSHA256") hmac.init(new SecretKeySpec(secret.getBytes(), "HmacSHA256")) def signature = Base64.getEncoder().encodeToString(hmac.doFinal(message.getBytes())) vars.put("signature", signature)

场景2:Token自动续期(避免线程间Token冲突)

// JSR223 PostProcessor(放在登录请求后) import groovy.json.JsonSlurper def json = new JsonSlurper().parseText(prev.getResponseDataAsString()) def token = json.data.token def expireTime = System.currentTimeMillis() + 30 * 60 * 1000 // 30分钟过期 props.put("auth_token_${ctx.getThreadNum()}", [token: token, expire: expireTime] as String)

场景3:提取JSON结果生成独立文件(解决“jmeter提取json结果生成文件”需求)

// JSR223 PostProcessor(放在目标请求后) import groovy.json.JsonOutput def json = new groovy.json.JsonSlurper().parseText(prev.getResponseDataAsString()) def fileName = "result_${System.currentTimeMillis()}_${ctx.getThreadNum()}.json" def file = new File("${System.getProperty('user.dir')}/results/${fileName}") file.parentFile.mkdirs() file.write(JsonOutput.toJson(json), "UTF-8") log.info("Saved to ${file.absolutePath}")

逻辑说明:props.put()写入全局属性,ctx.getThreadNum()获取当前线程编号,避免多线程写同一文件;JsonOutput.toJson()自动格式化,比手动拼接字符串更健壮;file.parentFile.mkdirs()确保目录存在——这是解决“jmeter界面布局错乱”之外,另一个常被忽略的IO权限坑。

4.3 避坑:常见问题与排查指南

现象1:JSR223脚本中log.info()不输出,或输出乱码
→ 原因:JMeter日志级别默认为INFO,但log对象实际指向org.slf4j.Logger,需确认bin/jmeter.properties中log_level.jmeter=INFO未被注释;Windows控制台编码非UTF-8。
→ 解决:在jmeter.properties中取消注释log_level.jmeter=DEBUG,并在脚本开头加System.setProperty("file.encoding", "UTF-8")。

现象2:Groovy脚本报MissingPropertyException: No such property: vars for class: ScriptXXX
→ 原因:脚本类型选错(如选了“JavaScript”而非“Groovy”),或JMeter未正确加载Groovy引擎。
→ 解决:检查lib/ext/目录是否存在groovy-all-*.jar;在JSR223组件中明确选择“groovy”作为语言;重启JMeter。

现象3:BeanShell断言中ctx.getThreadNum()返回-1
→ 原因:BeanShell断言执行时ctx(JMeterContext)未完全初始化。
→ 解决:立即弃用BeanShell断言,改用JSR223 Groovy,其中ctx.getThreadNum()始终有效。

现象4:HTTPS录制后部分请求显示java.net.UnknownHostException
→ 原因:JMeter代理未正确解析DNS,尤其在企业内网使用HTTP代理时。
→ 解决:在bin/jmeter.properties中添加http.proxyHost=your.corp.proxy和http.proxyPort=8080,并设置https.nonProxyHosts=localhost|127.*|10.*|192.168.*。

5. 压测结果可视化与CI/CD集成:从jmeter性能测试步骤到InfluxDB+Grafana实时监控闭环

JMeter的.jtl结果文件本质是CSV,但直接用Excel打开会丢失时间戳精度(毫秒级被截断)、无法关联线程组层级、且不支持聚合计算。真正的工程化压测,必须打通“执行→采集→存储→展示→告警”全链路。

5.1 Backend Listener配置:绕过本地磁盘I/O瓶颈,直推InfluxDB 2.x

JMeter 5.6.2内置Backend Listener支持InfluxDB 1.x/2.x、Graphite、Prometheus。InfluxDB 2.x需使用Token认证,且Bucket名称区分大小写——这是多数教程未提及的致命细节。

配置步骤:

  1. 在jmeter.properties中启用Backend Listener:
    # 启用InfluxDB 2.x支持 influxdb2.url=http://localhost:8086 influxdb2.bucket=jmeter_results influxdb2.org=my-org influxdb2.token=my-influx-token
  2. 在测试计划中添加Backend Listener,选择org.apache.jmeter.visualizers.backend.influxdb.InfluxdbBackendListenerClient
  3. 设置influxdbMetricsSender为org.apache.jmeter.visualizers.backend.influxdb.HttpMetricsSender

关键参数表:

参数名值说明
influxdbUrlhttp://localhost:8086InfluxDB 2.x API地址,非UI地址
influxdbBucketjmeter_resultsBucket名称,必须提前在InfluxDB中创建
influxdbOrgmy-org组织名,InfluxDB 2.x必填
influxdbTokenmy-influx-tokenToken需有Bucket写权限,非API Token
applicationorder-service自定义Tag,用于多服务隔离

注意:InfluxDB 2.x的Token需在UI中生成,权限选择“Write”并指定Bucket;若填错org或bucket,JMeter日志仅报404 Not Found,无具体提示。

5.2 Grafana仪表盘配置:复用JMeter官方Dashboard(ID: 12597)

JMeter 5.6.2配套Grafana Dashboard已适配InfluxDB 2.x数据模型。导入步骤:

  1. 访问Grafana →+ Import→ 输入Dashboard ID12597
  2. 选择InfluxDB 2.x数据源,填写Bucket和Organization
  3. 关键变量修正:将$application变量查询语句改为from(bucket: "$bucket") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn: (r) => r._measurement == "jmeter") |> group(columns: ["application"]) |> distinct(column: "application")

仪表盘核心指标:

  • Active Threads Over Time:实时线程数曲线,识别线程泄漏(持续上升不回落)
  • Response Times Over Time:P95/P99响应时间,比平均值更能暴露长尾问题
  • Errors vs Responses:错误率热力图,定位特定URL的5xx爆发点
  • Bytes Throughput:吞吐量(字节/秒),验证带宽瓶颈

5.3 CI/CD集成:GitLab CI中无人值守压测的YAML模板

将JMeter脚本纳入CI流水线,实现“提交即压测”。以下为GitLab CI.gitlab-ci.yml核心片段:

stages: - test jmeter-load-test: stage: test image: openjdk:17-jdk-slim before_script: - apt-get update && apt-get install -y wget unzip - wget https://dlcdn.apache.org/jmeter/binaries/apache-jmeter-5.6.2.zip - unzip apache-jmeter-5.6.2.zip - export JMETER_HOME=$PWD/apache-jmeter-5.6.2 script: - $JMETER_HOME/bin/jmeter -n -t tests/api_test.jmx \ -l results/result.jtl \ -e -o reports/ \ -Jthreads=100 \ -Jrampup=60 \ -Jduration=300 artifacts: paths: - reports/ - results/result.jtl expire_in: 1 week only: - main

参数说明:-Jthreads=100通过JMeter属性传参,避免修改.jmx文件;-e -o reports/生成HTML报告;artifacts保留报告供人工审查;only: main确保仅主干分支触发压测。

6. 故障诊断与性能调优:从jmeter界面布局错乱到线程阻塞的深度排查技巧

JMeter 5.6.2的GUI界面问题(如“jmeter界面布局错乱、窗口控件重叠/撕裂”)表面是显示bug,深层往往指向JVM渲染管线或系统DPI缩放冲突。而真正的性能瓶颈,90%藏在jmeter.log的WARN级别日志和jstack线程快照里。下面给出一套可落地的诊断组合拳。

6.1 GUI错乱根因与修复:强制禁用硬件加速与DPI感知

现象:Windows 10/11高分辨率屏幕(如2560×1440@150%缩放)下,JMeter菜单栏文字模糊、控件重叠、拖拽窗口时内容撕裂。
原因:Java AWT/Swing在高DPI下默认启用缩放,但JMeter未适配PerMonitorV2DPI模式,导致像素渲染错位。
解决:不在JMeter层面修,而在JVM启动参数中绕过:

:: Windows jmeter.bat修正(第95行附近) set JAVA_CMD="%JAVA_HOME%\bin\java.exe" :: 添加以下JVM参数 set JAVA_OPTS=%JAVA_OPTS% -Dsun.java2d.dpiaware=false -Dsun.java2d.win.ui.scale=100 -Dswing.aatext=true

Linux/macOS同理,在jmeter脚本中添加:

JAVA_OPTS="$JAVA_OPTS -Dsun.java2d.xrender=false -Dawt.useSystemAAFontSettings=lcd"

逻辑说明:-Dsun.java2d.dpiaware=false禁用DPI感知,强制按100%渲染;-Dsun.java2d.win.ui.scale=100覆盖Windows缩放比例;-Dswing.aatext=true开启字体抗锯齿——这三者组合可消除95%的GUI撕裂,比修改Windows系统DPI设置更安全。

6.2 线程阻塞诊断:用jstack捕获JMeter线程死锁与等待队列

当压测中出现“线程数卡在50不动”、“响应时间突增至10s+”时,不要盲目调大-Xmx。先获取线程快照:

# Linux/macOS:找到JMeter进程PID(通常为java -jar ApacheJMeter.jar) ps aux | grep jmeter # 生成线程dump jstack -l <PID> > jmeter-thread-dump.log

关键分析点:

  • 查找WAITING状态线程:java.lang.Thread.State: WAITING (parking)通常表示线程在Object.wait()或LockSupport.park(),可能是线程池满或锁竞争。
  • 定位BLOCKED线程:java.lang.Thread.State: BLOCKED (on object monitor)表明线程在等待进入synchronized块,需检查自定义Sampler或PostProcessor中的静态锁。
  • 识别TIMED_WAITING异常:java.lang.Thread.State: TIMED_WAITING (sleeping)若持续超10秒,大概率是HTTP连接池耗尽(httpclient的ConnectionPoolTimeoutException)。

典型修复:

// 若发现大量线程卡在HttpClient连接获取,需调整HTTP Request Defaults // 在GUI中:HTTP Request Defaults → Advanced → Connection Pool Size → 设为200+ // 或在jmeter.properties中全局设置: httpclient4.retrycount=1 httpclient4.max.connections.per.host=200 httpclient4.max.total.connections=1000

6.3 内存泄漏取证:用VisualVM监控JMeter Heap Dump

JMeter 5.6.2的View Results Tree监听器是内存杀手。即使关闭GUI,若测试计划中残留该监听器,其缓存仍会累积响应体。取证步骤:

  1. 启动JMeter时添加JVM参数:-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/jmeter.hprof
  2. 压测中观察jmeter.log是否出现java.lang.OutOfMemoryError: Java heap space
  3. 用VisualVM打开/tmp/jmeter.hprof,按Classes排序,查找org.apache.jmeter.samplers.SampleResult实例数
    • 若超过线程数×1000,证明View Results Tree未关闭或Result Collector配置不当
  4. 修复:删除所有View Results Tree,改用Simple Data Writer写入.jtl,并在jmeter.properties中设:
    # 禁用GUI模式下的结果缓存 view.results.tree.max_size=0 # 限制单个采样器响应体最大长度(KB) sampleresult.default.encoding=UTF-8

从那以后我每次新建测试计划,第一件事就是删掉View Results Tree,第二件事是检查jmeter.properties里的view.results.tree.max_size是否为0,第三件事是用jstack在压测峰值时抓一次线程快照——哪怕当时一切正常。因为JMeter的沉默,往往比报错更危险。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 1:08:39

基于ESP32-S3的实时马赛克拼贴画显示终端设计与实现

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

作者头像 李华
网站建设 2026/10/29 1:07:28

工业嵌入式系统电源路径智能管理方案

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

作者头像 李华
网站建设 2026/10/29 1:07:28

ESP32 Wi-Fi遥控车DIY:从选型到UDP控制全攻略

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

作者头像 李华
网站建设 2026/10/29 1:06:39

SAP GUI 770 安装配置与多环境连接实战指南

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

作者头像 李华
网站建设 2026/10/29 1:04:38

TPS259483AYWPR与PIC18F4553构建工业级电源路径保护系统

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

作者头像 李华