Jmeter JSON Config Element插件开发_jmeter插件开发-程序员宅基地

技术标签: java  Jmeter  json  html  

目录

背景:

 简单介绍一下:

文件名:即读取的json文件路径,json数组

文件编码:即文件读取时的编码

JSON Path 表达式:用来提取JSON数据文件中的

Variable Names:在Jmeter上下文引用的变量

主要步骤如下

1、选择一个包并编写三个文件:

[组件名称].java (jmeter.config.JSONDataSet.java)

[组件名称]BeanInfo.java (jmeter.config.JSONDataSetBeanInfo.java)

[组件名称]Resources.properties (org.apache.jmeter.config.JSONDataSetResources.properties)

2、JSONDataSet.java必须实现TestBean接口。

3、JSONDataSetBeanInfo.java应该扩展org.apache.jmeter.testbeans.BeanInfoSupport

4、实现逻辑。

具体逻辑实现如下:

在JSONDataSetBeanInfo 中设置 GUI 元素:

定义资源字符串。

详细的资源定义如下:

Pom文件如下:


背景:

在项目中有个场景需要从json文件中读取数据来并且进行引用,想法是做成和CSV Data Set Config类似,可以从json文件(json数组)中循环读取数据,并且通过JsonPath(使用fastjson的JSONPath类来提取数据)来提取与之匹配的值,提取之后可以在当前线程或者其他线程进行引用。界面如下:

 

 简单介绍一下:

文件名:即读取的json文件路径,json数组

文件编码:即文件读取时的编码

JSON Path 表达式:用来提取JSON数据文件中的

Variable Names:在Jmeter上下文引用的变量

主要步骤如下

1、选择一个包并编写三个文件:

[组件名称].java (jmeter.config.JSONDataSet.java)

[组件名称]BeanInfo.java (jmeter.config.JSONDataSetBeanInfo.java)

[组件名称]Resources.properties (org.apache.jmeter.config.JSONDataSetResources.properties)

如下图:

其中[组件名称]BeanInfo.java 表示Config Element的界面,如本例中的JSONDataSet BeanInfo;[组件名称].java 表示插件的处理逻辑,如本例中的JSONDataSet.java;[组件名称]Resources.properties表示界面显示的文字,同如本例相关文件。

2、JSONDataSet.java必须实现TestBean接口。

此外,它将扩展 ConfigTestElement,并实现LoopIterationListener。(不需要迭代的不用实现)TestBean是一个标记接口,因此没有要实现的方法。扩展ConfigTestElement将使我们的组件成为测试计划中的Config元素。

3、JSONDataSetBeanInfo.java应该扩展org.apache.jmeter.testbeans.BeanInfoSupport

创建一个零参数构造函数,我们在其中调用super(CSVDataSet.class);

4、实现逻辑。

该JSONDataSet将读取一个json数组文件,并会保存它发现到JMeter的运行范围内使用JSONPath匹配的值。为每个要引用的值定义变量名称。实现TestBean 时,请注意属性。这些属性将成为用户配置JSONDataSet元素的 GUI 表单的基础。

测试开始时,JMeter 将克隆您的元素。每个线程都会得到它自己的实例。但是,如果需要,您将有机会控制克隆的完成方式。

variableNames是一个字符串,它允许用户输入我们将为其赋值的变量的名称。为什么是字符串?为什么不是一个集合?用户肯定需要输入多个(和未知数量的)变量名称吗?是的,但是如果我们使用 List 或 Collection,我们就必须编写一个 GUI 组件来处理集合,而我只想快速完成。相反,我们将让用户输入以逗号分隔的变量名称列表。

然后我实现了LoopIterationListener接口的IterationStart方法。这个“事件”的重点是当测试进入它的父控制器时通知你的组件。出于我们的目的,每次输入JSONDataSet的父控制器时,我们都会读取数据文件的新对象并设置变量。因此,对于常规控制器,每次测试循环都会导致读取一组新值。对于循环控制器,每次迭代都会这样做。每个测试线程也会得到不同的值。

