fix(接口测试): 修复文件上传参数值勾选等问题
This commit is contained in:
parent
cc364cf1fc
commit
3813cdc120
|
@ -12,6 +12,7 @@ public class KeyValue {
|
||||||
private String type;
|
private String type;
|
||||||
private List<BodyFile> files;
|
private List<BodyFile> files;
|
||||||
private String description;
|
private String description;
|
||||||
|
private String contentType;
|
||||||
private boolean enable;
|
private boolean enable;
|
||||||
|
|
||||||
public KeyValue() {
|
public KeyValue() {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package io.metersphere.controller;
|
package io.metersphere.controller;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import io.metersphere.base.domain.User;
|
||||||
import io.metersphere.commons.utils.SessionUtils;
|
import io.metersphere.commons.utils.SessionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
@ -15,7 +16,8 @@ public class TestController {
|
||||||
|
|
||||||
|
|
||||||
@PostMapping(value = "/upload", consumes = {"multipart/form-data"})
|
@PostMapping(value = "/upload", consumes = {"multipart/form-data"})
|
||||||
public Object testUpload(@RequestPart(value = "id") String id, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles) {
|
public Object testUpload(@RequestPart(value = "id") String id, @RequestPart(value = "file") MultipartFile file, @RequestPart(value = "files") List<MultipartFile> bodyFiles
|
||||||
|
, @RequestPart(value = "user") User user, @RequestParam(value = "name") String name) {
|
||||||
JSONObject jsonObject = new JSONObject();
|
JSONObject jsonObject = new JSONObject();
|
||||||
jsonObject.put("id", id);
|
jsonObject.put("id", id);
|
||||||
jsonObject.put("file", file.getOriginalFilename());
|
jsonObject.put("file", file.getOriginalFilename());
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
<div class="kv-row" v-for="(item, index) in items" :key="index">
|
<div class="kv-row" v-for="(item, index) in items" :key="index">
|
||||||
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
|
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
|
||||||
<el-col v-if="isShowEnable" class="kv-checkbox">
|
<el-col v-if="isShowEnable" class="kv-checkbox">
|
||||||
<input type="checkbox" v-if="!isDisable(index)" @change="change" :value="item.uuid" v-model="checkedValues"
|
<input type="checkbox" v-if="!isDisable(index)" v-model="item.enable"
|
||||||
:disabled="isDisable(index) || isReadOnly"/>
|
:disabled="isReadOnly"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
<el-col>
|
<el-col>
|
||||||
|
@ -52,7 +52,7 @@
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
checkedValues: []
|
// checkedValues: []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -79,10 +79,6 @@
|
||||||
let isNeedCreate = true;
|
let isNeedCreate = true;
|
||||||
let removeIndex = -1;
|
let removeIndex = -1;
|
||||||
this.items.forEach((item, index) => {
|
this.items.forEach((item, index) => {
|
||||||
// 启用行赋值
|
|
||||||
if (this.isShowEnable) {
|
|
||||||
item.enable = this.checkedValues.indexOf(item.uuid) != -1 ? true : false;
|
|
||||||
}
|
|
||||||
if (!item.name && !item.value) {
|
if (!item.name && !item.value) {
|
||||||
// 多余的空行
|
// 多余的空行
|
||||||
if (index !== this.items.length - 1) {
|
if (index !== this.items.length - 1) {
|
||||||
|
@ -93,13 +89,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (isNeedCreate) {
|
if (isNeedCreate) {
|
||||||
// 往后台送入的复选框值布尔值
|
this.items.push(new KeyValue({enable: true}));
|
||||||
if (this.isShowEnable) {
|
|
||||||
this.items[this.items.length - 1].enable = true;
|
|
||||||
// v-model 选中状态
|
|
||||||
this.checkedValues.push(this.items[this.items.length - 1].uuid);
|
|
||||||
}
|
|
||||||
this.items.push(new KeyValue());
|
|
||||||
}
|
}
|
||||||
this.$emit('change', this.items);
|
this.$emit('change', this.items);
|
||||||
// TODO 检查key重复
|
// TODO 检查key重复
|
||||||
|
@ -112,9 +102,6 @@
|
||||||
let results = queryString ? suggestions.filter(this.createFilter(queryString)) : suggestions;
|
let results = queryString ? suggestions.filter(this.createFilter(queryString)) : suggestions;
|
||||||
cb(results);
|
cb(results);
|
||||||
},
|
},
|
||||||
uuid: function () {
|
|
||||||
return (((1 + Math.random()) * 0x100000) | 0).toString(16).substring(1);
|
|
||||||
},
|
|
||||||
createFilter(queryString) {
|
createFilter(queryString) {
|
||||||
return (restaurant) => {
|
return (restaurant) => {
|
||||||
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
|
return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0);
|
||||||
|
@ -123,15 +110,7 @@
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.items.length === 0) {
|
if (this.items.length === 0) {
|
||||||
this.items.push(new KeyValue());
|
this.items.push(new KeyValue({enable: true}));
|
||||||
} else if (this.isShowEnable) {
|
|
||||||
this.items.forEach((item, index) => {
|
|
||||||
let uuid = this.uuid();
|
|
||||||
item.uuid = uuid;
|
|
||||||
if (item.enable) {
|
|
||||||
this.checkedValues.push(uuid);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,26 +3,27 @@
|
||||||
<span class="kv-description" v-if="description">
|
<span class="kv-description" v-if="description">
|
||||||
{{ description }}
|
{{ description }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div class="kv-row" v-for="(item, index) in parameters" :key="index">
|
<div class="kv-row" v-for="(item, index) in parameters" :key="index">
|
||||||
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
|
<el-row type="flex" :gutter="20" justify="space-between" align="middle">
|
||||||
|
|
||||||
<el-col class="kv-checkbox">
|
<el-col class="kv-checkbox">
|
||||||
<input type="checkbox" v-if="!isDisable(index)" @change="change" :value="item.uuid" v-model="checkedValues"
|
<input type="checkbox" v-if="!isDisable(index)" v-model="item.enable"
|
||||||
:disabled="isDisable(index) || isReadOnly"/>
|
:disabled="isReadOnly"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col>
|
<el-col>
|
||||||
|
|
||||||
<el-input v-if="!suggestions" :disabled="isReadOnly" v-model="item.name" size="small" maxlength="200"
|
<el-input v-if="!suggestions" :disabled="isReadOnly" v-model="item.name" size="small" maxlength="200"
|
||||||
@change="change" :placeholder="keyText" show-word-limit>
|
@change="change" :placeholder="keyText" show-word-limit>
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<el-select v-if="type === 'body'" :disabled="isReadOnly" class="kv-type" v-model="item.type">
|
<el-select v-if="type === 'body'" :disabled="isReadOnly" class="kv-type" v-model="item.type" @change="typeChange(item)">
|
||||||
<el-option value="text"/>
|
<el-option value="text"/>
|
||||||
<el-option value="file"/>
|
<el-option value="file"/>
|
||||||
</el-select>
|
</el-select>
|
||||||
</template>
|
</template>
|
||||||
</el-input>
|
</el-input>
|
||||||
|
|
||||||
<el-autocomplete :disabled="isReadOnly" :maxlength="200" v-if="suggestions" v-model="item.name" size="small"
|
<el-autocomplete :disabled="isReadOnly" v-if="suggestions" v-model="item.name" size="small"
|
||||||
:fetch-suggestions="querySearch" @change="change" :placeholder="keyText" show-word-limit/>
|
:fetch-suggestions="querySearch" @change="change" :placeholder="keyText" show-word-limit/>
|
||||||
|
|
||||||
</el-col>
|
</el-col>
|
||||||
|
@ -44,6 +45,13 @@
|
||||||
<el-col v-if="item.type === 'file'">
|
<el-col v-if="item.type === 'file'">
|
||||||
<ms-api-body-file-upload :parameter="item"/>
|
<ms-api-body-file-upload :parameter="item"/>
|
||||||
</el-col>
|
</el-col>
|
||||||
|
|
||||||
|
<el-col v-if="type === 'body'">
|
||||||
|
<el-input :disabled="isReadOnly" v-model="item.contentType" size="small" maxlength="100"
|
||||||
|
@change="change" :placeholder="$t('api_test.request.content_type')" show-word-limit>
|
||||||
|
</el-input>
|
||||||
|
</el-col>
|
||||||
|
|
||||||
<el-col class="kv-delete">
|
<el-col class="kv-delete">
|
||||||
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
|
<el-button size="mini" class="el-icon-delete-solid" circle @click="remove(index)"
|
||||||
:disabled="isDisable(index) || isReadOnly"/>
|
:disabled="isDisable(index) || isReadOnly"/>
|
||||||
|
@ -85,7 +93,6 @@
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
currentItem: null,
|
currentItem: null,
|
||||||
checkedValues: []
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -98,9 +105,6 @@
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
remove: function (index) {
|
remove: function (index) {
|
||||||
// 移除勾选内容
|
|
||||||
let checkIndex = this.checkedValues.indexOf(this.parameters[index].uuid);
|
|
||||||
checkIndex != -1 ? this.checkedValues.splice(checkIndex, 1) : this.checkedValues;
|
|
||||||
// 移除整行输入控件及内容
|
// 移除整行输入控件及内容
|
||||||
this.parameters.splice(index, 1);
|
this.parameters.splice(index, 1);
|
||||||
this.$emit('change', this.parameters);
|
this.$emit('change', this.parameters);
|
||||||
|
@ -109,9 +113,6 @@
|
||||||
let isNeedCreate = true;
|
let isNeedCreate = true;
|
||||||
let removeIndex = -1;
|
let removeIndex = -1;
|
||||||
this.parameters.forEach((item, index) => {
|
this.parameters.forEach((item, index) => {
|
||||||
// 启用行赋值
|
|
||||||
item.enable = this.checkedValues.indexOf(item.uuid) != -1 ? true : false;
|
|
||||||
|
|
||||||
if (!item.name && !item.value) {
|
if (!item.name && !item.value) {
|
||||||
// 多余的空行
|
// 多余的空行
|
||||||
if (index !== this.parameters.length - 1) {
|
if (index !== this.parameters.length - 1) {
|
||||||
|
@ -122,11 +123,7 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (isNeedCreate) {
|
if (isNeedCreate) {
|
||||||
// 往后台送入的复选框值布尔值
|
this.parameters.push(new KeyValue({type: 'text', enable: true, uuid: this.uuid(), contentType: 'text/plain'}));
|
||||||
this.parameters[this.parameters.length - 1].enable = true;
|
|
||||||
// v-model 选中状态
|
|
||||||
this.checkedValues.push(this.parameters[this.parameters.length - 1].uuid);
|
|
||||||
this.parameters.push(new KeyValue(null, null, 'text', false, this.uuid()));
|
|
||||||
}
|
}
|
||||||
this.$emit('change', this.parameters);
|
this.$emit('change', this.parameters);
|
||||||
// TODO 检查key重复
|
// TODO 检查key重复
|
||||||
|
@ -161,22 +158,18 @@
|
||||||
advanced(item) {
|
advanced(item) {
|
||||||
this.$refs.variableAdvance.open();
|
this.$refs.variableAdvance.open();
|
||||||
this.currentItem = item;
|
this.currentItem = item;
|
||||||
this.itemValue = '';
|
|
||||||
this.mockVariableFuncs = [];
|
|
||||||
},
|
},
|
||||||
|
typeChange(item) {
|
||||||
|
if (item.type === 'file') {
|
||||||
|
item.contentType = 'application/octet-stream';
|
||||||
|
} else {
|
||||||
|
item.contentType = 'text/plain';
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
if (this.parameters.length === 0) {
|
if (this.parameters.length === 0) {
|
||||||
this.parameters.push(new KeyValue(null, null, 'text', false, this.uuid()));
|
this.parameters.push(new KeyValue( {type: 'text', enable: true, uuid: this.uuid(), contentType: 'text/plain'}));
|
||||||
} else {
|
|
||||||
this.parameters.forEach((item, index) => {
|
|
||||||
let uuid = this.uuid();
|
|
||||||
item.uuid = uuid;
|
|
||||||
if (item.enable) {
|
|
||||||
this.checkedValues.push(uuid);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ export default {
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
if (this.environment) {
|
if (this.environment) {
|
||||||
let variables = JSON.parse(this.environment.variables);
|
let variables = this.environment.config.commonConfig.variables;
|
||||||
this.environmentParams = [
|
this.environmentParams = [
|
||||||
{
|
{
|
||||||
name: this.environment.name,
|
name: this.environment.name,
|
||||||
|
|
|
@ -105,9 +105,9 @@
|
||||||
|
|
||||||
.api-body-upload {
|
.api-body-upload {
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
/*border: 1px solid #EBEEF5;*/
|
border: 1px solid #EBEEF5;
|
||||||
/*padding: 2px;*/
|
padding: 2px;
|
||||||
/*border-radius: 4px;*/
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upload-item {
|
.upload-item {
|
||||||
|
|
|
@ -156,7 +156,7 @@ export default {
|
||||||
let url = new URL(urlStr);
|
let url = new URL(urlStr);
|
||||||
url.searchParams.forEach((value, key) => {
|
url.searchParams.forEach((value, key) => {
|
||||||
if (key && value) {
|
if (key && value) {
|
||||||
this.request.parameters.splice(0, 0, new KeyValue(key, value));
|
this.request.parameters.splice(0, 0, new KeyValue({name: name, value: value}));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -344,6 +344,9 @@ export class HTTPSamplerArguments extends Element {
|
||||||
}
|
}
|
||||||
elementProp.stringProp('Argument.value', arg.value);
|
elementProp.stringProp('Argument.value', arg.value);
|
||||||
elementProp.stringProp('Argument.metadata', arg.metadata || "=");
|
elementProp.stringProp('Argument.metadata', arg.metadata || "=");
|
||||||
|
if (arg.contentType) {
|
||||||
|
elementProp.stringProp('HTTPArgument.content_type', arg.contentType, "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -363,7 +366,7 @@ export class HTTPsamplerFiles extends Element {
|
||||||
let elementProp = collectionProp.elementProp(arg.value, 'HTTPFileArg');
|
let elementProp = collectionProp.elementProp(arg.value, 'HTTPFileArg');
|
||||||
elementProp.stringProp('File.path', arg.value);
|
elementProp.stringProp('File.path', arg.value);
|
||||||
elementProp.stringProp('File.paramname', arg.name);
|
elementProp.stringProp('File.paramname', arg.name);
|
||||||
elementProp.stringProp('File.mimetype', arg.metadata || "application/octet-stream");
|
elementProp.stringProp('File.mimetype', arg.contentType || "application/octet-stream");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -656,35 +656,18 @@ export class Body extends BaseConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class KeyValue extends BaseConfig {
|
export class KeyValue extends BaseConfig {
|
||||||
constructor() {
|
constructor(options) {
|
||||||
let options, key, value, type, enable, uuid;
|
options = options || {};
|
||||||
if (arguments.length === 1) {
|
options.enable = options.enable != false ? true : false;
|
||||||
options = arguments[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arguments.length === 2) {
|
|
||||||
key = arguments[0];
|
|
||||||
value = arguments[1];
|
|
||||||
}
|
|
||||||
if (arguments.length === 3) {
|
|
||||||
key = arguments[0];
|
|
||||||
value = arguments[1];
|
|
||||||
type = arguments[2];
|
|
||||||
}
|
|
||||||
if (arguments.length === 5) {
|
|
||||||
key = arguments[0];
|
|
||||||
value = arguments[1];
|
|
||||||
type = arguments[2];
|
|
||||||
enable = arguments[3];
|
|
||||||
uuid = arguments[4];
|
|
||||||
}
|
|
||||||
super();
|
super();
|
||||||
this.name = key;
|
this.name = undefined;
|
||||||
this.value = value;
|
this.value = undefined;
|
||||||
this.type = type;
|
this.type = undefined;
|
||||||
this.files = undefined;
|
this.files = undefined;
|
||||||
this.enable = enable;
|
this.enable = undefined;
|
||||||
this.uuid = uuid;
|
this.uuid = undefined;
|
||||||
|
this.contentType = undefined;
|
||||||
this.set(options);
|
this.set(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -956,7 +939,7 @@ class JMXHttpRequest {
|
||||||
this.domain = environment.config.httpConfig.domain;
|
this.domain = environment.config.httpConfig.domain;
|
||||||
this.port = environment.config.httpConfig.port;
|
this.port = environment.config.httpConfig.port;
|
||||||
this.protocol = environment.config.httpConfig.protocol;
|
this.protocol = environment.config.httpConfig.protocol;
|
||||||
let url = new URL(environment.config.httpConfig.protocol + "://" + environment.config.commonConfig.socket);
|
let url = new URL(environment.config.httpConfig.protocol + "://" + environment.config.httpConfig.socket);
|
||||||
this.path = this.getPostQueryParameters(request, decodeURIComponent(url.pathname + (request.path ? request.path : '')));
|
this.path = this.getPostQueryParameters(request, decodeURIComponent(url.pathname + (request.path ? request.path : '')));
|
||||||
}
|
}
|
||||||
this.connectTimeout = request.connectTimeout;
|
this.connectTimeout = request.connectTimeout;
|
||||||
|
@ -1117,7 +1100,7 @@ class JMXGenerator {
|
||||||
}
|
}
|
||||||
envArray.forEach(item => {
|
envArray.forEach(item => {
|
||||||
if (item.name && !keys.has(item.name)) {
|
if (item.name && !keys.has(item.name)) {
|
||||||
target.push(new KeyValue(item.name, item.value));
|
target.push(new KeyValue({name: item.name, value: item.value}));
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1294,7 +1277,7 @@ class JMXGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
request.headers.push(new KeyValue('Content-Type', type));
|
request.headers.push(new KeyValue({name: 'Content-Type', value: type}));
|
||||||
}
|
}
|
||||||
|
|
||||||
addRequestArguments(httpSamplerProxy, request) {
|
addRequestArguments(httpSamplerProxy, request) {
|
||||||
|
@ -1323,7 +1306,7 @@ class JMXGenerator {
|
||||||
let files = [];
|
let files = [];
|
||||||
let kvs = this.filterKVFile(request.body.kvs);
|
let kvs = this.filterKVFile(request.body.kvs);
|
||||||
kvs.forEach(kv => {
|
kvs.forEach(kv => {
|
||||||
if (kv.files) {
|
if ((kv.enable != false) && kv.files) {
|
||||||
kv.files.forEach(file => {
|
kv.files.forEach(file => {
|
||||||
let arg = {};
|
let arg = {};
|
||||||
arg.name = kv.name;
|
arg.name = kv.name;
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit cc38137a69a0f20fadece9c0f9f50a9468c4ace9
|
Subproject commit 06d935cd1d22ab36f09763745c2aff8ad3fb08c1
|
|
@ -468,6 +468,7 @@ export default {
|
||||||
input_url: "Please enter the request URL",
|
input_url: "Please enter the request URL",
|
||||||
input_path: "Please enter the request path",
|
input_path: "Please enter the request path",
|
||||||
name: "Name",
|
name: "Name",
|
||||||
|
content_type: "Content Type",
|
||||||
method: "Method",
|
method: "Method",
|
||||||
url: "URL",
|
url: "URL",
|
||||||
path: "Path",
|
path: "Path",
|
||||||
|
|
|
@ -468,6 +468,7 @@ export default {
|
||||||
input_url: "请输入请求URL",
|
input_url: "请输入请求URL",
|
||||||
input_path: "请输入请求路径",
|
input_path: "请输入请求路径",
|
||||||
name: "请求名称",
|
name: "请求名称",
|
||||||
|
content_type: "请求类型",
|
||||||
method: "请求方法",
|
method: "请求方法",
|
||||||
url: "请求URL",
|
url: "请求URL",
|
||||||
path: "请求路径",
|
path: "请求路径",
|
||||||
|
|
|
@ -470,6 +470,7 @@ export default {
|
||||||
name: "請求名稱",
|
name: "請求名稱",
|
||||||
method: "請求方法",
|
method: "請求方法",
|
||||||
url: "請求URL",
|
url: "請求URL",
|
||||||
|
content_type: "請求類型",
|
||||||
path: "請求路徑",
|
path: "請求路徑",
|
||||||
address: "請求地址",
|
address: "請求地址",
|
||||||
refer_to_environment: "引用環境",
|
refer_to_environment: "引用環境",
|
||||||
|
|
Loading…
Reference in New Issue