多文件上传修改

This commit is contained in:
Captain.B 2020-03-19 18:53:41 +08:00
parent f0dcf4e364
commit 86113caae1
10 changed files with 175 additions and 109 deletions

View File

@ -1,5 +1,5 @@
package io.metersphere.commons.constants; package io.metersphere.commons.constants;
public enum FileType { public enum FileType {
JMX JMX, CSV
} }

View File

@ -50,17 +50,17 @@ public class LoadTestController {
@PostMapping(value = "/save", consumes = {"multipart/form-data"}) @PostMapping(value = "/save", consumes = {"multipart/form-data"})
public String save( public String save(
@RequestPart("request") SaveTestPlanRequest request, @RequestPart("request") SaveTestPlanRequest request,
@RequestPart(value = "file") MultipartFile file @RequestPart(value = "file") List<MultipartFile> files
) { ) {
return loadTestService.save(request, file); return loadTestService.save(request, files);
} }
@PostMapping(value = "/edit", consumes = {"multipart/form-data"}) @PostMapping(value = "/edit", consumes = {"multipart/form-data"})
public String edit( public String edit(
@RequestPart("request") EditTestPlanRequest request, @RequestPart("request") EditTestPlanRequest request,
@RequestPart(value = "file", required = false) MultipartFile file @RequestPart(value = "file", required = false) List<MultipartFile> files
) { ) {
return loadTestService.edit(request, file); return loadTestService.edit(request, files);
} }
@GetMapping("/get/{testId}") @GetMapping("/get/{testId}")
@ -89,7 +89,7 @@ public class LoadTestController {
} }
@GetMapping("/file/metadata/{testId}") @GetMapping("/file/metadata/{testId}")
public FileMetadata getFileMetadata(@PathVariable String testId) { public List<FileMetadata> getFileMetadata(@PathVariable String testId) {
return fileService.getFileMetadataByTestId(testId); return fileService.getFileMetadataByTestId(testId);
} }

View File

@ -1,4 +1,17 @@
package io.metersphere.controller.request.testplan; package io.metersphere.controller.request.testplan;
import io.metersphere.base.domain.FileMetadata;
import java.util.List;
public class EditTestPlanRequest extends TestPlanRequest { public class EditTestPlanRequest extends TestPlanRequest {
private List<FileMetadata> updatedFileList;
public List<FileMetadata> getUpdatedFileList() {
return updatedFileList;
}
public void setUpdatedFileList(List<FileMetadata> updatedFileList) {
this.updatedFileList = updatedFileList;
}
} }

View File

@ -29,7 +29,7 @@ public class FileService {
return fileContent.getFile(); return fileContent.getFile();
} }
public FileMetadata getFileMetadataByTestId(String testId) { public List<FileMetadata> getFileMetadataByTestId(String testId) {
LoadTestFileExample loadTestFileExample = new LoadTestFileExample(); LoadTestFileExample loadTestFileExample = new LoadTestFileExample();
loadTestFileExample.createCriteria().andTestIdEqualTo(testId); loadTestFileExample.createCriteria().andTestIdEqualTo(testId);
final List<LoadTestFile> loadTestFiles = loadTestFileMapper.selectByExample(loadTestFileExample); final List<LoadTestFile> loadTestFiles = loadTestFileMapper.selectByExample(loadTestFileExample);
@ -37,8 +37,10 @@ public class FileService {
if (CollectionUtils.isEmpty(loadTestFiles)) { if (CollectionUtils.isEmpty(loadTestFiles)) {
return null; return null;
} }
List<String> fileIds = loadTestFiles.stream().map(LoadTestFile::getFileId).collect(Collectors.toList());
return fileMetadataMapper.selectByPrimaryKey(loadTestFiles.get(0).getFileId()); FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andIdIn(fileIds);
return fileMetadataMapper.selectByExample(example);
} }
public FileMetadata getFucFileMetadataByTestId(String testId) { public FileMetadata getFucFileMetadataByTestId(String testId) {
@ -74,4 +76,17 @@ public class FileService {
fileContentMapper.deleteByExample(fileContentExample); fileContentMapper.deleteByExample(fileContentExample);
} }
} }
public void deleteFileByIds(List<String> ids) {
if (CollectionUtils.isEmpty(ids)) {
return;
}
FileMetadataExample example = new FileMetadataExample();
example.createCriteria().andIdIn(ids);
fileMetadataMapper.deleteByExample(example);
FileContentExample example2 = new FileContentExample();
example2.createCriteria().andFileIdIn(ids);
fileContentMapper.deleteByExample(example2);
}
} }