具体逻辑实现如下:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package jmeter.config;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.engine.event.LoopIterationEvent;
import org.apache.jmeter.engine.event.LoopIterationListener;
import org.apache.jmeter.testbeans.TestBean;
import org.apache.jmeter.testbeans.gui.GenericTestBeanCustomizer;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.testelement.property.StringProperty;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.threads.JMeterVariables;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.util.JMeterStopThreadException;
import org.apache.jorphan.util.JOrphanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.io.*;
import java.util.*;

/**
 * Read lines from a file and split int variables.
 * <p>
 * The iterationStart() method is used to set up each set of values.
 * <p>
 * By default, the same file is shared between all threads
 * (and other thread groups, if they use the same file name).
 * <p>
 * The shareMode can be set to:
 * <ul>
 * <li>All threads - default, as described above</li>
 * <li>Current thread group</li>
 * <li>Current thread</li>
 * <li>Identifier - all threads sharing the same identifier</li>
 * </ul>
 * <p>
 * The class uses the FileServer alias mechanism to provide the different share modes.
 * For all threads, the file alias is set to the file name.
 * Otherwise, a suffix is appended to the filename to make it unique within the required context.
 * For current thread group, the thread group identityHashcode is used;
 * for individual threads, the thread hashcode is used as the suffix.
 * Or the user can provide their own suffix, in which case the file is shared between all
 * threads with the same suffix.
 */

