
本文介绍如何在 Gatling 压测脚本中,无需手动合并列表,直接利用 Pebble 模板引擎将从响应中提取的多组结构化数据(如 uniqueId 与 deptId 映射对)动态渲染进 JSON 请求体,实现每个虚拟用户按需发送个性化更新请求。
本文介绍如何在 gatling 压测脚本中,无需手动合并列表,直接利用 pebble 模板引擎将从响应中提取的多组结构化数据(如 `uniqueid` 与 `deptid` 映射对)动态渲染进 json 请求体,实现每个虚拟用户按需发送个性化更新请求。
在 Gatling 中处理「一对多」结构化会话数据(例如从搜索接口返回的多个 {uniqueId, deptId} 对),并将其逐条用于后续更新请求,不推荐手动在 Scala 代码中拼接 Map 列表再存入 Session —— 这不仅易出错、难维护,还违背 Gatling 的声明式与流式设计理念。
✅ 正确做法是:跳过手动合并步骤,直接用 Pebble 模板按需渲染请求体。
Pebble 是 Gatling 内置支持的轻量级模板引擎(类似 Jinja2),可安全访问 Session 中的任意变量,并支持循环、条件、表达式等核心功能。你只需将原始提取的两个列表(uniqueIdList 和 deptIdList)保留在 Session 中,Pebble 即可在模板中通过索引或 zip 方式配对使用。
✅ 步骤一:保持原始提取,无需 merge
你的初始提取逻辑已足够:
.exec(http("Search for row")
.post("/app_category/search")
.body(RawFileBody("search.json"))
.check(status().is(200))
.check(jsonPath("$..uniqueId").findAll().saveAs("uniqueIdList"))
.check(jsonPath("$..deptId").findAll().saveAs("deptIdList"))
)
此时 Session 中已有两个平行 List:uniqueIdList: List[String] 和 deptIdList: List[String](类型为 java.util.List,Pebble 可直接遍历)。
✅ 步骤二:编写 Pebble 模板文件 assign-data.pebble
在 src/test/resources 下创建 assign-data.pebble,内容如下:
{
"operations": [
{% for i in range(0, uniqueIdList?size) %}
{
"uniqueId": "{{ uniqueIdList[i] }}",
"deptId": "{{ deptIdList[i] }}"
}{% if not loop.last %},{% endif %}
{% endfor %}
]
}
? 提示:range(0, list?size) 是 Pebble 推荐的索引遍历方式;loop.last 用于控制 JSON 数组末尾不加多余逗号。
✅ 步骤三:在请求中使用 PebbleFileBody
.exec(http("Update")
.post("/update_data")
.body(PebbleFileBody("assign-data.pebble"))
.header("Content-Type", "application/json")
)
⚠️ 注意事项
- Pebble 模板中变量名严格区分大小写,确保与 saveAs("xxx") 中的键名完全一致;
- 若某次请求需逐条发送(即每个 {uniqueId, deptId} 发起独立请求),应改用 forEach + exec 组合,并在每次迭代中传入单个元素(而非批量渲染);
- Pebble 不支持原生 zip,但可通过索引安全配对 —— 前提是两个列表长度一致(建议添加 .check(count.gte(1)) 等校验保障数据完整性);
- 模板语法错误会在运行时报 PebbleException,建议先用小样例验证模板逻辑。
✅ 总结
Gatling 的 Pebble 集成让动态请求体生成变得简洁、安全且可读性强。与其在 Scala 层做冗余的数据组装,不如把结构化逻辑交给模板层处理 —— 这既符合关注点分离原则,也大幅降低脚本维护成本。对于大多数批量更新类场景,PebbleFileBody 是比 ElFileBody + 手动 Session 操作更专业、更可持续的选择。










