提交 b9b5c6eb 编写于 作者: Q q4speed

Merge remote-tracking branch 'origin/dev' into dev

......@@ -3,8 +3,12 @@ package io.metersphere.config;
import io.metersphere.commons.utils.CommonBeanFactory;
import io.metersphere.i18n.Translator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import javax.validation.Validator;
@Configuration
public class I18nConfig {
......@@ -20,4 +24,16 @@ public class I18nConfig {
public CommonBeanFactory commonBeanFactory() {
return new CommonBeanFactory();
}
/**
* JSR-303校验国际化
* @param messageSource
* @return
*/
@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean(MessageSource messageSource) {
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setValidationMessageSource(messageSource);
return localValidatorFactoryBean;
}
}
......@@ -2,12 +2,13 @@ package io.metersphere.excel.domain;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import lombok.Data;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
@Data
@ColumnWidth(15)
public class TestCaseExcelData {
......@@ -20,12 +21,12 @@ public class TestCaseExcelData {
@Length(max=1000)
@ExcelProperty("所属模块")
@ColumnWidth(30)
@Pattern(regexp = "^(?!.*//).*$", message = "格式不正确")
@Pattern(regexp = "^(?!.*//).*$", message = "{incorrect_format}")
private String nodePath;
@NotBlank
@ExcelProperty("用例类型")
@Pattern(regexp = "(^functional$)|(^performance$)|(^api$)", message = "必须为functional、performance、api")
@Pattern(regexp = "(^functional$)|(^performance$)|(^api$)", message = "{test_case_type_validate}")
private String type;
@NotBlank
......@@ -34,12 +35,12 @@ public class TestCaseExcelData {
@NotBlank
@ExcelProperty("优先级")
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "必须为P0、P1、P2、P3")
@Pattern(regexp = "(^P0$)|(^P1$)|(^P2$)|(^P3$)", message = "{test_case_priority_validate}")
private String priority;
@NotBlank
@ExcelProperty("测试方式")
@Pattern(regexp = "(^manual$)|(^auto$)", message = "必须为manual、auto")
@Pattern(regexp = "(^manual$)|(^auto$)", message = "{test_case_method_validate}")
private String method;
@ColumnWidth(50)
......@@ -61,85 +62,4 @@ public class TestCaseExcelData {
@ExcelProperty("预期结果")
@Length(max=1000)
private String stepResult;
public String getNodePath() {
return nodePath;
}
public void setNodePath(String nodePath) {
this.nodePath = nodePath;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMaintainer() {
return maintainer;
}
public void setMaintainer(String maintainer) {
this.maintainer = maintainer;
}
public String getPriority() {
return priority;
}
public void setPriority(String priority) {
this.priority = priority;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getPrerequisite() {
return prerequisite;
}
public void setPrerequisite(String prerequisite) {
this.prerequisite = prerequisite;
}
public String getRemark() {
return remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getStepDesc() {
return stepDesc;
}
public void setStepDesc(String stepDesc) {
this.stepDesc = stepDesc;
}
public String getStepResult() {
return stepResult;
}
public void setStepResult(String stepResult) {
this.stepResult = stepResult;
}
}
......@@ -8,11 +8,16 @@ import com.alibaba.excel.util.StringUtils;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.excel.utils.ExcelValidateHelper;
import io.metersphere.excel.domain.ExcelErrData;
import io.metersphere.i18n.Translator;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
@Component
public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
protected List<ExcelErrData<T>> errList = new ArrayList<>();
......@@ -26,9 +31,12 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
protected Class<T> clazz;
@Resource
ExcelValidateHelper excelValidateHelper;
public EasyExcelListener(Class<T> clazz){
this.clazz = clazz;
public EasyExcelListener(){
Type type = getClass().getGenericSuperclass();
this.clazz = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
}
/**
......@@ -43,16 +51,18 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
Integer rowIndex = analysisContext.readRowHolder().getRowIndex();
try {
//根据excel数据实体中的javax.validation + 正则表达式来校验excel数据
errMsg = ExcelValidateHelper.validateEntity(t);
errMsg = excelValidateHelper.validateEntity(t);
//自定义校验规则
errMsg = validate(t, errMsg);
} catch (NoSuchFieldException e) {
errMsg = "解析数据出错";
errMsg = Translator.get("parse_data_error");
LogUtil.error(e.getMessage(), e);
}
if (!StringUtils.isEmpty(errMsg)) {
ExcelErrData excelErrData = new ExcelErrData(t, rowIndex, "第" + rowIndex + "行出错:" + errMsg);
ExcelErrData excelErrData = new ExcelErrData(t, rowIndex,
Translator.get("number") + rowIndex + Translator.get("row") + Translator.get("error")
+ ":" + errMsg);
errList.add(excelErrData);
} else {
list.add(t);
......@@ -101,7 +111,7 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
Collection<String> values = headMap.values();
for (String key : fieldNameSet) {
if (!values.contains(key)){
throw new ExcelAnalysisException("缺少头部信息:" + key);
throw new ExcelAnalysisException(Translator.get("missing_header_information") + ":" + key);
}
}
} catch (NoSuchFieldException e) {
......@@ -133,8 +143,10 @@ public abstract class EasyExcelListener <T> extends AnalysisEventListener<T> {
}
public List<ExcelErrData<T>> getErrList() {
return errList;
public List<ExcelErrData<T>> getAndClearErrList() {
List<ExcelErrData<T>> tmp = this.errList;
this.errList = new ArrayList<>();
return tmp;
}
}
\ No newline at end of file
......@@ -6,18 +6,22 @@ import io.metersphere.excel.domain.TestCaseExcelData;
import io.metersphere.base.domain.TestCaseWithBLOBs;
import io.metersphere.commons.constants.TestCaseConstants;
import io.metersphere.commons.utils.BeanUtils;
import io.metersphere.i18n.Translator;
import io.metersphere.track.service.TestCaseService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
@Component
public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
@Resource
private TestCaseService testCaseService;
private String projectId;
......@@ -26,13 +30,13 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
Set<String> userIds;
public TestCaseDataListener(TestCaseService testCaseService, String projectId,
Set<String> testCaseNames, Set<String> userIds, Class<TestCaseExcelData> clazz) {
super(clazz);
this.testCaseService = testCaseService;
public TestCaseDataListener() {}
public TestCaseDataListener init(String projectId, Set<String> testCaseNames, Set<String> userIds) {
this.projectId = projectId;
this.testCaseNames = testCaseNames;
this.userIds = userIds;
return this;
}
@Override
......@@ -43,21 +47,22 @@ public class TestCaseDataListener extends EasyExcelListener<TestCaseExcelData> {
if (nodePath != null) {
String[] nodes = nodePath.split("/");
if ( nodes.length > TestCaseConstants.MAX_NODE_DEPTH + 1) {
stringBuilder.append("节点最多为" + TestCaseConstants.MAX_NODE_DEPTH + "层;");
stringBuilder.append(Translator.get("test_case_node_level_tip") +
TestCaseConstants.MAX_NODE_DEPTH + Translator.get("test_case_node_level"));
}
for (int i = 0; i < nodes.length; i++) {
if (i != 0 && StringUtils.equals(nodes[i].trim(), "")) {
stringBuilder.append("所属模块不能为空格");
stringBuilder.append(Translator.get("module_not_null"));
break;
}
}
}
if (!userIds.contains(data.getMaintainer())) {
stringBuilder.append("该工作空间下无该用户:" + data.getMaintainer() + ";");
stringBuilder.append(Translator.get("user_not_exists") + ":" + data.getMaintainer() + "; ");
}
if (testCaseNames.contains(data.getName())) {
stringBuilder.append("该项目下已存在该测试用例:" + data.getName() + ";");
stringBuilder.append(Translator.get("test_case_already_exists") + ":" + data.getName() + "; ");
}
return stringBuilder.toString();
}
......
package io.metersphere.excel.utils;
import com.alibaba.excel.annotation.ExcelProperty;
import org.springframework.stereotype.Component;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.groups.Default;
import java.lang.reflect.Field;
import java.util.Set;
@Component
public class ExcelValidateHelper {
private ExcelValidateHelper(){}
private static Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
@Resource
LocalValidatorFactoryBean localValidatorFactoryBean;
public static <T> String validateEntity(T obj) throws NoSuchFieldException {
public <T> String validateEntity(T obj) throws NoSuchFieldException {
StringBuilder result = new StringBuilder();
Set<ConstraintViolation<T>> set = validator.validate(obj, Default.class);
Set<ConstraintViolation<T>> set = localValidatorFactoryBean.getValidator().validate(obj, Default.class);
if (set != null && !set.isEmpty()) {
for (ConstraintViolation<T> cv : set) {
Field declaredField = obj.getClass().getDeclaredField(cv.getPropertyPath().toString());
ExcelProperty annotation = declaredField.getAnnotation(ExcelProperty.class);
//拼接错误信息,包含当前出错数据的标题名字+错误信息
result.append(annotation.value()[0]+cv.getMessage()).append(";");
result.append(annotation.value()[0]+cv.getMessage()).append("; ");
}
}
return result.toString();
......
......@@ -260,7 +260,7 @@ public class TestCaseNodeService {
String rootNodeName = null;
if (nodeNameList.size() <= 1) {
throw new ExcelException(Translator.get("test_case_module_not_null") + ":" + path);
throw new ExcelException(Translator.get("test_case_create_module_fail") + ":" + path);
} else {
pathIterator.next();
pathIterator.remove();
......
......@@ -60,6 +60,9 @@ public class TestCaseService {
@Resource
TestCaseNodeService testCaseNodeService;
@Resource
TestCaseDataListener testCaseDataListener;
@Resource
UserMapper userMapper;
......@@ -187,11 +190,10 @@ public class TestCaseService {
List<User> users = userMapper.selectByExample(userExample);
Set<String> userIds = users.stream().map(User::getId).collect(Collectors.toSet());
EasyExcelListener easyExcelListener = new TestCaseDataListener(this, projectId,
testCaseNames, userIds, TestCaseExcelData.class);
EasyExcelFactory.read(file.getInputStream(), TestCaseExcelData.class, easyExcelListener).sheet().doRead();
EasyExcelFactory.read(file.getInputStream(), TestCaseExcelData.class,
testCaseDataListener.init(projectId, testCaseNames, userIds)).sheet().doRead();
List<ExcelErrData<TestCaseExcelData>> errList = easyExcelListener.getErrList();
List<ExcelErrData<TestCaseExcelData>> errList = testCaseDataListener.getAndClearErrList();
//如果包含错误信息就导出错误信息
if (!errList.isEmpty()) {
excelResponse.setSuccess(false);
......
......@@ -3,6 +3,18 @@ before_delete_plan=
test_case_node_level_tip=
test_case_node_level=
test_case_module_not_null=
test_case_create_moule_fail=
test_case_create_module_fail=
test_case_import_template_name=
test_case_import_template_sheet=
module_not_null=
user_not_exists=
test_case_already_exists=
parse_data_error=
missing_header_information=
number=
row=
error=
incorrect_format=
test_case_type_validate=
test_case_priority_validate=
test_case_method_validate=
\ No newline at end of file
......@@ -37,6 +37,18 @@ password_modification_failed=Password modification failed
cannot_delete_current_user=Cannot delete the user currently logged in
test_case_node_level=level
test_case_module_not_null=The owned module cannot be empty
test_case_create_moule_fail=Failed to create module
test_case_create_module_fail=Failed to create module
test_case_import_template_name=Test case templates
test_case_import_template_sheet=Template
module_not_null=The module must not be blank
user_not_exists=The user in this workspace is not exists
test_case_already_exists=The test case in this project is exists
parse_data_error=Parse data error
missing_header_information=Missing header information
number=Number
row=row
error=error
incorrect_format=Incorrect format
test_case_type_validate=must be functional, performance, api
test_case_priority_validate=must be P0, P1, P2, P3
test_case_method_validate=\ must be manual, auto
\ No newline at end of file
......@@ -38,7 +38,19 @@ cannot_delete_current_user=无法删除当前登录用户
test_case_node_level=
test_case_node_level_tip=模块树最大深度为
test_case_module_not_null=所属模块不能为空
test_case_create_moule_fail=创建模块失败
test_case_create_module_fail=创建模块失败
test_case_import_template_name=测试用例模版
test_case_import_template_sheet=模版
module_not_null=所属模块不能为空格
user_not_exists=该工作空间下无该用户
test_case_already_exists=该项目下已存在该测试用例
parse_data_error=解析数据出错
missing_header_information=缺少头部信息
number=
row=
incorrect_format=格式不正确
test_case_type_validate=必须为functional、performance、api
test_case_priority_validate=必须为P0、P1、P2、P3
test_case_method_validate=必须为manual、auto
error=出错
#test case end
\ No newline at end of file
test_case_exist=該項目下已存在用例:
error_lang_invalid=語言參數錯誤
load_test_already_exists=測試名稱不能重
load_test_already_exists=測試名稱不能重
project_name_is_null=項目名稱不能為空
project_name_already_exists=項目名稱已存在
workspace_name_is_null=工作空間名不能為空
......@@ -16,10 +16,10 @@ run_load_test_file_init_error=無法運行測試,初始化運行環境失敗
load_test_is_running=測試正在運行, 請等待
node_deep_limit=節點深度不超過5層!
no_nodes_message=沒有節點信息
duplicate_node_ip=節點 IP 重
only_one_k8s=只能添加個 K8s
duplicate_node_ip=節點 IP 重
only_one_k8s=只能添加個 K8s
organization_id_is_null=組織 ID 不能為空
max_thread_insufficient=用戶數超額
max_thread_insufficient=用戶數超額
cannot_edit_load_test_running=不能修改正在運行的測試
test_not_found=測試不存在:
test_not_running=測試未運行
......@@ -38,7 +38,19 @@ cannot_delete_current_user=無法刪除當前登錄用戶
test_case_node_level=
test_case_node_level_tip=模塊樹最大深度為
test_case_module_not_null=所屬模塊不能為空
test_case_create_moule_fail=創建模塊失敗
test_case_create_module_fail=創建模塊失敗
test_case_import_template_name=測試用例模版
test_case_import_template_sheet=模版
module_not_null=所屬模塊不能為空格
user_not_exists=該工作空間下無該用戶
test_case_already_exists=該項目下已存在該測試用例
parse_data_error=解析數據出錯
missing_header_information=缺少頭部信息
number=
row=
incorrect_format=格式不正確
test_case_type_validate=必須為functional、performance、api
test_case_priority_validate=必須為P0、P1、P2、P3
test_case_method_validate=必須為manual、auto
error=出错
#test case end
\ No newline at end of file
......@@ -16,22 +16,13 @@
data() {
return {
endDate: new Date(),
unit: 'tests',
colorRange: ['#ebedf0', '#c6e48b', '#7bc96f', '#239a3b', '#196127'],
locale: {
// 一月 二月 三月 四月 五月 六月 七月 八月 九月 十月 十一月 十二月
months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
// 星期日 Sun. 星期一 Mon. 星期二 Tues. 星期三 Wed. 星期四 Thur. 星期五 Fri. 星期六 Sat.
days: ['Sun', 'Mon', 'Tues', 'Wed', 'Thur', 'Fri', 'Sat'],
No: 'No',
on: ',',
less: 'Less',
more: 'More'
},
}
},
mounted() {
this.locale.months = [
computed: {
locale() {
return {
months: [
this.$t('commons.months_1'),
this.$t('commons.months_2'),
this.$t('commons.months_3'),
......@@ -44,8 +35,8 @@
this.$t('commons.months_10'),
this.$t('commons.months_11'),
this.$t('commons.months_12')
];
this.locale.days = [
],
days: [
this.$t('commons.weeks_0'),
this.$t('commons.weeks_1'),
this.$t('commons.weeks_2'),
......@@ -53,9 +44,17 @@
this.$t('commons.weeks_4'),
this.$t('commons.weeks_5'),
this.$t('commons.weeks_6')
];
this.unit = this.$t('commons.test_unit')
],
No: 'No',
on: ',',
less: 'Less',
more: 'More'
}
},
unit() {
return this.$t('commons.test_unit')
}
},
}
</script>
......
<template>
<div>
<el-dialog width="30%" :title="$t('test_track.case.import.case_import')" :visible.sync="dialogVisible"
@close="init">
......@@ -41,8 +38,6 @@
</el-row>
</el-dialog>
</div>
</template>
<script>
......@@ -112,11 +107,9 @@
</script>
<style>
</style>
.el-dialog__body {
padding-top: 10px;
padding-bottom: 10px;
}
<style scoped>
.download-template {
padding-top: 0px;
......@@ -124,8 +117,3 @@
}
</style>
<style scoped>
</style>
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册