public class JSONDataSet extends ConfigTestElement
        implements TestBean, LoopIterationListener {
    private static final Logger log = LoggerFactory.getLogger(JSONDataSet.class);

    private static final long serialVersionUID = 233L;

    private static final String EOFVALUE = // value to return at EOF
            JMeterUtils.getPropDefault("jsondataset.eofstring", "<EOF>"); //$NON-NLS-1$ //$NON-NLS-2$

    private transient String filename;

    private transient String fileEncoding;

    private transient String variableNames;


    private transient String jsonpathExpression;

    private transient boolean recycle = true;

    private transient boolean stopThread;

    private transient String[] vars;

    private transient String[] jsonPathVars;

//    private transient String alias;

    private transient String shareMode;


    /**
     * @return Returns the filename.
     */
    public String getFilename() {
        return filename;
    }

    /**
     * @param filename The filename to set.
     */
    public void setFilename(String filename) {
        this.filename = filename;
    }

    /**
     * @return Returns the file encoding.
     */
    public String getFileEncoding() {
        return fileEncoding;
    }

    /**
     * @param fileEncoding The fileEncoding to set.
     */
    public void setFileEncoding(String fileEncoding) {
        this.fileEncoding = fileEncoding;
    }

    /**
     * @return Returns the variableNames.
     */
    public String getVariableNames() {
        return variableNames;
    }

    /**
     * @param variableNames The variableNames to set.
     */
    public void setVariableNames(String variableNames) {
        this.variableNames = variableNames;
    }

    public String getJsonpathExpression() {
        return jsonpathExpression;
    }

    public void setJsonpathExpression(String jsonpathExpression) {
        this.jsonpathExpression = jsonpathExpression;
    }

    public boolean getRecycle() {
        return recycle;
    }

    public void setRecycle(boolean recycle) {
        this.recycle = recycle;
    }

    public boolean getStopThread() {
        return stopThread;
    }

    public void setStopThread(boolean value) {
        this.stopThread = value;
    }

    public String getShareMode() {
        return shareMode;
    }

    public void setShareMode(String value) {
        this.shareMode = value;
    }


    private Object readResolve() {
        recycle = true;
        return this;
    }

    /**
     * Override the setProperty method in order to convert
     * the original String shareMode property.
     * This used the locale-dependent display value, so caused
     * problems when the language was changed.
     * If the "shareMode" value matches a resource value then it is converted
     * into the resource key.
     * To reduce the need to look up resources, we only attempt to
     * convert values with spaces in them, as these are almost certainly
     * not variables (and they are definitely not resource keys).
     */
    @Override
    public void setProperty(JMeterProperty property) {
        if (property instanceof StringProperty) {
            final String propName = property.getName();
            if ("shareMode".equals(propName)) { // The original name of the property
                final String propValue = property.getStringValue();
                if (propValue.contains(" ")) { // variables are unlikely to contain spaces, so most likely a translation
                    try {
                        final BeanInfo beanInfo = Introspector.getBeanInfo(this.getClass());
                        final ResourceBundle rb = (ResourceBundle) beanInfo.getBeanDescriptor().getValue(GenericTestBeanCustomizer.RESOURCE_BUNDLE);
                        for (String resKey : JSONDataSetBeanInfo.getShareTags()) {
                            if (propValue.equals(rb.getString(resKey))) {
                                if (log.isDebugEnabled()) {
                                    log.debug("Converted {}={} to {} using Locale: {}", propName, propValue, resKey, rb.getLocale());
                                }
                                ((StringProperty) property).setValue(resKey); // reset the value
                                super.setProperty(property);
                                return;
                            }
                        }
                        // This could perhaps be a variable name
                        log.warn("Could not translate {}={} using Locale: {}", propName, propValue, rb.getLocale());
                    } catch (IntrospectionException e) {
                        log.error("Could not find BeanInfo; cannot translate shareMode entries", e);
                    }
                }
            }
        }
        super.setProperty(property);
    }

    @Override
    public void iterationStart(LoopIterationEvent iterEvent) {
//        FileServer server = FileServer.getFileServer();
        final JMeterContext context = getThreadContext();//Jmeter 上下文
        int index = 0;
        if (vars == null) {
            String fileName = getFilename().trim();

            String mode = getShareMode();
            int modeInt = JSONDataSetBeanInfo.getShareModeAsInt(mode);
//            switch (modeInt) {
//                case JSONDataSetBeanInfo.SHARE_ALL:
//                    alias = fileName;
//                    break;
//                case JSONDataSetBeanInfo.SHARE_GROUP:
//                    alias = fileName + "@" + System.identityHashCode(context.getThreadGroup());
//                    break;
//                case JSONDataSetBeanInfo.SHARE_THREAD:
//                    alias = fileName + "@" + System.identityHashCode(context.getThread());
//                    break;
//                default:
//                    alias = fileName + "@" + mode; // user-specified key
//                    break;
//            }

            //获取引用的变量
            final String names = getVariableNames();//引用变量
            final String jsonNames = getJsonpathExpression();
            if (!StringUtils.isEmpty(names)) {
//                server.reserveFile(fileName, getFileEncoding(), alias);
                // 提取引用变量到数组
                vars = JOrphanUtils.split(names, ",");
                log.info("===============================================" + vars.toString());
                //提取JsonPath变量并存到数组
                jsonPathVars = JOrphanUtils.split(jsonNames, ",");
                log.info("jsonPathVars数组长度为:" + jsonPathVars.length);

            } else {
                throw new IllegalArgumentException("Could not split JSON Path Expression line from file:" + fileName);
            }
            trimVarNames(vars);

            //获取数据
            // TODO: fetch this once as per vars above?
            JMeterVariables threadVars = context.getVariables();

            String[] jsonLineValues = {};//存取使用JsonPath提取后的值
            //分割JsonPath表达式提取的值并存到数组
            jsonLineValues = JOrphanUtils.split(jsonNames, ",", false);
            log.info("===============================================" + fileName);
            String jsonFile = readJsonFile(fileName);
            //从json输入文件中,读取一个Json对象

            JSONArray jsonArray = JSON.parseArray(jsonFile);

            log.info("***************************index: " + "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" + iterEvent.getIteration());

            System.out.println("============================********************" + threadVars.getIteration());
            String num=threadVars.getThreadName().split("-")[1];
            index=Integer.parseInt(num);
            JSONObject jsonObject = jsonArray.getJSONObject(index);

            String line = jsonObject.toJSONString();

            log.info("===" + line);
            String jsonValue;

            for (int i = 0; i < jsonPathVars.length; i++) {
                log.info("i " + i + "==========================");
                log.info("i: " + jsonPathVars[i]);
                jsonValue = JSONPath.read(line, jsonPathVars[i]).toString();

                jsonLineValues[i] = jsonValue;
            }

            //提取Json Path匹配的值,经过jsonpath转换的值
//        lineValues = JOrphanUtils.split(line, ",", false);

            for (int a = 0; a < vars.length && a < jsonLineValues.length; a++) {
                threadVars.put(vars[a], jsonLineValues[a]);
            }

            if (jsonLineValues.length == 0) {// i.e. EOF
                if (getStopThread()) {
                    throw new JMeterStopThreadException("End of file:" + getFilename() + " detected for JSON DataSet:"
                            + getName() + " configured with stopThread:" + getStopThread() + ", recycle:" + getRecycle());
                }
                for (String var : vars) {
                    threadVars.put(var, EOFVALUE);
                }
            }

            threadVars.incIteration();
        }

    }

    /**
     * trim content of array varNames
     *
     * @param varsNames
     */
    private void trimVarNames(String[] varsNames) {
        for (int i = 0; i < varsNames.length; i++) {
            varsNames[i] = varsNames[i].trim();
        }
    }

    //读取json文件
    public static String readJsonFile(String fileName) {
        String jsonStr = "";
        try {
            File jsonFile = new File(fileName);
            FileReader fileReader = new FileReader(jsonFile);
            Reader reader = new InputStreamReader(new FileInputStream(jsonFile), "utf-8");
            int ch = 0;
            StringBuffer sb = new StringBuffer();
            while ((ch = reader.read()) != -1) {
                sb.append((char) ch);
            }
            fileReader.close();
            reader.close();
            jsonStr = sb.toString();
            return jsonStr;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }

}

在JSONDataSetBeanInfo 中设置 GUI 元素:

我们可以为组件的属性创建分组。创建的每个分组都需要一个标签和要包含在该分组中的属性名称列表。IE:

createPropertyGroup("json_data",             //$NON-NLS-1$
        new String[]{FILENAME, FILE_ENCODING, JSONPATH_EXP,VARIABLE_NAMES,
                RECYCLE, STOPTHREAD, SHAREMODE});

创建分组称为json_data,其中将包括在GUI上的输入元件 的文件名和variableNames的性质JSONDataSet。然后,我们需要定义我们希望这些属性的类型:

PropertyDescriptor p = property(FILENAME);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");        //$NON-NLS-1$
p.setValue(NOT_EXPRESSION, Boolean.TRUE);
p.setPropertyEditorClass(FileEditor.class);

p = property(FILE_ENCODING, TypeEditor.ComboStringEditor);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");        //$NON-NLS-1$
p.setValue(TAGS, getListFileEncoding());

//jsonpath表达式用","分隔
p = property(JSONPATH_EXP);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");        //$NON-NLS-1$
p.setValue(NOT_EXPRESSION, Boolean.TRUE);

p = property(VARIABLE_NAMES);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, "");        //$NON-NLS-1$
p.setValue(NOT_EXPRESSION, Boolean.TRUE);


