Jmeter JSR223+Groovy创建、赋值与解析HashMap变量
一、源起
这是一篇为了解决工作脚本中的HashMap变量解析问题,而做的探究
二、安装Jmeter
(一)、首先检查机子上是否有安装 jdk
检查方式,在 cmd 中输入 java -version,出现如下信息,即已经安装好 jdk

检查Java JDK环境变量【这是另外一件事情,如果我啥时候有了新的电脑,没有安装过jdk,那么认真查考相关教程再来补充这个地方吧~~~】

(二)、安装Jmeter
1、下载Jmeter (切记:一定要下载Binaries 下面的文件,而不是Source下面的!!!)
https://jmeter.apache.org/download_jmeter.cgi

2、 解压 Jmeter 安装包
3、 配置Jmeter环境变量
(注意:JMETER_HOME不是必须配置,因为有时候这个路径代言,会引起Jmeter.bat访问失灵,本tip也可作为启动Jmeter排查方案)
按下面变量名和变量值配置 Jmeter 系统环境变量:
【变量名】JMETER_HOME
【变量值】D:\Program Files\apache-jmeter-5.6.3(jmeter 解压路径)
【变量名】CLASSPATH
【变量值】% JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;% JMETER_HOME%\lib\jorphan.jar;% JMETER_HOME%\lib\log4j-core-2.22.1.jar;
【变量名】Path
【变量值】在原值末尾加;然后补充======%JMETER_HOME%\bin======进去,为了能够在开始菜单中输入jmeter.bat启动程序。
三、启动Jmeter,并开始调试脚本
(一)、启动Jmeter

(二)、解决启动警告
1、识别警告
遇到了WARN警告,DS一下,说是当前版本用【扫描包】的方式来定位插件位置的办法已经被deprecated,而且即将在未来的版本中移除,我需要安装Plugins Manager插件来解决这个问题。(本以为可以带着这个问题继续,但后续进入脚本调试时,遇到了不得不解决这个问题的情况——我需要Custom JMeter Functions插件中提供的getObject功能,所以现在将解决方案列在这里)
2、解决警告
进入官网https://jmeter.apache.org/,找不到下载Plugins Manager插件的位置,于是,又请DS给出详细的下载地址,答案在此↓↓↓
https://jmeter-plugins.org/install/install 下面,点击箭头所指位置即可下载(注意:网络不太好使,下载可能比较慢,但链接是可用的,建议多尝试)

插件下载成功后,放入 %JMETER_HOME%\lib\ext 目录,重启Jmeter(警告仍会存在,但可以忽略了),选项/Options菜单下应该出现 Plugins Manager 选项

(三)、调整偏好设置
1、 界面风格及颜色 - 菜单设置,即可固定

2、 语言设置 - 临时 或者 固定
临时的话,菜单设置即可,但重启Jmeter后,界面语言会恢复默认的英文。

固定的话,需要修改配置文件

