feat(接口测试): json-schema自动生成测试数据
--story=1015366 --user=陈建星 【接口测试】json-schema组件 https://www.tapd.cn/55049933/s/1547748
This commit is contained in:
parent
e4864184f8
commit
f4b277125c
|
@ -94,6 +94,12 @@
|
||||||
</exclusion>
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- 根据正则表达式,生成随机字符串 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.krraghavan</groupId>
|
||||||
|
<artifactId>xeger</artifactId>
|
||||||
|
<version>${xeger.version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -278,13 +278,20 @@ public class ApiDefinitionController {
|
||||||
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), apiDefinitionDir);
|
return apiFileResourceService.transfer(request, SessionUtils.getUserId(), apiDefinitionDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/preview")
|
@PostMapping("/json-schema/preview")
|
||||||
@Operation(summary = "接口测试-接口管理-接口-json-schema-预览")
|
@Operation(summary = "接口测试-接口管理-接口-json-schema-预览")
|
||||||
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
|
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
|
||||||
public String preview(@RequestBody JsonSchemaItem jsonSchemaItem) {
|
public String preview(@RequestBody JsonSchemaItem jsonSchemaItem) {
|
||||||
return apiDefinitionService.preview(jsonSchemaItem);
|
return apiDefinitionService.preview(jsonSchemaItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/json-schema/auto-generate")
|
||||||
|
@Operation(summary = "接口测试-接口管理-接口-json-schema-自动生成测试数据")
|
||||||
|
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
|
||||||
|
public String jsonSchemaAutoGenerate(@RequestBody JsonSchemaItem jsonSchemaItem) {
|
||||||
|
return apiDefinitionService.jsonSchemaAutoGenerate(jsonSchemaItem);
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping("/debug")
|
@PostMapping("/debug")
|
||||||
@Operation(summary = "接口调试")
|
@Operation(summary = "接口调试")
|
||||||
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_EXECUTE)
|
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_EXECUTE)
|
||||||
|
|
|
@ -106,7 +106,7 @@ public class JsonSchemaItem {
|
||||||
/**
|
/**
|
||||||
* 参数值的枚举
|
* 参数值的枚举
|
||||||
*/
|
*/
|
||||||
private List<? extends Object> enumValues;
|
private List<String> enumValues;
|
||||||
/**
|
/**
|
||||||
* 是否启用
|
* 是否启用
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -310,7 +310,7 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
|
||||||
} else {
|
} else {
|
||||||
String jsonString = JSON.toJSONString(jsonSchemaItem);
|
String jsonString = JSON.toJSONString(jsonSchemaItem);
|
||||||
if (StringUtils.isNotBlank(jsonString)) {
|
if (StringUtils.isNotBlank(jsonString)) {
|
||||||
jsonBody.setJsonValue(JsonSchemaBuilder.jsonSchemaToJson(jsonString));
|
jsonBody.setJsonValue(JsonSchemaBuilder.jsonSchemaToJson(jsonString, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return jsonBody;
|
return jsonBody;
|
||||||
|
@ -663,7 +663,10 @@ public class Swagger3Parser extends ApiImportAbstractParser<ApiDefinitionImport>
|
||||||
jsonSchemaItem.setFormat(StringUtils.isNotBlank(integerSchema.getFormat()) ? integerSchema.getFormat() : StringUtils.EMPTY);
|
jsonSchemaItem.setFormat(StringUtils.isNotBlank(integerSchema.getFormat()) ? integerSchema.getFormat() : StringUtils.EMPTY);
|
||||||
jsonSchemaItem.setMaximum(integerSchema.getMaximum());
|
jsonSchemaItem.setMaximum(integerSchema.getMaximum());
|
||||||
jsonSchemaItem.setMinimum(integerSchema.getMinimum());
|
jsonSchemaItem.setMinimum(integerSchema.getMinimum());
|
||||||
jsonSchemaItem.setEnumValues(integerSchema.getEnum());
|
List<Number> enumValues = integerSchema.getEnum();
|
||||||
|
if (CollectionUtils.isNotEmpty(enumValues)) {
|
||||||
|
jsonSchemaItem.setEnumValues(enumValues.stream().map(item -> item.toString()).toList());
|
||||||
|
}
|
||||||
return jsonSchemaItem;
|
return jsonSchemaItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1195,6 +1195,14 @@ public class ApiDefinitionService extends MoveNodeService {
|
||||||
return JsonSchemaBuilder.preview(JSON.toJSONString(jsonSchemaItem));
|
return JsonSchemaBuilder.preview(JSON.toJSONString(jsonSchemaItem));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String jsonSchemaAutoGenerate(JsonSchemaItem jsonSchemaItem) {
|
||||||
|
if (BooleanUtils.isFalse(jsonSchemaItem.getEnable())) {
|
||||||
|
return "{}";
|
||||||
|
}
|
||||||
|
filterDisableItem(jsonSchemaItem);
|
||||||
|
return JsonSchemaBuilder.jsonSchemaAutoGenerate(JSON.toJSONString(jsonSchemaItem));
|
||||||
|
}
|
||||||
|
|
||||||
private void filterDisableItem(JsonSchemaItem jsonSchemaItem) {
|
private void filterDisableItem(JsonSchemaItem jsonSchemaItem) {
|
||||||
if (isObjectItem(jsonSchemaItem)) {
|
if (isObjectItem(jsonSchemaItem)) {
|
||||||
Map<String, JsonSchemaItem> properties = jsonSchemaItem.getProperties();
|
Map<String, JsonSchemaItem> properties = jsonSchemaItem.getProperties();
|
||||||
|
|
|
@ -2,26 +2,26 @@ package io.metersphere.api.utils;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.JsonNode;
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
import com.fasterxml.jackson.databind.node.*;
|
import com.fasterxml.jackson.databind.node.*;
|
||||||
import io.metersphere.jmeter.mock.Mock;
|
|
||||||
import io.metersphere.project.constants.PropertyConstant;
|
import io.metersphere.project.constants.PropertyConstant;
|
||||||
|
import nl.flotsam.xeger.Xeger;
|
||||||
import org.apache.commons.collections4.MapUtils;
|
import org.apache.commons.collections4.MapUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.commons.text.RandomStringGenerator;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.regex.Matcher;
|
import java.util.Random;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
public class JsonSchemaBuilder {
|
public class JsonSchemaBuilder {
|
||||||
|
|
||||||
public static String jsonSchemaToJson(String jsonSchemaString) {
|
public static String jsonSchemaToJson(String jsonSchemaString, boolean isPreview) {
|
||||||
// 解析 JSON Schema 字符串为 JsonNode
|
// 解析 JSON Schema 字符串为 JsonNode
|
||||||
JsonNode jsonSchemaNode = ApiDataUtils.readTree(jsonSchemaString);
|
JsonNode jsonSchemaNode = ApiDataUtils.readTree(jsonSchemaString);
|
||||||
Map<String, String> processMap = new HashMap<>();
|
Map<String, String> processMap = new HashMap<>();
|
||||||
// 生成符合 JSON Schema 的 JSON
|
// 生成符合 JSON Schema 的 JSON
|
||||||
JsonNode jsonNode = generateJson(jsonSchemaNode, processMap);
|
JsonNode jsonNode = generateJson(jsonSchemaNode, processMap, isPreview);
|
||||||
String jsonString = ApiDataUtils.writerWithDefaultPrettyPrinter(jsonNode);
|
String jsonString = ApiDataUtils.writerWithDefaultPrettyPrinter(jsonNode);
|
||||||
if (MapUtils.isNotEmpty(processMap)) {
|
if (MapUtils.isNotEmpty(processMap)) {
|
||||||
for (String str : processMap.keySet()) {
|
for (String str : processMap.keySet()) {
|
||||||
|
@ -31,13 +31,13 @@ public class JsonSchemaBuilder {
|
||||||
return jsonString;
|
return jsonString;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JsonNode generateJson(JsonNode jsonSchemaNode, Map<String, String> processMap) {
|
private static JsonNode generateJson(JsonNode jsonSchemaNode, Map<String, String> processMap, boolean isPreview) {
|
||||||
ObjectNode jsonNode = ApiDataUtils.createObjectNode();
|
ObjectNode jsonNode = ApiDataUtils.createObjectNode();
|
||||||
|
|
||||||
if (jsonSchemaNode instanceof NullNode) {
|
if (jsonSchemaNode instanceof NullNode) {
|
||||||
return NullNode.getInstance();
|
return NullNode.getInstance();
|
||||||
}
|
}
|
||||||
String type = jsonSchemaNode.get(PropertyConstant.TYPE) == null ? StringUtils.EMPTY : jsonSchemaNode.get(PropertyConstant.TYPE).asText();
|
String type = getPropertyTextValue(jsonSchemaNode, PropertyConstant.TYPE);
|
||||||
if (StringUtils.equals(type, PropertyConstant.OBJECT)) {
|
if (StringUtils.equals(type, PropertyConstant.OBJECT)) {
|
||||||
JsonNode propertiesNode = jsonSchemaNode.get(PropertyConstant.PROPERTIES);
|
JsonNode propertiesNode = jsonSchemaNode.get(PropertyConstant.PROPERTIES);
|
||||||
// 遍历 properties
|
// 遍历 properties
|
||||||
|
@ -46,7 +46,8 @@ public class JsonSchemaBuilder {
|
||||||
String propertyName = entry.getKey();
|
String propertyName = entry.getKey();
|
||||||
JsonNode propertyNode = entry.getValue();
|
JsonNode propertyNode = entry.getValue();
|
||||||
// 根据属性类型生成对应的值
|
// 根据属性类型生成对应的值
|
||||||
JsonNode valueNode = generateValue(entry.getKey(), propertyNode, processMap);
|
JsonNode valueNode = isPreview ? generateValueForPreview(entry.getKey(), propertyNode, processMap)
|
||||||
|
: generateValue(entry.getKey(), propertyNode, processMap);
|
||||||
// 将属性和值添加到 JSON 对象节点
|
// 将属性和值添加到 JSON 对象节点
|
||||||
jsonNode.set(propertyName, valueNode);
|
jsonNode.set(propertyName, valueNode);
|
||||||
});
|
});
|
||||||
|
@ -55,23 +56,27 @@ public class JsonSchemaBuilder {
|
||||||
JsonNode items = jsonSchemaNode.get(PropertyConstant.ITEMS);
|
JsonNode items = jsonSchemaNode.get(PropertyConstant.ITEMS);
|
||||||
if (items != null) {
|
if (items != null) {
|
||||||
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
|
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
|
||||||
items.forEach(item -> arrayNode.add(generateValue(null, item, processMap)));
|
items.forEach(item -> {
|
||||||
|
JsonNode valueNode = isPreview ? generateValueForPreview(null, item, processMap)
|
||||||
|
: generateValue(null, item, processMap);
|
||||||
|
arrayNode.add(valueNode);
|
||||||
|
});
|
||||||
return arrayNode;
|
return arrayNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return jsonNode;
|
return jsonNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static JsonNode generateValue(String propertyName, JsonNode propertyNode, Map<String, String> processMap) {
|
private static JsonNode generateValueForPreview(String propertyName, JsonNode propertyNode, Map<String, String> processMap) {
|
||||||
// 获取属性类型
|
// 获取属性类型
|
||||||
if (propertyNode instanceof NullNode) {
|
if (propertyNode instanceof NullNode) {
|
||||||
return NullNode.getInstance();
|
return NullNode.getInstance();
|
||||||
}
|
}
|
||||||
String type = propertyNode.get(PropertyConstant.TYPE) == null ? StringUtils.EMPTY : propertyNode.get(PropertyConstant.TYPE).asText();
|
String type = getPropertyTextValue(propertyNode, PropertyConstant.TYPE);
|
||||||
String value = propertyNode.get(PropertyConstant.EXAMPLE) == null ? StringUtils.EMPTY : propertyNode.get(PropertyConstant.EXAMPLE).asText();
|
String value = getPropertyTextValue(propertyNode, PropertyConstant.EXAMPLE);
|
||||||
return switch (type) {
|
return switch (type) {
|
||||||
case PropertyConstant.STRING ->
|
case PropertyConstant.STRING ->
|
||||||
new TextNode(!StringUtils.equals(value, PropertyConstant.NULL) ? value : "string");
|
new TextNode(StringUtils.isBlank(value) ? "string" : value);
|
||||||
case PropertyConstant.INTEGER -> {
|
case PropertyConstant.INTEGER -> {
|
||||||
if (isVariable(value)) {
|
if (isVariable(value)) {
|
||||||
yield getJsonNodes(propertyName, processMap, value);
|
yield getJsonNodes(propertyName, processMap, value);
|
||||||
|
@ -97,8 +102,112 @@ public class JsonSchemaBuilder {
|
||||||
yield BooleanNode.valueOf(propertyNode.get(PropertyConstant.EXAMPLE).asBoolean());
|
yield BooleanNode.valueOf(propertyNode.get(PropertyConstant.EXAMPLE).asBoolean());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
case PropertyConstant.OBJECT -> generateJson(propertyNode, processMap, true);
|
||||||
|
case PropertyConstant.ARRAY -> {
|
||||||
|
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
|
||||||
|
JsonNode items = propertyNode.get(PropertyConstant.ITEMS);
|
||||||
|
if (items != null) {
|
||||||
|
items.forEach(item -> arrayNode.add(generateValueForPreview(null, item, processMap)));
|
||||||
|
}
|
||||||
|
yield arrayNode;
|
||||||
|
}
|
||||||
|
default -> NullNode.getInstance();
|
||||||
|
};
|
||||||
|
|
||||||
case PropertyConstant.OBJECT -> generateJson(propertyNode, processMap);
|
}
|
||||||
|
|
||||||
|
private static JsonNode generateValue(String propertyName, JsonNode propertyNode, Map<String, String> processMap) {
|
||||||
|
// 获取属性类型
|
||||||
|
if (propertyNode instanceof NullNode) {
|
||||||
|
return NullNode.getInstance();
|
||||||
|
}
|
||||||
|
String type = getPropertyTextValue(propertyNode, PropertyConstant.TYPE);
|
||||||
|
String value = getPropertyTextValue(propertyNode, PropertyConstant.EXAMPLE);
|
||||||
|
return switch (type) {
|
||||||
|
case PropertyConstant.STRING -> {
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
JsonNode enumValues = propertyNode.get(PropertyConstant.ENUM_VALUES);
|
||||||
|
JsonNode defaultValue = propertyNode.get(PropertyConstant.DEFAULT_VALUE);
|
||||||
|
JsonNode pattern = propertyNode.get(PropertyConstant.PATTERN);
|
||||||
|
JsonNode maxLength = propertyNode.get(PropertyConstant.MAX_LENGTH);
|
||||||
|
JsonNode minLength = propertyNode.get(PropertyConstant.MIN_LENGTH);
|
||||||
|
int max = isTextNotBlank(maxLength) ? maxLength.asInt() : 20;
|
||||||
|
int min = isTextNotBlank(minLength) ? minLength.asInt() : 1;
|
||||||
|
if (enumValues != null && enumValues instanceof ArrayNode) {
|
||||||
|
value = enumValues.get(new Random().nextInt(enumValues.size())).asText();
|
||||||
|
} else if (isTextNotBlank(defaultValue)) {
|
||||||
|
value = defaultValue.asText();
|
||||||
|
} else if (isTextNotBlank(pattern)) {
|
||||||
|
Xeger generator = new Xeger(pattern.asText());
|
||||||
|
value = generator.generate();
|
||||||
|
} else {
|
||||||
|
value = RandomStringGenerator.builder().withinRange('0', 'z').build().generate(new Random().nextInt(max - min + 1) + min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
yield new TextNode(value);
|
||||||
|
}
|
||||||
|
case PropertyConstant.INTEGER -> {
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
JsonNode enumValues = propertyNode.get(PropertyConstant.ENUM_VALUES);
|
||||||
|
JsonNode defaultValue = propertyNode.get(PropertyConstant.DEFAULT_VALUE);
|
||||||
|
if (enumValues != null && enumValues instanceof ArrayNode) {
|
||||||
|
value = enumValues.get(new Random().nextInt(enumValues.size())).asText();
|
||||||
|
} else if (isTextNotBlank(defaultValue)) {
|
||||||
|
value = defaultValue.asText();
|
||||||
|
} else {
|
||||||
|
JsonNode maximum = propertyNode.get(PropertyConstant.MAXIMUM);
|
||||||
|
JsonNode minimum = propertyNode.get(PropertyConstant.MINIMUM);
|
||||||
|
int max = isTextNotBlank(maximum) ? maximum.asInt() : Integer.MAX_VALUE;
|
||||||
|
int min = isTextNotBlank(minimum) ? minimum.asInt() : Integer.MIN_VALUE;
|
||||||
|
// 这里减去负数可能超过整型最大值,使用 Long 类型
|
||||||
|
value = new Random().nextLong(Long.valueOf(max) - Long.valueOf(min)) + min + StringUtils.EMPTY;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isVariable(value)) {
|
||||||
|
yield getJsonNodes(propertyName, processMap, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
yield new IntNode(Integer.valueOf(value));
|
||||||
|
} catch (Exception e) {
|
||||||
|
yield new IntNode(propertyNode.get(PropertyConstant.EXAMPLE).asInt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PropertyConstant.NUMBER -> {
|
||||||
|
if (StringUtils.isBlank(value)) {
|
||||||
|
JsonNode enumValues = propertyNode.get(PropertyConstant.ENUM_VALUES);
|
||||||
|
JsonNode defaultValue = propertyNode.get(PropertyConstant.DEFAULT_VALUE);
|
||||||
|
if (enumValues != null && enumValues instanceof ArrayNode) {
|
||||||
|
value = enumValues.get(new Random().nextInt(enumValues.size())).asText();
|
||||||
|
} else if (isTextNotBlank(defaultValue)) {
|
||||||
|
value = defaultValue.asText();
|
||||||
|
} else {
|
||||||
|
JsonNode maximum = propertyNode.get(PropertyConstant.MAXIMUM);
|
||||||
|
JsonNode minimum = propertyNode.get(PropertyConstant.MINIMUM);
|
||||||
|
BigDecimal max = isTextNotBlank(maximum) ? new BigDecimal(maximum.asText()) : new BigDecimal(String.valueOf(Float.MAX_VALUE));
|
||||||
|
BigDecimal min = isTextNotBlank(minimum) ? new BigDecimal(minimum.asText()) : new BigDecimal(String.valueOf(Float.MIN_VALUE));
|
||||||
|
BigDecimal randomBigDecimal = min.add(new BigDecimal(String.valueOf(Math.random())).multiply(max.subtract(min)));
|
||||||
|
yield new DecimalNode(randomBigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isVariable(value)) {
|
||||||
|
yield getJsonNodes(propertyName, processMap, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
yield new DecimalNode(new BigDecimal(value));
|
||||||
|
} catch (Exception e) {
|
||||||
|
yield new DecimalNode(propertyNode.get(PropertyConstant.EXAMPLE).decimalValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PropertyConstant.BOOLEAN -> {
|
||||||
|
if (isVariable(value)) {
|
||||||
|
yield getJsonNodes(propertyName, processMap, value);
|
||||||
|
} else {
|
||||||
|
yield BooleanNode.valueOf(propertyNode.get(PropertyConstant.EXAMPLE).asBoolean());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case PropertyConstant.OBJECT -> generateJson(propertyNode, processMap, true);
|
||||||
case PropertyConstant.ARRAY -> {
|
case PropertyConstant.ARRAY -> {
|
||||||
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
|
ArrayNode arrayNode = new ArrayNode(JsonNodeFactory.instance);
|
||||||
JsonNode items = propertyNode.get(PropertyConstant.ITEMS);
|
JsonNode items = propertyNode.get(PropertyConstant.ITEMS);
|
||||||
|
@ -112,6 +221,14 @@ public class JsonSchemaBuilder {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isTextNotBlank(JsonNode jsonNode) {
|
||||||
|
return jsonNode != null && !(jsonNode instanceof NullNode) && StringUtils.isNotBlank(jsonNode.asText());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getPropertyTextValue(JsonNode propertyNode, String key) {
|
||||||
|
return propertyNode.get(key) == null ? StringUtils.EMPTY : propertyNode.get(key).asText();
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isVariable(String value) {
|
private static boolean isVariable(String value) {
|
||||||
return !StringUtils.equals(value, PropertyConstant.NULL) && (value.startsWith("@") || value.startsWith("${"));
|
return !StringUtils.equals(value, PropertyConstant.NULL) && (value.startsWith("@") || value.startsWith("${"));
|
||||||
}
|
}
|
||||||
|
@ -125,25 +242,10 @@ public class JsonSchemaBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String preview(String jsonSchema) {
|
public static String preview(String jsonSchema) {
|
||||||
String jsonString = jsonSchemaToJson(jsonSchema);
|
return jsonSchemaToJson(jsonSchema, true);
|
||||||
//需要匹配到mock函数 然后换成mock数据
|
}
|
||||||
if (StringUtils.isNotBlank(jsonString)) {
|
|
||||||
String pattern = "@[a-zA-Z\\\\(|,'-\\\\d ]*[a-zA-Z)-9),\\\\\"]";
|
|
||||||
Pattern regex = Pattern.compile(pattern);
|
|
||||||
Matcher matcher = regex.matcher(jsonString);
|
|
||||||
while (matcher.find()) {
|
|
||||||
//取出group的最后一个字符 主要是防止 @string|number 和 @string 这种情况
|
|
||||||
String group = matcher.group();
|
|
||||||
String lastChar = null;
|
|
||||||
if (group.endsWith(",") || group.endsWith("\"")) {
|
|
||||||
lastChar = group.substring(group.length() - 1);
|
|
||||||
group = group.substring(0, group.length() - 1);
|
|
||||||
}
|
|
||||||
jsonString = jsonString.replace(matcher.group(),
|
|
||||||
StringUtils.join(Mock.calculate(group), lastChar));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return jsonString;
|
|
||||||
|
|
||||||
|
public static String jsonSchemaAutoGenerate(String jsonString) {
|
||||||
|
return jsonSchemaToJson(jsonString, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -22,5 +22,12 @@ public class PropertyConstant {
|
||||||
public final static String MOCK = "mock";
|
public final static String MOCK = "mock";
|
||||||
public final static String BODY_TYPE = "bodyType";
|
public final static String BODY_TYPE = "bodyType";
|
||||||
public final static String PARAM_TYPE = "paramType";
|
public final static String PARAM_TYPE = "paramType";
|
||||||
|
public final static String ENUM_VALUES = "enumValues";
|
||||||
|
public final static String DEFAULT_VALUE = "defaultValue";
|
||||||
|
public final static String PATTERN = "pattern";
|
||||||
|
public final static String MAX_LENGTH = "maxLength";
|
||||||
|
public final static String MIN_LENGTH = "minLength";
|
||||||
|
public final static String MINIMUM = "minimum";
|
||||||
|
public final static String MAXIMUM = "maximum";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ import {
|
||||||
GetTrashModuleCountUrl,
|
GetTrashModuleCountUrl,
|
||||||
GetTrashModuleTreeUrl,
|
GetTrashModuleTreeUrl,
|
||||||
ImportDefinitionUrl,
|
ImportDefinitionUrl,
|
||||||
|
JsonSchemaAutoGenerateUrl,
|
||||||
MockDetailUrl,
|
MockDetailUrl,
|
||||||
MoveModuleUrl,
|
MoveModuleUrl,
|
||||||
OperationHistoryUrl,
|
OperationHistoryUrl,
|
||||||
|
@ -308,6 +309,11 @@ export function convertJsonSchemaToJson(data: JsonSchema) {
|
||||||
return MSR.post({ url: ConvertJsonSchemaToJsonUrl, data });
|
return MSR.post({ url: ConvertJsonSchemaToJsonUrl, data });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// json-schema 生成测试数据
|
||||||
|
export function jsonSchemaAutoGenerate(data: JsonSchema) {
|
||||||
|
return MSR.post({ url: JsonSchemaAutoGenerateUrl, data });
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mock
|
* Mock
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -36,7 +36,8 @@ export const OperationHistoryUrl = '/api/definition/operation-history'; // 接
|
||||||
export const SaveOperationHistoryUrl = '/api/definition/operation-history/save'; // 接口定义-另存变更历史为指定版本
|
export const SaveOperationHistoryUrl = '/api/definition/operation-history/save'; // 接口定义-另存变更历史为指定版本
|
||||||
export const RecoverOperationHistoryUrl = '/api/definition/operation-history/recover'; // 接口定义-变更历史恢复
|
export const RecoverOperationHistoryUrl = '/api/definition/operation-history/recover'; // 接口定义-变更历史恢复
|
||||||
export const DefinitionReferenceUrl = '/api/definition/get-reference'; // 获取接口引用关系
|
export const DefinitionReferenceUrl = '/api/definition/get-reference'; // 获取接口引用关系
|
||||||
export const ConvertJsonSchemaToJsonUrl = '/api/definition/preview'; // 将json-schema转换为 json 数据
|
export const ConvertJsonSchemaToJsonUrl = '/api/definition/json-schema/preview'; // 将json-schema转换为 json 数据
|
||||||
|
export const JsonSchemaAutoGenerateUrl = '/api/definition/json-schema/auto-generate'; // 将json-schema转换为 json 数据
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mock
|
* Mock
|
||||||
|
|
|
@ -427,7 +427,7 @@
|
||||||
<template v-if="activeRecord.type === 'string'">
|
<template v-if="activeRecord.type === 'string'">
|
||||||
<a-form-item :label="t('ms.json.schema.regex')">
|
<a-form-item :label="t('ms.json.schema.regex')">
|
||||||
<a-input
|
<a-input
|
||||||
v-model:model-value="activeRecord.regex"
|
v-model:model-value="activeRecord.pattern"
|
||||||
:placeholder="t('ms.json.schema.regexPlaceholder', { reg: '/<title(.*?)</title>' })"
|
:placeholder="t('ms.json.schema.regexPlaceholder', { reg: '/<title(.*?)</title>' })"
|
||||||
@change="handleSettingFormChange"
|
@change="handleSettingFormChange"
|
||||||
/>
|
/>
|
||||||
|
@ -821,8 +821,8 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: t('ms.json.schema.regex'),
|
title: t('ms.json.schema.regex'),
|
||||||
dataIndex: 'regex',
|
dataIndex: 'pattern',
|
||||||
slotName: 'regex',
|
slotName: 'pattern',
|
||||||
inputType: 'input',
|
inputType: 'input',
|
||||||
size: 'medium',
|
size: 'medium',
|
||||||
addLineDisabled: true,
|
addLineDisabled: true,
|
||||||
|
|
|
@ -185,7 +185,7 @@
|
||||||
import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue';
|
import batchAddKeyVal from '@/views/api-test/components/batchAddKeyVal.vue';
|
||||||
import paramTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
import paramTable, { type ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||||
|
|
||||||
import { convertJsonSchemaToJson } from '@/api/modules/api-test/management';
|
import { jsonSchemaAutoGenerate } from '@/api/modules/api-test/management';
|
||||||
import { requestBodyTypeMap } from '@/config/apiTest';
|
import { requestBodyTypeMap } from '@/config/apiTest';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
@ -387,7 +387,7 @@
|
||||||
const schema = parseTableDataToJsonSchema(innerParams.value.jsonBody.jsonSchemaTableData?.[0]);
|
const schema = parseTableDataToJsonSchema(innerParams.value.jsonBody.jsonSchemaTableData?.[0]);
|
||||||
if (schema) {
|
if (schema) {
|
||||||
// 再将 json schema 转换为 json 格式
|
// 再将 json schema 转换为 json 格式
|
||||||
const res = await convertJsonSchemaToJson(schema);
|
const res = await jsonSchemaAutoGenerate(schema);
|
||||||
innerParams.value.jsonBody.jsonValue = res;
|
innerParams.value.jsonBody.jsonValue = res;
|
||||||
emit('change');
|
emit('change');
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -254,7 +254,7 @@
|
||||||
import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
import paramTable, { ParamTableColumn } from '@/views/api-test/components/paramTable.vue';
|
||||||
import popConfirm from '@/views/api-test/components/popConfirm.vue';
|
import popConfirm from '@/views/api-test/components/popConfirm.vue';
|
||||||
|
|
||||||
import { convertJsonSchemaToJson } from '@/api/modules/api-test/management';
|
import { jsonSchemaAutoGenerate } from '@/api/modules/api-test/management';
|
||||||
import { responseHeaderOption } from '@/config/apiTest';
|
import { responseHeaderOption } from '@/config/apiTest';
|
||||||
import { useI18n } from '@/hooks/useI18n';
|
import { useI18n } from '@/hooks/useI18n';
|
||||||
import useAppStore from '@/store/modules/app';
|
import useAppStore from '@/store/modules/app';
|
||||||
|
@ -431,7 +431,7 @@
|
||||||
}
|
}
|
||||||
if (schema) {
|
if (schema) {
|
||||||
// 再将 json schema 转换为 json 格式
|
// 再将 json schema 转换为 json 格式
|
||||||
const res = await convertJsonSchemaToJson(schema);
|
const res = await jsonSchemaAutoGenerate(schema);
|
||||||
activeResponse.value.body.jsonBody.jsonValue = res;
|
activeResponse.value.body.jsonBody.jsonValue = res;
|
||||||
} else {
|
} else {
|
||||||
Message.warning(t('apiTestManagement.pleaseInputJsonSchema'));
|
Message.warning(t('apiTestManagement.pleaseInputJsonSchema'));
|
||||||
|
|
2
pom.xml
2
pom.xml
|
@ -85,7 +85,7 @@
|
||||||
<commons-jexl3.version>3.3</commons-jexl3.version>
|
<commons-jexl3.version>3.3</commons-jexl3.version>
|
||||||
<revision>3.x</revision>
|
<revision>3.x</revision>
|
||||||
<monitoring-engine.revision>3.0</monitoring-engine.revision>
|
<monitoring-engine.revision>3.0</monitoring-engine.revision>
|
||||||
|
<xeger.version>1.0.0-RELEASE</xeger.version>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<modules>
|
<modules>
|
||||||
|
|
Loading…
Reference in New Issue