p = property(RECYCLE);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, Boolean.TRUE);

p = property(STOPTHREAD);
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, Boolean.FALSE);

p = property(SHAREMODE, TypeEditor.ComboStringEditor);
p.setValue(RESOURCE_BUNDLE, getBeanDescriptor().getValue(RESOURCE_BUNDLE));
p.setValue(NOT_UNDEFINED, Boolean.TRUE);
p.setValue(DEFAULT, SHARE_TAGS[SHARE_ALL]);
p.setValue(NOT_OTHER, Boolean.FALSE);
p.setValue(NOT_EXPRESSION, Boolean.FALSE);
p.setValue(TAGS, SHARE_TAGS);

这实质上创建了7个属性,其值不允许为null,其默认值为""。可以为每个属性设置几个这样的属性。这是一个纲要:

NOT_UNDEFINED

该属性不会保留为null。

DEFAULT

如果NOT_UNDEFINED为true ,则必须给出默认值。

NOT_EXPRESSION

如果为true ,则不会为函数解析该值。

NOT_OTHER

这不是一个自由形式的输入字段——必须提供一个值列表。

TAGS

使用String[]作为值,这将设置可接受值的预定义列表,JMeter 将创建一个下拉选择。

此外,可以为属性指定自定义属性编辑器:

p.setPropertyEditorClass(FileEditor.class);