(四)、调试脚本
1 、 需求及DS方案
1/* *** ==================需求================
2 我现在的前置脚本中,已经用vars.putObjcet("s_dict")存储了一个HashMap变量,它在调试取样器中打印的值如下: 3 s_dict={div=450300, seqStr='S001', 'S002'} 4 我在后续的JSR223组件中如何获取这个变量,并使用它的值呢? 5 *** */ 6 7 // =======================DS方案====================== 8 在 JMeter 中直接通过 `vars.putObject()` 存储的对象需要使用对应的 `vars.getObject()` 方法获取。以下是详细的操作步骤和注意事项: 9 10 --- 11 12 ### 1. **获取并验证对象** 13 ```groovy 14 // 直接获取对象(假设已通过 vars.putObject 存储) 15 def sDict = vars.getObject("s_dict") 16 17 // 类型安全检查 18 if (sDict instanceof Map) { 19 log.info("✅ 成功获取HashMap对象,类型: " + sDict.getClass().name) 20 log.info("完整内容: " + sDict.toString()) 21 } else { 22 log.error(" 变量 s_dict 不是Map类型,实际类型: " + (sDict?.getClass()?.name ?: "null")) 23 throw new Exception("无效的s_dict类型") 24 } 25 ``` 26 27 --- 28 29 ### 2. **访问Map中的值** 30 ```groovy 31 // 方式1:Groovy属性风格(推荐) 32 def divCode = sDict.div 33 def seqStr = sDict.seqStr 34 35 // 方式2:传统Map.get() 36 def divCode = sDict.get("div") 37 def seqStr = sDict.get("seqStr") 38 39 // 使用值示例 40 log.info("行政区划码: ${divCode}") 41 log.info("序列字符串: ${seqStr}") 42 43 // 注意键的引号问题(调试器中显示 div=450300 的键未加引号) 44 // 实际存储时Groovy会自动处理键的字符串类型,无需担心 45 ``` 46 47 --- 48 49 ### 3. **处理调试器中显示的问题** 50 你的调试取样器显示: 51 `s_dict={div=450300, seqStr='S001', 'S002'}` 52 这里可能存在两个问题: 53 54 1. **键名引号缺失** 55 `div` 和 `seqStr` 作为键时,Groovy默认会处理为字符串,但最后的 `'S002'` 可能被误解析为值而不是键,说明原始Map构造可能有误。 56 57 2. **键值对数量异常** 58 显示的键值对数量不匹配(似乎有3个元素但只有两个键),需检查存储时的Map构造代码。 59 60 --- 61 62 ### 4. **修正原始Map的构造代码** 63 检查你的前置脚本中的Map创建代码,确保键值对正确: 64 ```groovy 65 // 错误示例(导致键不明确) 66 def badMap = [div:450300, seqStr:'S001', 'S002'] // 第三个元素缺少键名! 67 68 // 正确写法 69 def correctMap = [ 70 div: 450300, 71 seqStr: "S001", 72 nextSeq: "S002" // 明确指定键名 73 ] 74 75 // 存储修正后的Map 76 vars.putObject("s_dict", correctMap) 77 ``` 78 79 --- 80 81 ### 5. **跨线程组传递对象** 82 如果需要在 **不同线程组** 中使用该对象,需改用 `props` 代替 `vars`: 83 ```groovy 84 // 存储 85 props.putObject("GLOBAL_s_dict", sDict) 86 87 // 获取(任意线程组) 88 def globalDict = props.getObject("GLOBAL_s_dict") 89 ``` 90 91 --- 92 93 ### 6. **备用方案(兼容性更强)** 94 如果 `getObject()` 不可用(如未安装插件),改用 **JSON序列化**: 95 ```groovy 96 // --------- 前置脚本 --------- 97 import groovy.json.JsonBuilder 98 99 def sDict = [div: 450300, seqStr: "S001", nextSeq: "S002"] 100 vars.put("s_dict", new JsonBuilder(sDict).toString()) 101 102 // --------- 后续脚本 --------- 103 import groovy.json.JsonSlurper 104 105 def jsonStr = vars.get("s_dict") 106 def sDict = new JsonSlurper().parseText(jsonStr) as Map 107 ``` 108 109 --- 110 111 ### 常见问题排查表 112 113 | 现象 | 原因 | 解决方案 | 114 |------|------|----------| 115 | `getObject()` 返回 `null` | 1. 变量名拼写错误<br>2. 对象未正确存储 | 1. 检查变量名大小写<br>2. 确认前置脚本已执行 | 116 | 类转换异常 | 实际存储的不是Map类型 | 检查前置脚本中的 `putObject` 数据类型 | 117 | 键不存在错误 | 键名错误或Map构造错误 | 使用 `sDict.containsKey("div")` 检查键是否存在 | 118 119 --- 120 121 通过以上方法,你可以安全地在 JMeter 的 Groovy 脚本间传递复杂对象。如果问题仍然存在,建议: 122 1. 在前置脚本中添加 `log.info("存储的对象类型: " + sDict.getClass())` 123 2. 确保 JMeter 版本 ≥ 5.0 并安装了 **Plugins Manager** 中的 **Custom JMeter Functions** 插件(提供 `putObject/getObject` 支持)
2 、 根据DS方案,编写脚本请求代码
1 // 第一个JSR223 + Groovy请求 2 import java.util.HashMap 3 4 def seq_dict = [:] 5 6 seq_dict.put("div","450300") 7 seq_dict.put("seqStr","'S001','S002'") 8 9 vars.putObject("seq_dict",seq_dict) 10 11 12 13 // 第二个JSR223 + Groovy请求 14 import java.util.HashMap 15 16 def aMap = vars.getObject(seq_dict)? : new HashMap() 17 18 String str = Map.get("450300") 19 20 vars.put("str",str)
2、报错及问题排查
上述脚本执行报错如下:

