refactor(工作台): 优化 API 统计时内存占用较大
This commit is contained in:
parent
c7bfb50fb0
commit
ccf932f03b
|
@ -97,26 +97,29 @@ public class ApiDefinitionController {
|
|||
@RequiresPermissions(PermissionConstants.PROJECT_API_DEFINITION_READ)
|
||||
@CheckOwner(resourceId = "#projectId", resourceType = "project")
|
||||
public ApiCoverageDTO rage(@PathVariable String projectId) {
|
||||
List<String> apiAllIds = new ArrayList<>();
|
||||
List<ApiDefinition> httpApiList = new ArrayList<>();
|
||||
extApiDefinitionMapper.selectBaseInfoByProjectId(projectId).forEach(apiDefinition -> {
|
||||
if (StringUtils.equalsIgnoreCase(apiDefinition.getProtocol(), "http")) {
|
||||
httpApiList.add(apiDefinition);
|
||||
}
|
||||
apiAllIds.add(apiDefinition.getId());
|
||||
});
|
||||
// 筛选出所有 API 的 ID 和 HTTP 类型的 API
|
||||
List<ApiDefinition> apiDefinitions = extApiDefinitionMapper.selectBaseInfoByProjectId(projectId);
|
||||
List<String> apiAllIds = apiDefinitions.stream().map(ApiDefinition::getId).toList();
|
||||
List<ApiDefinition> httpApiList = apiDefinitions.stream()
|
||||
.filter(api -> StringUtils.equalsIgnoreCase(api.getProtocol(), "http"))
|
||||
.toList();
|
||||
|
||||
// 获取 API 定义、测试用例 ID 和场景步骤中的 API ID
|
||||
List<String> apiDefinitionIdFromCase = extApiTestCaseMapper.selectApiId(projectId);
|
||||
List<String> apiInScenarioStep = extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API.name());
|
||||
List<String> apiInScenarioStep = new ArrayList<>(extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API.name()));
|
||||
List<String> apiCaseIdInStep = extApiScenarioStepMapper.selectResourceId(projectId, ApiScenarioStepType.API_CASE.name());
|
||||
|
||||
// 如果有场景步骤中的 API 用例 ID,追加相关 API ID
|
||||
if (CollectionUtils.isNotEmpty(apiCaseIdInStep)) {
|
||||
List<String> apiCaseIdInScenarioStep = extApiTestCaseMapper.selectApiIdByCaseId(apiCaseIdInStep);
|
||||
apiInScenarioStep.addAll(apiCaseIdInScenarioStep);
|
||||
}
|
||||
|
||||
List<String> apiInStepList = apiScenarioService.selectApiIdInCustomRequest(projectId, httpApiList);
|
||||
// 获取自定义步骤中的 API ID 并合并
|
||||
List<String> apiInStepList = new ArrayList<>(apiScenarioService.selectApiIdInCustomRequest(projectId, httpApiList));
|
||||
apiInStepList.addAll(apiInScenarioStep);
|
||||
|
||||
// 构建结果 DTO
|
||||
return new ApiCoverageDTO(apiAllIds, apiDefinitionIdFromCase, apiInStepList);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.metersphere.api.mapper;
|
||||
|
||||
import io.metersphere.api.domain.ApiScenarioCsvStep;
|
||||
import io.metersphere.api.domain.ApiScenarioStep;
|
||||
import io.metersphere.api.dto.scenario.ApiScenarioStepDTO;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
|
@ -29,5 +28,5 @@ public interface ExtApiScenarioStepMapper {
|
|||
|
||||
List<String> selectResourceId(@Param("projectId") String projectId, @Param("stepType") String stepType);
|
||||
|
||||
List<ApiScenarioStep> selectCustomRequestConfigByProjectId(String projectId);
|
||||
List<String> selectCustomRequestConfigByProjectId(String projectId);
|
||||
}
|
||||
|
|
|
@ -37,12 +37,14 @@
|
|||
AND scenario.project_id = #{projectId}
|
||||
AND scenario.deleted IS FALSE
|
||||
</select>
|
||||
<select id="selectCustomRequestConfigByProjectId" resultType="io.metersphere.api.domain.ApiScenarioStep">
|
||||
select step.id, step.config
|
||||
<select id="selectCustomRequestConfigByProjectId" resultType="java.lang.String">
|
||||
select step.id
|
||||
from api_scenario_step step
|
||||
INNER JOIN api_scenario scenario
|
||||
ON step.scenario_id = scenario.id
|
||||
where scenario.project_id = #{0}
|
||||
AND scenario.deleted IS FALSE
|
||||
AND step.step_type IN ('API', 'API_CASE', 'CUSTOM_REQUEST')
|
||||
AND JSON_EXTRACT(step.config, '$.protocol') = 'http'
|
||||
</select>
|
||||
</mapper>
|
|
@ -2375,7 +2375,6 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
}
|
||||
|
||||
|
||||
|
||||
public List<OperationHistoryDTO> operationHistoryList(OperationHistoryRequest request) {
|
||||
return operationHistoryService.listWidthTable(request, SCENARIO_TABLE);
|
||||
}
|
||||
|
@ -2626,45 +2625,51 @@ public class ApiScenarioService extends MoveNodeService {
|
|||
}
|
||||
|
||||
public List<String> selectApiIdInCustomRequest(String projectId, List<ApiDefinition> apiDefinitions) {
|
||||
List<String> returnList = new ArrayList<>();
|
||||
List<ApiScenarioStep> stepConfigList = extApiScenarioStepMapper.selectCustomRequestConfigByProjectId(projectId);
|
||||
List<String> requestIdList = new ArrayList<>();
|
||||
stepConfigList.forEach(step -> requestIdList.add(step.getId()));
|
||||
if (apiDefinitions == null || apiDefinitions.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
// 获取项目中所有的自定义请求 ID
|
||||
List<String> requestIdList = extApiScenarioStepMapper.selectCustomRequestConfigByProjectId(projectId);
|
||||
if (requestIdList.isEmpty()) {
|
||||
return returnList;
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
|
||||
// 分批处理配置请求 ID 列表
|
||||
Map<String, Set<String>> methodPathMap = new HashMap<>();
|
||||
SubListUtils.dealForSubList(requestIdList, 200, batchIds -> {
|
||||
// 查询当前批次的 Blob 数据
|
||||
ApiScenarioStepBlobExample scenarioStepBlobExample = new ApiScenarioStepBlobExample();
|
||||
scenarioStepBlobExample.createCriteria().andIdIn(requestIdList);
|
||||
List<ApiScenarioStepBlob> httpRequestStopBlobList = apiScenarioStepBlobMapper.selectByExampleWithBLOBs(scenarioStepBlobExample);
|
||||
Map<String, List<String>> methodPathMap = new HashMap<>();
|
||||
httpRequestStopBlobList.forEach(blob -> {
|
||||
if (blob.getContent() != null) {
|
||||
scenarioStepBlobExample.createCriteria().andIdIn(batchIds);
|
||||
List<ApiScenarioStepBlob> blobList = apiScenarioStepBlobMapper.selectByExampleWithBLOBs(scenarioStepBlobExample);
|
||||
|
||||
// 解析并构建方法与路径映射,处理完一个批次后释放内存
|
||||
blobList.stream()
|
||||
.map(ApiScenarioStepBlob::getContent)
|
||||
.filter(Objects::nonNull)
|
||||
.forEach(content -> {
|
||||
try {
|
||||
AbstractMsProtocolTestElement protocolTestElement = ApiDataUtils.parseObject(new String(blob.getContent()), AbstractMsProtocolTestElement.class);
|
||||
AbstractMsProtocolTestElement protocolTestElement = ApiDataUtils.parseObject(new String(content), AbstractMsProtocolTestElement.class);
|
||||
if (protocolTestElement instanceof MsHTTPElement msHTTPElement) {
|
||||
String method = msHTTPElement.getMethod();
|
||||
if (methodPathMap.containsKey(method)) {
|
||||
methodPathMap.get(method).add(msHTTPElement.getPath());
|
||||
} else {
|
||||
List<String> pathList = new ArrayList<>();
|
||||
pathList.add(msHTTPElement.getPath());
|
||||
methodPathMap.put(method, pathList);
|
||||
}
|
||||
methodPathMap.computeIfAbsent(msHTTPElement.getMethod(), k -> new HashSet<>())
|
||||
.add(msHTTPElement.getPath());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
for (ApiDefinition apiDefinition : apiDefinitions) {
|
||||
if (methodPathMap.containsKey(apiDefinition.getMethod())) {
|
||||
String apiPath = apiDefinition.getPath();
|
||||
List<String> customUrlList = methodPathMap.get(apiDefinition.getMethod());
|
||||
if (ApiDefinitionUtils.isUrlInList(apiPath, customUrlList)) {
|
||||
returnList.add(apiDefinition.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
return returnList;
|
||||
blobList.clear(); // 清空当前批次,释放内存
|
||||
});
|
||||
|
||||
// 遍历 API 定义,匹配路径
|
||||
return apiDefinitions.stream()
|
||||
.filter(apiDefinition -> {
|
||||
Set<String> customUrls = methodPathMap.get(apiDefinition.getMethod());
|
||||
return customUrls != null && ApiDefinitionUtils.isUrlInList(apiDefinition.getPath(), customUrls);
|
||||
})
|
||||
.map(ApiDefinition::getId)
|
||||
.toList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ public class ApiCalculateTest extends BaseTest {
|
|||
Assertions.assertEquals(16, apiCoverageDTO.getUnCoverWithApiCase());
|
||||
Assertions.assertEquals(apiCoverageDTO.getApiCaseCoverage(), CalculateUtils.reportPercentage(apiCoverageDTO.getCoverWithApiCase(), apiCoverageDTO.getAllApiCount()));
|
||||
|
||||
Assertions.assertEquals(8, apiCoverageDTO.getCoverWithApiScenario());
|
||||
Assertions.assertEquals(4, apiCoverageDTO.getCoverWithApiScenario());
|
||||
Assertions.assertEquals(12, apiCoverageDTO.getUnCoverWithApiScenario());
|
||||
Assertions.assertEquals(apiCoverageDTO.getScenarioCoverage(), CalculateUtils.reportPercentage(apiCoverageDTO.getCoverWithApiScenario(), apiCoverageDTO.getAllApiCount()));
|
||||
|
||||
|
|
Loading…
Reference in New Issue