这将创建一个文本输入和浏览按钮,该按钮打开一个用于查找文件的对话框。

详细的GUI文件定义如下:

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package jmeter.config;

import org.apache.jmeter.testbeans.BeanInfoSupport;
import org.apache.jmeter.testbeans.gui.FileEditor;
import org.apache.jmeter.testbeans.gui.TypeEditor;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.util.JOrphanUtils;

import java.beans.PropertyDescriptor;

public class JSONDataSetBeanInfo extends BeanInfoSupport {

    static final int SHARE_ALL = 0;
    static final int SHARE_GROUP = 1;
    static final int SHARE_THREAD = 2;
    // These names must agree case-wise with the variable and property names
    private static final String FILENAME = "filename";               //$NON-NLS-1$
    private static final String FILE_ENCODING = "fileEncoding";      //$NON-NLS-1$
    private static final String VARIABLE_NAMES = "variableNames";    //$NON-NLS-1$
    private static final String JSONPATH_EXP = "jsonpathExpression";
    private static final String RECYCLE = "recycle";                 //$NON-NLS-1$
    private static final String STOPTHREAD = "stopThread";           //$NON-NLS-1$
    private static final String SHAREMODE = "shareMode";             //$NON-NLS-1$
    // Access needed from CSVDataSet
    private static final String[] SHARE_TAGS = new String[3];

    // Store the resource keys
    static {
        SHARE_TAGS[SHARE_ALL] = "shareMode.all"; //$NON-NLS-1$
        SHARE_TAGS[SHARE_GROUP] = "shareMode.group"; //$NON-NLS-1$
        SHARE_TAGS[SHARE_THREAD] = "shareMode.thread"; //$NON-NLS-1$        
    }

    public JSONDataSetBeanInfo() {
        super(JSONDataSet.class);

        createPropertyGroup("json_data",             //$NON-NLS-1$
                new String[]{FILENAME, FILE_ENCODING, JSONPATH_EXP,VARIABLE_NAMES,
                        RECYCLE, STOPTHREAD, SHAREMODE});

        PropertyDescriptor p = property(FILENAME);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, "");        //$NON-NLS-1$
        p.setValue(NOT_EXPRESSION, Boolean.TRUE);
        p.setPropertyEditorClass(FileEditor.class);