结合DS给的方案及常见错误,排查如下:
(1)缺少Custom JMeter Functions插件——
通过 Plugins Manager 安装Custom JMeter Functions插件

重启后,仍然报原来的错误,有点崩溃,继续检查——
(2)发现第二个请求里,定义的是aMap变量,但使用的是Map变量。。改正。但改正后仍然报错。
(3)判断创建 和 获取的变量类型是否为Map,修改代码如下:
1 // 第一个请求 2 import java.util.HashMap 3 4 def seq_dict = new HashMap() 5 6 if (seq_dict instanceof Map) { 7 seq_dict.put("div","450300") 8 seq_dict.put("seqStr","'S001','S002'") 9 vars.putObject("seq_dict",seq_dict) 10 vars.put("valid","true") 11 } else { 12 vars.put("valid","false") 13 } 14 15 16 // 第二个请求 ====》 加上try catch 异常捕获逻辑 17 import java.util.HashMap 18 19 try { 20 def aMap = vars.getObject("seq_dict") 21 if (aMap instanceof Map) { 22 String str = aMap.get("450300") 23 vars.put("str",str) 24 vars.put("validObt","true") 25 } else { 26 vars.put("validObt","false") 27 } 28 29 } catch (Exception e){ 30 log.error("Failed to getObject" + e.getMessage()) 31 }
执行后,竟然不报错了!!!但是没有获取到 str值……

(4)再次浏览DS给的方案,发现它提到我的键值对存储有问题,一段调整,如下代码,竟然获取到k-v中的 value值了
// 修改第一个请求 import java.util.HashMap def seq_dict = new HashMap() if (seq_dict instanceof Map) { seq_dict.put("450300","'S001','S002'") // 这里调整了 K-V的添加方式 seq_dict.put("210000","'A001'") // 添加第二组数据 vars.putObject("seq_dict",seq_dict) vars.put("valid","true") } else { vars.put("valid","false") } // 修改第二个请求 import java.util.HashMap String dd = "450300" try { def aMap = vars.getObject("seq_dict") if (aMap instanceof Map) { if (aMap.containsKey(dd)){ String str = aMap.get(dd) vars.put("str",str) } vars.put("validObt","true") } else { vars.put("validObt","false") } } catch (Exception e){ log.error("Failed to getObject" + e.getMessage()) }

3 、 更新需求
1 /* *** 2 3 我需要将获取到的 str中的字符串 用 , 分割,分割后,返回一个字符串数组,并需要计算该数组的长度 4 5 *** */ 6 7 // =====================代码===================== 8 9 // 第一个请求 10 import java.util.HashMap 11 12 def seq_dict = new HashMap() 13 14 if (seq_dict instanceof Map) { 15 seq_dict.put("450300","'S001','S002'") 16 seq_dict.put("210000","'A001'") 17 vars.putObject("seq_dict",seq_dict) 18 vars.put("valid","true") 19 } else { 20 vars.put("valid","false") 21 } 22 23 24 // 第二个请求 25 import java.util.HashMap 26 27 // 条件获取键值对 28 String dd = "450300" 29 30 try { 31 def aMap = vars.getObject("seq_dict") 32 if (aMap instanceof Map) { 33 if (aMap.containsKey(dd)){ 34 String str = aMap.get(dd) 35 vars.put("str",str) 36 // 将获取的 str 按, 分割,获取字符串数组strArr 37 List<String> strArr = str.split(",") 38 // 将获取的字符串数组转换成字符串,检查分割结果 39 vars.put("strArr",strArr.toString() ) 40 // 并计算 字符串数组长度 41 vars.put("count", strArr.size().toString()) 42 } 43 vars.put("validObt","true") 44 } else { 45 vars.put("validObt","false") 46 } 47 48 } catch (Exception e){ 49 log.error("Failed to getObject" + e.getMessage()) 50 }
执行成功了啊!!!!!竟然成功了………………

四、祈祷明天把调试结果应用到工作脚本顺利……
阿门!
———————————————
Jmeter安装及配置部分参考链接:https://learnku.com/articles/43858
posted on 2025-03-23 19:06 Shannon_Zhang 阅读(211) 评论(0) 收藏 举报
浙公网安备 33010602011771号