View File

@ -138,39 +138,39 @@ public class FuctionalTestService {
public void run(RunTestPlanRequest request) { public void run(RunTestPlanRequest request) {
final FucTestWithBLOBs fucTest = fucTestMapper.selectByPrimaryKey(request.getId()); final FucTestWithBLOBs fucTest = fucTestMapper.selectByPrimaryKey(request.getId());
if (fucTest == null) { // if (fucTest == null) {
MSException.throwException("无法运行测试,未找到测试:" + request.getId()); // MSException.throwException("无法运行测试,未找到测试:" + request.getId());
} // }
//
final FileMetadata fileMetadata = fileService.getFileMetadataByTestId(request.getId()); // final List<FileMetadata> fileMetadataList = fileService.getFileMetadataByTestId(request.getId());
if (fileMetadata == null) { // if (fileMetadataList == null) {
MSException.throwException("无法运行测试无法获取测试文件元信息测试ID" + request.getId()); // MSException.throwException("无法运行测试无法获取测试文件元信息测试ID" + request.getId());
} // }
//
final FileContent fileContent = fileService.getFileContent(fileMetadata.getId()); // final FileContent fileContent = fileService.getFileContent(fileMetadata.getId());
if (fileContent == null) { // if (fileContent == null) {
MSException.throwException("无法运行测试无法获取测试文件内容测试ID" + request.getId()); // MSException.throwException("无法运行测试无法获取测试文件内容测试ID" + request.getId());
} // }
//
System.out.println("开始运行:" + fucTest.getName()); // System.out.println("开始运行:" + fucTest.getName());
final Engine engine = EngineFactory.createEngine(fileMetadata.getType()); // final Engine engine = EngineFactory.createEngine(fileMetadata.getType());
if (engine == null) { // if (engine == null) {
MSException.throwException(String.format("无法运行测试未识别测试文件类型测试ID%s文件类型%s", // MSException.throwException(String.format("无法运行测试未识别测试文件类型测试ID%s文件类型%s",
request.getId(), // request.getId(),
fileMetadata.getType())); // fileMetadata.getType()));
} // }
//
boolean init = true; // boolean init = true;
try { // try {
// init = engine.init(EngineFactory.createContext(fucTest, fileMetadata, fileContent)); //// init = engine.init(EngineFactory.createContext(fucTest, fileMetadata, fileContent));
} catch (Exception e) { // } catch (Exception e) {
MSException.throwException(e); // MSException.throwException(e);
} // }
if (!init) { // if (!init) {
MSException.throwException(String.format("无法运行测试初始化运行环境失败测试ID%s", request.getId())); // MSException.throwException(String.format("无法运行测试初始化运行环境失败测试ID%s", request.getId()));
} // }
//
// engine.start(); //// engine.start();
/// todo通过调用stop方法能够停止正在运行的engine但是如果部署了多个backend实例页面发送的停止请求如何定位到具体的engine /// todo通过调用stop方法能够停止正在运行的engine但是如果部署了多个backend实例页面发送的停止请求如何定位到具体的engine
} }

View File

@ -7,6 +7,7 @@ import io.metersphere.base.mapper.LoadTestFileMapper;
import io.metersphere.base.mapper.LoadTestMapper; import io.metersphere.base.mapper.LoadTestMapper;
import io.metersphere.base.mapper.ext.ExtLoadTestMapper; import io.metersphere.base.mapper.ext.ExtLoadTestMapper;
import io.metersphere.commons.constants.EngineType; import io.metersphere.commons.constants.EngineType;
import io.metersphere.commons.constants.FileType;
import io.metersphere.commons.constants.TestStatus; import io.metersphere.commons.constants.TestStatus;
import io.metersphere.commons.exception.MSException; import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.LogUtil; import io.metersphere.commons.utils.LogUtil;
@ -15,6 +16,8 @@ import io.metersphere.dto.LoadTestDTO;
import io.metersphere.engine.Engine; import io.metersphere.engine.Engine;
import io.metersphere.engine.EngineFactory; import io.metersphere.engine.EngineFactory;
import io.metersphere.i18n.Translator; import io.metersphere.i18n.Translator;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
@ -25,6 +28,7 @@ import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Collectors;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -52,20 +56,18 @@ public class LoadTestService {
fileService.deleteFileByTestId(request.getId()); fileService.deleteFileByTestId(request.getId());
} }
public String save(SaveTestPlanRequest request, MultipartFile file) { public String save(SaveTestPlanRequest request, List<MultipartFile> files) {
if (file == null) { if (files == null) {
throw new IllegalArgumentException(Translator.get("file_cannot_be_null")); throw new IllegalArgumentException(Translator.get("file_cannot_be_null"));
} }
final FileMetadata fileMetadata = saveFile(file);
final LoadTestWithBLOBs loadTest = saveLoadTest(request); final LoadTestWithBLOBs loadTest = saveLoadTest(request);
files.forEach(file -> {
LoadTestFile loadTestFile = new LoadTestFile(); final FileMetadata fileMetadata = saveFile(file);
loadTestFile.setTestId(loadTest.getId()); LoadTestFile loadTestFile = new LoadTestFile();
loadTestFile.setFileId(fileMetadata.getId()); loadTestFile.setTestId(loadTest.getId());
loadTestFileMapper.insert(loadTestFile); loadTestFile.setFileId(fileMetadata.getId());
loadTestFileMapper.insert(loadTestFile);
});
return loadTest.getId(); return loadTest.getId();
} }
@ -98,7 +100,8 @@ public class LoadTestService {
fileMetadata.setSize(file.getSize()); fileMetadata.setSize(file.getSize());
fileMetadata.setCreateTime(System.currentTimeMillis()); fileMetadata.setCreateTime(System.currentTimeMillis());
fileMetadata.setUpdateTime(System.currentTimeMillis()); fileMetadata.setUpdateTime(System.currentTimeMillis());
fileMetadata.setType("JMX"); FileType fileType = getFileType(fileMetadata.getName());
fileMetadata.setType(fileType.name());
// TODO engine 选择 // TODO engine 选择
fileMetadata.setEngine(EngineType.DOCKER.name()); fileMetadata.setEngine(EngineType.DOCKER.name());
fileMetadataMapper.insert(fileMetadata); fileMetadataMapper.insert(fileMetadata);
@ -115,15 +118,30 @@ public class LoadTestService {
return fileMetadata; return fileMetadata;
} }
public String edit(EditTestPlanRequest request, MultipartFile file) { private FileType getFileType(String filename) {
int s = filename.lastIndexOf(".") + 1;
String type = filename.substring(s);
return FileType.valueOf(type.toUpperCase());
}
public String edit(EditTestPlanRequest request, List<MultipartFile> files) {
// 新选择了一个文件删除原来的文件 // 新选择了一个文件删除原来的文件
if (file != null) { if (files != null) {
fileService.deleteFileByTestId(request.getId()); List<FileMetadata> updatedFiles = request.getUpdatedFileList();
final FileMetadata fileMetadata = saveFile(file); List<FileMetadata> originFiles = fileService.getFileMetadataByTestId(request.getId());
LoadTestFile loadTestFile = new LoadTestFile(); List<String> updatedFileIds = updatedFiles.stream().map(FileMetadata::getId).collect(Collectors.toList());
loadTestFile.setTestId(request.getId()); List<String> originFileIds = originFiles.stream().map(FileMetadata::getId).collect(Collectors.toList());
loadTestFile.setFileId(fileMetadata.getId()); // 相减
loadTestFileMapper.insert(loadTestFile); List<String> deleteFileIds = ListUtils.subtract(originFileIds, updatedFileIds);
fileService.deleteFileByIds(deleteFileIds);
files.forEach(file -> {
final FileMetadata fileMetadata = saveFile(file);
LoadTestFile loadTestFile = new LoadTestFile();
loadTestFile.setTestId(request.getId());
loadTestFile.setFileId(fileMetadata.getId());
loadTestFileMapper.insert(loadTestFile);
});
} }
final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId()); final LoadTestWithBLOBs loadTest = loadTestMapper.selectByPrimaryKey(request.getId());
@ -149,10 +167,14 @@ public class LoadTestService {
MSException.throwException(Translator.get("run_load_test_not_found") + request.getId()); MSException.throwException(Translator.get("run_load_test_not_found") + request.getId());
} }
final FileMetadata fileMetadata = fileService.getFileMetadataByTestId(request.getId()); final List<FileMetadata> fileMetadataList = fileService.getFileMetadataByTestId(request.getId());
if (fileMetadata == null) { if (CollectionUtils.isEmpty(fileMetadataList)) {
MSException.throwException(Translator.get("run_load_test_file_not_found") + request.getId()); MSException.throwException(Translator.get("run_load_test_file_not_found") + request.getId());
} }
FileMetadata fileMetadata = fileMetadataList.stream().filter(f -> StringUtils.equalsIgnoreCase(f.getType(), "JMX"))
.findFirst().orElseGet(() -> {
throw new RuntimeException(Translator.get("run_load_test_file_not_found") + request.getId());
});
final FileContent fileContent = fileService.getFileContent(fileMetadata.getId()); final FileContent fileContent = fileService.getFileContent(fileMetadata.getId());
if (fileContent == null) { if (fileContent == null) {

View File

@ -85,7 +85,7 @@
let testId = to.path.split('/')[4]; // find testId let testId = to.path.split('/')[4]; // find testId
if (testId) { if (testId) {
this.$get('/testplan/get/' + testId, response => { this.$get('/testplan/get/' + testId, response => {
if(response.data){ if (response.data) {
this.testPlan = response.data; this.testPlan = response.data;
} }
}); });
@ -151,9 +151,13 @@
let formData = new FormData(); let formData = new FormData();
let url = this.testPlan.id ? this.editPath : this.savePath; let url = this.testPlan.id ? this.editPath : this.savePath;
if (!this.testPlan.file.id) { if (this.$refs.basicConfig.uploadList.length > 0) {
formData.append("file", this.testPlan.file); this.$refs.basicConfig.uploadList.forEach(f => {
formData.append("file", f);
});
} }
//
this.testPlan.updatedFileList = this.$refs.basicConfig.updatedFileList();
// //
this.testPlan.loadConfiguration = JSON.stringify(this.$refs.pressureConfig.convertProperty()); this.testPlan.loadConfiguration = JSON.stringify(this.$refs.pressureConfig.convertProperty());
// //
@ -199,12 +203,7 @@
return false; return false;
} }
if (!this.testPlan.file) { if (!this.$refs.basicConfig.validConfig()) {
this.$message({
message: this.$t('load_test.jmx_is_null'),
type: 'error'
});
return false; return false;
} }

View File

@ -1,10 +1,11 @@
<template> <template>
<div v-loading="result.loading"> <div v-loading="result.loading">
<el-upload <el-upload
accept=".jmx" accept=".jmx,.csv"
drag drag
action="" action=""
:limit="1" :limit="5"
multiple
:show-file-list="false" :show-file-list="false"
:before-upload="beforeUpload" :before-upload="beforeUpload"
:http-request="handleUpload" :http-request="handleUpload"
@ -32,13 +33,9 @@
:label="$t('load_test.last_modify_time')"> :label="$t('load_test.last_modify_time')">
<template slot-scope="scope"> <template slot-scope="scope">
<i class="el-icon-time"/> <i class="el-icon-time"/>
<span class="last-modified">{{ scope.row.lastModified | timestampFormatDate }}</span> <span class="last-modified">{{ scope.row.updateTime | timestampFormatDate }}</span>
</template> </template>
</el-table-column> </el-table-column>
<el-table-column
prop="status"
:label="$t('load_test.file_status')">
</el-table-column>
<el-table-column <el-table-column
:label="$t('commons.operating')"> :label="$t('commons.operating')">
<template slot-scope="scope"> <template slot-scope="scope">
@ -66,6 +63,7 @@
jmxDeletePath: '/testplan/file/delete', jmxDeletePath: '/testplan/file/delete',
fileList: [], fileList: [],
tableData: [], tableData: [],
uploadList: [],
}; };
}, },
created() { created() {
@ -82,29 +80,20 @@
}, },
methods: { methods: {
getFileMetadata(testPlan) { getFileMetadata(testPlan) {
this.fileList = [];// this.fileList = [];
this.tableData = [];// this.tableData = [];
this.result = this.$get(this.getFileMetadataPath + "/" + testPlan.id, response => { this.result = this.$get(this.getFileMetadataPath + "/" + testPlan.id, response => {
let file = response.data; let files = response.data;
if (!file) { if (!files) {
Message.error({message: this.$t('load_test.related_file_not_found'), showClose: true}); Message.error({message: this.$t('load_test.related_file_not_found'), showClose: true});
return; return;
} }
// deep copy
this.testPlan.file = file; this.fileList = JSON.parse(JSON.stringify(files));
this.fileList.push({ this.tableData = JSON.parse(JSON.stringify(files));
id: file.id, this.tableData.map(f => {
name: file.name f.size = f.size + ' Bytes';
});
this.tableData.push({
id: file.id,
name: file.name,
size: file.size + 'Byte', /// todo: ByteKBMB
type: 'JMX',
lastModified: file.updateTime,
status: 'todo',
}); });
}) })
}, },
@ -114,18 +103,24 @@
return false; return false;
} }
if (this.tableData.filter(f => f.name === file.name).length > 0) {
this.$message.error(this.$t('load_test.delete_file'));
return false;
}
let type = file.name.substring(file.name.lastIndexOf(".") + 1);
this.tableData.push({ this.tableData.push({
name: file.name, name: file.name,
size: file.size + 'Byte', /// todo: ByteKBMB size: file.size + ' Bytes', /// todo: ByteKBMB
type: 'JMX', type: type.toUpperCase(),
lastModified: file.lastModified, updateTime: file.lastModified,
status: 'todo',
}); });
return true; return true;
}, },
handleUpload(uploadResources) { handleUpload(uploadResources) {
this.testPlan.file = uploadResources.file; this.uploadList.push(uploadResources.file);
}, },
handleDownload(file) { handleDownload(file) {
let data = { let data = {
@ -158,7 +153,7 @@
}); });
}, },
handleDelete(file, index) { handleDelete(file, index) {
this.$alert(this.$t('commons.delete_file_confirm') + file.name + "", '', { this.$alert(this.$t('load_test.delete_file_confirm') + file.name + "", '', {
confirmButtonText: this.$t('commons.confirm'), confirmButtonText: this.$t('commons.confirm'),
callback: (action) => { callback: (action) => {
if (action === 'confirm') { if (action === 'confirm') {
@ -170,7 +165,9 @@
_handleDelete(file, index) { _handleDelete(file, index) {
this.fileList.splice(index, 1); this.fileList.splice(index, 1);
this.tableData.splice(index, 1); this.tableData.splice(index, 1);
this.testPlan.file = null; //
let i = this.uploadList.indexOf(file);
this.uploadList.splice(i, 1);
}, },
handleExceed() { handleExceed() {
this.$message.error(this.$t('load_test.delete_file')); this.$message.error(this.$t('load_test.delete_file'));
@ -179,6 +176,26 @@
/// todo: /// todo:
return file.size > 0; return file.size > 0;
}, },
updatedFileList() {
return this.fileList;//
},
validConfig() {
let newJmxNum = 0, oldJmxNum = 0;
if (this.uploadList.length > 0) {
newJmxNum = this.uploadList.filter(f => f.name.endsWith(".jmx")).length;
}
if (this.fileList.length > 0) {
oldJmxNum = this.fileList.filter(f => f.name.endsWith(".jmx")).length;
}
if (newJmxNum + oldJmxNum !== 1) {
this.$message({
message: this.$t('load_test.jmx_is_null'),
type: 'error'
});
return false;
}
return true;
}
}, },
} }
</script> </script>

View File

@ -122,14 +122,14 @@ export default {
'is_running': 'Test is running! ', 'is_running': 'Test is running! ',
'test_name_is_null': 'Test name cannot be empty! ', 'test_name_is_null': 'Test name cannot be empty! ',
'project_is_null': 'Project cannot be empty! ', 'project_is_null': 'Project cannot be empty! ',
'jmx_is_null': 'JMX file cannot be empty! ', 'jmx_is_null': 'Can only contain one JMX file',
'file_name': 'File name', 'file_name': 'File name',
'file_size': 'File size', 'file_size': 'File size',
'file_type': 'File Type', 'file_type': 'File Type',
'file_status': 'File Status', 'file_status': 'File Status',
'last_modify_time': 'Modify time', 'last_modify_time': 'Modify time',
'upload_tips': 'Drag files here, or <em> click to upload </em>', 'upload_tips': 'Drag files here, or <em> click to upload </em>',
'upload_type': 'Only JMX files can be uploaded', 'upload_type': 'Only JMX/CSV files can be uploaded',
'related_file_not_found': "No related test file found!", 'related_file_not_found': "No related test file found!",
'delete_file_confirm': 'Confirm delete file:', 'delete_file_confirm': 'Confirm delete file:',
'delete_file': "Please delete an existing file first!", 'delete_file': "Please delete an existing file first!",

View File

@ -122,14 +122,14 @@ export default {
'is_running': '正在运行!', 'is_running': '正在运行!',
'test_name_is_null': '测试名称不能为空!', 'test_name_is_null': '测试名称不能为空!',
'project_is_null': '项目不能为空!', 'project_is_null': '项目不能为空!',
'jmx_is_null': 'JMX文件不能为空', 'jmx_is_null': '只能包含一个JMX文件',
'file_name': '文件名', 'file_name': '文件名',
'file_size': '文件大小', 'file_size': '文件大小',
'file_type': '文件类型', 'file_type': '文件类型',
'file_status': '文件状态', 'file_status': '文件状态',
'last_modify_time': '修改时间', 'last_modify_time': '修改时间',
'upload_tips': '将文件拖到此处,或<em>点击上传</em>', 'upload_tips': '将文件拖到此处,或<em>点击上传</em>',
'upload_type': '只能上传JMX文件', 'upload_type': '只能上传JMX/CSV文件',
'related_file_not_found': "未找到关联的测试文件!", 'related_file_not_found': "未找到关联的测试文件!",
'delete_file_confirm': '确认删除文件: ', 'delete_file_confirm': '确认删除文件: ',
'delete_file': "请先删除已存在的文件!", 'delete_file': "请先删除已存在的文件!",