        p = property(FILE_ENCODING, TypeEditor.ComboStringEditor);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, "");        //$NON-NLS-1$
        p.setValue(TAGS, getListFileEncoding());

        //jsonpath表达式用","分隔
        p = property(JSONPATH_EXP);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, "");        //$NON-NLS-1$
        p.setValue(NOT_EXPRESSION, Boolean.TRUE);

        p = property(VARIABLE_NAMES);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, "");        //$NON-NLS-1$
        p.setValue(NOT_EXPRESSION, Boolean.TRUE);


        p = property(RECYCLE);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, Boolean.TRUE);

        p = property(STOPTHREAD);
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, Boolean.FALSE);

        p = property(SHAREMODE, TypeEditor.ComboStringEditor);
        p.setValue(RESOURCE_BUNDLE, getBeanDescriptor().getValue(RESOURCE_BUNDLE));
        p.setValue(NOT_UNDEFINED, Boolean.TRUE);
        p.setValue(DEFAULT, SHARE_TAGS[SHARE_ALL]);
        p.setValue(NOT_OTHER, Boolean.FALSE);
        p.setValue(NOT_EXPRESSION, Boolean.FALSE);
        p.setValue(TAGS, SHARE_TAGS);
    }

    public static int getShareModeAsInt(String mode) {
        if (mode == null || mode.length() == 0) {
            return SHARE_ALL; // default (e.g. if test plan does not have definition)
        }
        for (int i = 0; i < SHARE_TAGS.length; i++) {
            if (SHARE_TAGS[i].equals(mode)) {
                return i;
            }
        }
        return -1;
    }

    /**
     * @return array of String for possible sharing modes
     */
    public static String[] getShareTags() {
        String[] copy = new String[SHARE_TAGS.length];
        System.arraycopy(SHARE_TAGS, 0, copy, 0, SHARE_TAGS.length);
        return copy;
    }

    /**
     * Get the mains file encoding
     * list from https://docs.oracle.com/javase/8/docs/technotes/guides/intl/encoding.doc.html
     *
     * @return a String[] with the list of file encoding
     */
    private String[] getListFileEncoding() {
        return JOrphanUtils.split(JMeterUtils.getPropDefault("csvdataset.file.encoding_list", ""), "|"); //$NON-NLS-1$
    }
}

定义资源字符串。

在JSONDataSetResources.properties 中,我们必须定义所有字符串资源。为了提供翻译,可以创建其他文件,例如 JSONDataSetResources_ja.properties和JSONDataSetResources_de.properties。对于我们的组件,我们必须定义以下资源:

displayName

这将为将出现在菜单中的元素提供一个名称。

json_data.displayName

我们创建了一个名为csv_data的属性分组,因此我们必须为分组提供一个标签

filename.displayName

文件名输入元素的标签。

filename.shortDescription(当鼠标定位到GUI输入框名称提示性文字)

类似工具提示的帮助文本简介。

variableNames.displayName

变量名称输入元素的标签。

variableNames.shortDescription

variableNames输入元素的工具提示。

详细的资源定义如下:

displayName=JSON Data Set Config
#控制面板名称
json_data.displayName=Config the JSON Data Source
filename.displayName=FileName
filename.shortDescription=Name of the file that holds the json data (relative or absolute filename)
fileEncoding.displayName=File encoding
fileEncoding.shortDescription=The character set encoding used in the file
jsonpathExpression.displayName=JSON Path Expression(comma-delimited)
jsonpathExpression.shortDescription=JSON Path Expressions in order to match the order of data in your json data
variableNames.displayName=Variable Names (comma-delimited)
variableNames.shortDescription=List your variable names in order to match the order of columns in your json data. Keep it empty to use the first line of the file for variable names.
recycle.displayName=Recycle on EOF ?
recycle.shortDescription=Should the file be re-read from the start on reaching EOF ?
stopThread.displayName=Stop thread on EOF ?
stopThread.shortDescription=Should the thread be stopped on reaching EOF (if Recycle is false) ?
shareMode.displayName=Sharing mode
shareMode.shortDescription=Select which threads share the same file pointer
shareMode.all=All threads
shareMode.group=Current thread group
shareMode.thread=Current thread

