在JMeter中使用JSR223处理参数化SQL查询遇问题求助
JMeter JSR223(Groovy)SQL文件处理问题解决
问题背景
在JMeter中使用JSR223 Sampler(Groovy)从分号分隔的键值对文件读取SQL查询并预处理,替代之前bash脚本传参时的字符串转义问题。核心需求:
- 从JMeter属性(如
user.properties中的SQL_FILE)读取SQL文件路径 - 提取文件中的
query键对应的SQL语句,用其余键值对替换语句中的占位符(如$name替换为John Doe) - 格式化SQL:将换行符转为空格、合并多空格为单个空格
- 将处理后的SQL存入JMeter变量
SQL_QUERY - 基于原SQL文件名(不含扩展名)和时间戳(格式:
hhmmss_MMDDYYYY)生成唯一结果文件名
当前问题
- 占位符替换未生效,例如
$name这类占位符未被替换为对应值 - 生成的结果文件名包含完整路径,仅需保留无扩展名的基础文件名
修正后的Groovy代码
import org.apache.jmeter.util.JMeterUtils import java.nio.file.* import java.text.SimpleDateFormat // 格式化SQL:换行转空格、合并多空格、去除首尾空白 String cleanQuery(String query) { return query.replaceAll("[\r\n]+", " ").replaceAll("\\s+", " ").trim() } // 替换SQL中的占位符($key格式) String substitutePlaceholders(String query, Map<String, String> properties) { properties.each { key, value -> if (key != "query") { // 跳过SQL语句本身的键 query = query.replace("\$" + key, value) } } return query } // 生成唯一结果文件名:时间戳_原文件基础名.jtl String generateResultsFilename(String sqlFilePath) { if (sqlFilePath == null || sqlFilePath.trim().isEmpty()) { throw new IllegalArgumentException("SQL文件路径为空或未提供") } // 获取时间戳(格式:HHmmss_MMddyyyy) String timestamp = new SimpleDateFormat("HHmmss_MMddyyyy").format(new Date()) // 提取原文件名(不含路径) String fileName = Paths.get(sqlFilePath).getFileName().toString() // 提取基础文件名(不含扩展名) String baseName = fileName.replaceAll(/\.[^.]*$/, "") // 拼接最终文件名 return "${timestamp}_${baseName}.jtl" } // 从JMeter属性读取SQL文件路径 String sqlFilePath = JMeterUtils.getPropDefault("SQL_FILE", "") if (sqlFilePath == null || sqlFilePath.trim().isEmpty()) { throw new IllegalArgumentException("JMeter属性中未配置SQL_FILE参数") } try { // 读取文件内容 String fileContent = new String(Files.readAllBytes(Paths.get(sqlFilePath)), "UTF-8").trim() // 解析分号分隔的键值对 Map<String, String> properties = fileContent.split(";").collectEntries { entry -> def parts = entry.split("=", 2) parts.length == 2 ? [(parts[0].trim()): parts[1].trim()] : [:] } // 提取SQL语句 String sqlQuery = properties.get("query", "").trim() if (sqlQuery.isEmpty()) { throw new IllegalArgumentException("SQL文件中未找到query键:${sqlFilePath}") } // 打印调试信息 log.info("原始SQL:${sqlQuery}") properties.each { key, value -> if (key != "query") log.info("占位符${key} = ${value}") } // 格式化SQL sqlQuery = cleanQuery(sqlQuery) log.info("格式化后SQL:${sqlQuery}") // 替换占位符 sqlQuery = substitutePlaceholders(sqlQuery, properties) log.info("最终SQL:${sqlQuery}") // 存储到JMeter变量 vars.put("SQL_QUERY", sqlQuery) log.info("SQL已成功处理并存入变量SQL_QUERY") // 生成结果文件名并存储 String resultsFile = generateResultsFilename(sqlFilePath) vars.put("RESULTS_FILE", resultsFile) log.info("结果文件名将使用:${resultsFile}") } catch (Exception e) { log.error("处理SQL文件出错:${sqlFilePath}", e) throw new RuntimeException("处理SQL文件失败:${sqlFilePath}", e) }
关键修正说明
占位符替换修复:
- 修正了SQL语句提取逻辑,从读取
sqlQuery键改为读取需求中的query键 - 保留了
$key格式的字符串替换逻辑,确保占位符能被正确匹配替换
- 修正了SQL语句提取逻辑,从读取
结果文件名修复:
- 移除了文件名中的路径部分,仅保留时间戳、原文件基础名(不含扩展名)和
.jtl后缀 - 简化了文件名处理逻辑,直接提取原文件的基础名称,避免路径干扰
- 移除了文件名中的路径部分,仅保留时间戳、原文件基础名(不含扩展名)和
内容的提问来源于stack exchange,提问作者Gajendra Shete
相关产品推荐
相关产品推荐