Pom文件如下:

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"

         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>



    <groupId>com.test.jmeter</groupId>

    <artifactId>JmeterFunctions</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <packaging>jar</packaging>



    <name>JmeterFunctions</name>

    <url>http://maven.apache.org</url>



    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

    </properties>



    <repositories>



    </repositories>



    <dependencies>

        



        <dependency>

            <groupId>junit</groupId>

            <artifactId>junit</artifactId>

            <version>4.12</version>

            <scope>compile</scope>

        </dependency>

        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->

        <dependency>

            <groupId>com.alibaba</groupId>

            <artifactId>fastjson</artifactId>

            <version>1.2.73</version>

        </dependency>

        <dependency>

            <groupId>org.apache.commons</groupId>

            <artifactId>commons-lang3</artifactId>

            <version>3.4</version>

        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.zxing/zxing-parent -->



        <dependency>

            <groupId>org.apache.jmeter</groupId>

            <artifactId>ApacheJMeter_core</artifactId>

            <version>5.2.1</version>

            <exclusions>

                <exclusion>

                    <groupId>org.codehaus.groovy</groupId>

                    <artifactId>groovy-all</artifactId>

                </exclusion>

            </exclusions>

        </dependency>



        <dependency>

            <groupId>org.apache.jmeter</groupId>

            <artifactId>ApacheJMeter_java</artifactId>

            <version>5.2.1</version>

            <exclusions>

                <exclusion>

                    <groupId>org.codehaus.groovy</groupId>

                    <artifactId>groovy-all</artifactId>

                </exclusion>

            </exclusions>

        </dependency>

        <dependency>

            <groupId>org.apache.jmeter</groupId>

            <artifactId>ApacheJMeter_core</artifactId>

            <version>5.2.1</version>

        </dependency>





    </dependencies>

    <build>



        <resources>

            <resource>

                <directory>src/main/java</directory>

                <includes>

                    <include>**/*.properties</include>

                </includes>

            </resource>

            <resource>

                <directory>src/main/resources</directory>

                <includes>

                    <include>**/*.properties</include>

                </includes>

            </resource>

        </resources>





        <plugins>

            <plugin>

                <artifactId>maven-compiler-plugin</artifactId>

                <version>3.7.0</version>

                <configuration>

                    <source>1.8</source>

                    <target>1.8</target>

                </configuration>

            </plugin>



            <plugin>

                <artifactId>maven-assembly-plugin</artifactId>

                <configuration>

                    <descriptorRefs>

                        <descriptorRef>jar-with-dependencies</descriptorRef>

                    </descriptorRefs>

                    <archive>

                        <manifest>

                            <mainClass>com.test.util.GenerateSortCode</mainClass>

                        </manifest>

                    </archive>

                </configuration>

                <executions>

                    <execution>

                        <id>make-assembly</id>

                        <phase>package</phase>

                        <goals>

                            <goal>single</goal>

                        </goals>

                    </execution>

                </executions>

            </plugin>

        </plugins>

    </build>

</project>

调试组件。

 逻辑实现完后使用maven打包然后放到Jmeter\lib\ext目录下后重启Jmeter即可在Config Element中找到我们开发的JSON DataSet Config,然后可以使用json数组文件试一下,运行结果如下图:

 目前存在的问题,不能像CSV那样去一行一行的遍历json对象,想法是一次遍历一个json对象,目前还没有想到很好的办法,当前是根据线程数去访问json对象有可能产生数组越界(在Json数组比较小的时候),先记录一下流程后续再优化

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/TalorSwfit20111208/article/details/120371672

智能推荐

oracle 12c 集群安装后的检查_12c查看crs状态-程序员宅基地

文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态

解决jupyter notebook无法找到虚拟环境的问题_jupyter没有pytorch环境-程序员宅基地

文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境

国内安装scoop的保姆教程_scoop-cn-程序员宅基地

文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn

Element ui colorpicker在Vue中的使用_vue el-color-picker-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker

迅为iTOP-4412精英版之烧写内核移植后的镜像_exynos 4412 刷机-程序员宅基地

文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机

Linux系统配置jdk_linux配置jdk-程序员宅基地

文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk

随便推点

matlab(4):特殊符号的输入_matlab微米怎么输入-程序员宅基地

文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入

C语言程序设计-文件(打开与关闭、顺序、二进制读写)-程序员宅基地

文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。‍ Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。

Touchdesigner自学笔记之三_touchdesigner怎么让一个模型跟着鼠标移动-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动

【附源码】基于java的校园停车场管理系统的设计与实现61m0e9计算机毕设SSM_基于java技术的停车场管理系统实现与设计-程序员宅基地

文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计

Android系统播放器MediaPlayer源码分析_android多媒体播放源码分析 时序图-程序员宅基地

文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;amp;gt;Jni-&amp;amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图

java 数据结构与算法 ——快速排序法-程序员宅基地

文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法