Commit c1628ebf authored by linpeiqin's avatar linpeiqin

数据集管理第一版完成

parent 78bb81ca
...@@ -60,7 +60,12 @@ ...@@ -60,7 +60,12 @@
<artifactId>common-dict</artifactId> <artifactId>common-dict</artifactId>
<version>1.0.0</version> <version>1.0.0</version>
</dependency> </dependency>
</dependencies> <dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>
</dependencies>
<build> <build>
<plugins> <plugins>
......
...@@ -12,11 +12,14 @@ import com.yice.common.core.util.*; ...@@ -12,11 +12,14 @@ import com.yice.common.core.util.*;
import com.yice.common.core.constant.*; import com.yice.common.core.constant.*;
import com.yice.common.core.annotation.MyRequestBody; import com.yice.common.core.annotation.MyRequestBody;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.yice.webadmin.config.ApplicationConfig;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.*; import java.util.*;
/** /**
...@@ -34,6 +37,9 @@ public class DatasetDetailController { ...@@ -34,6 +37,9 @@ public class DatasetDetailController {
@Autowired @Autowired
private DatasetDetailService datasetDetailService; private DatasetDetailService datasetDetailService;
@Autowired
private ApplicationConfig appConfig;
/** /**
* 新增数据集详情数据。 * 新增数据集详情数据。
* *
...@@ -148,4 +154,44 @@ public class DatasetDetailController { ...@@ -148,4 +154,44 @@ public class DatasetDetailController {
} }
return ResponseResult.success(); return ResponseResult.success();
} }
/**
* 导入主表数据列表。
*
* @param importFile 上传的文件,目前仅仅支持xlsx和xls两种格式。
* @return 应答结果对象。
*/
@OperationLog(type = SysOperationLogType.IMPORT)
@PostMapping("/import")
public ResponseResult<Void> importBatch(
@RequestParam Long datasetId,
@RequestParam Long versionId,
@RequestParam Boolean skipHeader,
@RequestParam("importFile") MultipartFile importFile) throws IOException {
String errorMessage;
if (Objects.isNull(importFile) || importFile.isEmpty()) {
errorMessage = "数据验证失败,导入文件不能为空!";
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST, errorMessage);
}
ImportUtil.saveImportFile(appConfig.getUploadFileBaseDir(), null, importFile);
// 这里可以指定需要忽略导入的字段集合。如创建时间、创建人、更新时间、更新人、主键Id和逻辑删除,
// 以及一些存在缺省值且无需导入的字段。其中主键字段和逻辑删除字段不需要在这里设置,批量插入逻辑会自动处理的。
/*Set<String> ignoreFieldSet = new HashSet<>();
ignoreFieldSet.add("createUserId");
ignoreFieldSet.add("createTime");
ignoreFieldSet.add("updateUserId");
ignoreFieldSet.add("updateTime");
List<ImportUtil.ImportHeaderInfo> headerInfoList = ImportUtil.makeHeaderInfoList(DatasetDetail.class, ignoreFieldSet);
// TODO: 下面是导入时需要注意的地方,如果我们缺省生成的代码,与实际情况存在差异,请手动修改。
// 1. 头信息数据字段,我们只是根据当前的主表实体对象生成了缺省数组,开发者可根据实际情况,对headerInfoList进行修改。
ImportUtil.ImportHeaderInfo[] headerInfos = headerInfoList.toArray(new ImportUtil.ImportHeaderInfo[]{});
// 2. 这里需要根据实际情况决定,导入文件中第一行是否为中文头信息,如果是可以跳过。这里我们默认为true。
// 这里根据自己的实际需求,为doImport的最后一个参数,传递需要进行字典转换的字段集合。
// 注意,集合中包含需要翻译的Java字段名,如: gradeId。
Set<String> translatedDictFieldSet = new HashSet<>();
List<DatasetDetail> dataList =
ImportUtil.doImport(headerInfos, skipHeader, filename, DatasetDetail.class, translatedDictFieldSet);
datasetDetailService.saveNewBatch(dataList, -1);*/
return ResponseResult.success();
}
} }
...@@ -49,7 +49,8 @@ public class DatasetManageController { ...@@ -49,7 +49,8 @@ public class DatasetManageController {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
} }
DatasetManage datasetManage = MyModelUtil.copyTo(datasetManageDto, DatasetManage.class); DatasetManage datasetManage = MyModelUtil.copyTo(datasetManageDto, DatasetManage.class);
datasetManage = datasetManageService.saveNew(datasetManage); // datasetManage = datasetManageService.saveNew(datasetManage);
datasetManage = datasetManageService.saveAndCreateVersion(datasetManage);
return ResponseResult.success(datasetManage.getDatasetId()); return ResponseResult.success(datasetManage.getDatasetId());
} }
......
package com.yice.webadmin.app.controller; package com.yice.webadmin.app.controller;
import com.yice.common.log.annotation.OperationLog; import cn.hutool.poi.excel.ExcelUtil;
import com.yice.common.log.model.constant.SysOperationLogType; import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod; import com.github.pagehelper.page.PageMethod;
import com.yice.webadmin.app.vo.*;
import com.yice.webadmin.app.dto.*;
import com.yice.webadmin.app.model.*;
import com.yice.webadmin.app.service.*;
import com.yice.common.core.object.*;
import com.yice.common.core.util.*;
import com.yice.common.core.constant.*;
import com.yice.common.core.annotation.MyRequestBody;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport; import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.yice.common.core.annotation.MyRequestBody;
import com.yice.common.core.constant.ErrorCodeEnum;
import com.yice.common.core.object.*;
import com.yice.common.core.util.ImportUtil;
import com.yice.common.core.util.MyCommonUtil;
import com.yice.common.core.util.MyModelUtil;
import com.yice.common.core.util.MyPageUtil;
import com.yice.common.log.annotation.OperationLog;
import com.yice.common.log.model.constant.SysOperationLogType;
import com.yice.webadmin.app.dto.DatasetDetailDto;
import com.yice.webadmin.app.dto.DatasetVersionDto;
import com.yice.webadmin.app.model.DatasetDetail;
import com.yice.webadmin.app.model.DatasetVersion;
import com.yice.webadmin.app.service.DatasetVersionService;
import com.yice.webadmin.app.vo.DatasetVersionVo;
import com.yice.webadmin.config.ApplicationConfig;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.*; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
/** /**
* 数据集版本操作控制器类。 * 数据集版本操作控制器类。
...@@ -33,6 +62,8 @@ public class DatasetVersionController { ...@@ -33,6 +62,8 @@ public class DatasetVersionController {
@Autowired @Autowired
private DatasetVersionService datasetVersionService; private DatasetVersionService datasetVersionService;
@Autowired
private ApplicationConfig appConfig;
/** /**
* 新增数据集版本数据。 * 新增数据集版本数据。
...@@ -98,9 +129,9 @@ public class DatasetVersionController { ...@@ -98,9 +129,9 @@ public class DatasetVersionController {
* 列出符合过滤条件的数据集版本列表。 * 列出符合过滤条件的数据集版本列表。
* *
* @param datasetVersionDtoFilter 过滤对象。 * @param datasetVersionDtoFilter 过滤对象。
* @param datasetDetailDtoFilter 一对一从表过滤对象。 * @param datasetDetailDtoFilter 一对一从表过滤对象。
* @param orderParam 排序参数。 * @param orderParam 排序参数。
* @param pageParam 分页参数。 * @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。 * @return 应答结果对象,包含查询结果集。
*/ */
@PostMapping("/list") @PostMapping("/list")
...@@ -151,4 +182,73 @@ public class DatasetVersionController { ...@@ -151,4 +182,73 @@ public class DatasetVersionController {
} }
return ResponseResult.success(); return ResponseResult.success();
} }
@PostMapping(value = "/detail")
public ResponseResult<MyPageData<String>> detail(@MyRequestBody Long versionId,
@MyRequestBody MyPageParam pageParam) throws IOException {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
DatasetVersion datasetVersion = this.datasetVersionService.getById(versionId);
File file = new File(datasetVersion.getFileUrl()); // 指定文件路径
ObjectMapper objectMapper = new ObjectMapper();
ArrayNode arrayNode = (ArrayNode) objectMapper.readTree(file); // 读取JSON文件内容并转换为ArrayNode对象
List<String> dataList = new ArrayList<>();
for (JsonNode jsonNode : arrayNode) { // 遍历JSON数组并取出每个元素(ObjectNode)中的数据
dataList.add(jsonNode.toString());
}
int total = dataList.size(); // 获取总数据量
int page = pageParam.getPageNum();
int limit = pageParam.getPageSize();
int startIndex = (page - 1) * limit; // 计算起始索引位置
int endIndex = Math.min(page * limit, total); // 计算结束索引位置(不超出总数据量)
List<String> pageDataList = dataList.subList(startIndex, endIndex); // 分页处理并取出指定页的数据列表
return ResponseResult.success(MyPageUtil.makeResponseData(pageDataList, (long) total));
}
/**
* 导入主表数据列表。
*
* @param importFile 上传的文件。
* @return 应答结果对象。
*/
@OperationLog(type = SysOperationLogType.IMPORT)
@PostMapping("/import")
public ResponseResult<Void> importFile(
@RequestParam Long datasetId,
@RequestParam Long versionId,
@RequestParam("importFile") MultipartFile importFile) throws IOException {
String errorMessage;
if (Objects.isNull(importFile) || importFile.isEmpty()) {
errorMessage = "数据验证失败,导入文件不能为空!";
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST, errorMessage);
}
DatasetVersion datasetVersion = this.datasetVersionService.getById(versionId);
String subDir = datasetId + "-" + datasetVersion.getDatasetVersion();
String fullName = ImportUtil.saveImportFile(appConfig.getUploadFileBaseDir(), subDir, importFile);
datasetVersion.setFileUrl(fullName);
datasetVersion.setInputStatus(1);
datasetVersion.setDataVolume(Long.valueOf(JSON.parseArray(new String(importFile.getBytes(), StandardCharsets.UTF_8)).size()));
this.datasetVersionService.updateById(datasetVersion);
return ResponseResult.success();
}
@GetMapping("/export")
public ResponseEntity<Resource> export(@RequestParam Long versionId) throws IOException {
DatasetVersion datasetVersion = this.datasetVersionService.getById(versionId);
Path file = Paths.get(datasetVersion.getFileUrl()); // 指定本地JSON文件的路径
Resource resource = new UrlResource(file.toUri()); // 使用UrlResource从文件路径构建一个Resource对象
Optional<Resource> optionalResource = Optional.ofNullable(resource);
if (optionalResource.isPresent() && optionalResource.get().exists()) { // 检查文件是否存在
HttpHeaders headers = new HttpHeaders(); // 构建HTTP响应头
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\""); // 设置内容类型为附件,并指定文件名
headers.setContentType(MediaType.TEXT_PLAIN); // 设置内容类型为JSON
return ResponseEntity.ok() // 返回200 OK状态码
.headers(headers) // 设置响应头
.contentLength(resource.contentLength()) // 设置响应内容长度(可选)
.body(resource); // 将Resource对象作为响应的主体返回
} else {
return ResponseEntity.notFound().build(); // 如果文件不存在,返回404 Not Found状态码
}
}
} }
...@@ -49,6 +49,11 @@ public class ModelDeployController { ...@@ -49,6 +49,11 @@ public class ModelDeployController {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
} }
ModelDeploy modelDeploy = MyModelUtil.copyTo(modelDeployDto, ModelDeploy.class); ModelDeploy modelDeploy = MyModelUtil.copyTo(modelDeployDto, ModelDeploy.class);
// 验证关联Id的数据合法性
CallResult callResult = modelDeployService.verifyRelatedData(modelDeploy, null);
if (!callResult.isSuccess()) {
return ResponseResult.errorFrom(callResult);
}
modelDeploy = modelDeployService.saveNew(modelDeploy); modelDeploy = modelDeployService.saveNew(modelDeploy);
return ResponseResult.success(modelDeploy.getDeployId()); return ResponseResult.success(modelDeploy.getDeployId());
} }
...@@ -73,6 +78,11 @@ public class ModelDeployController { ...@@ -73,6 +78,11 @@ public class ModelDeployController {
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
} }
// 验证关联Id的数据合法性
CallResult callResult = modelDeployService.verifyRelatedData(modelDeploy, originalModelDeploy);
if (!callResult.isSuccess()) {
return ResponseResult.errorFrom(callResult);
}
if (!modelDeployService.update(modelDeploy, originalModelDeploy)) { if (!modelDeployService.update(modelDeploy, originalModelDeploy)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
} }
......
package com.yice.webadmin.app.controller;
import com.alibaba.fastjson.JSONObject;
import com.yice.common.log.annotation.OperationLog;
import com.yice.common.log.model.constant.SysOperationLogType;
import com.github.pagehelper.page.PageMethod;
import com.yice.webadmin.app.vo.*;
import com.yice.webadmin.app.dto.*;
import com.yice.webadmin.app.model.*;
import com.yice.webadmin.app.service.*;
import com.yice.common.core.object.*;
import com.yice.common.core.util.*;
import com.yice.common.core.constant.*;
import com.yice.common.core.annotation.MyRequestBody;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.*;
/**
* 模型管理操作控制器类。
*
* @author linking
* @date 2023-04-13
*/
@Api(tags = "模型管理接口")
@Slf4j
@RestController
@RequestMapping("/admin/app/modelManage")
public class ModelManageController {
@Autowired
private ModelManageService modelManageService;
@Autowired
private ModelVersionService modelVersionService;
/**
* 新增模型管理数据,及其关联的从表数据。
*
* @param modelManageDto 新增主表对象。
* @return 应答结果对象,包含新增对象主键Id。
*/
@ApiOperationSupport(ignoreParameters = {"modelManageDto.modelId", "modelManageDto.searchString"})
@OperationLog(type = SysOperationLogType.ADD)
@PostMapping("/add")
public ResponseResult<Long> add(
@MyRequestBody ModelManageDto modelManageDto,
@MyRequestBody ModelVersionDto modelVersionDto) {
String errorMessage = MyCommonUtil.getModelValidationError(modelManageDto, false);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
ModelManage modelManage = MyModelUtil.copyTo(modelManageDto, ModelManage.class);
ModelVersion modelVersion = MyModelUtil.copyTo(modelVersionDto, ModelVersion.class);
modelManage = modelManageService.saveAndCreateVersion(modelManage,modelVersion);
return ResponseResult.success(modelManage.getModelId());
}
/**
* 更新模型管理数据。
*
* @param modelManageDto 更新对象。
* @return 应答结果对象。
*/
@ApiOperationSupport(ignoreParameters = {"modelManageDto.searchString"})
@OperationLog(type = SysOperationLogType.UPDATE)
@PostMapping("/update")
public ResponseResult<Void> update(@MyRequestBody ModelManageDto modelManageDto) {
String errorMessage = MyCommonUtil.getModelValidationError(modelManageDto, true);
if (errorMessage != null) {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
}
ModelManage modelManage = MyModelUtil.copyTo(modelManageDto, ModelManage.class);
ModelManage originalModelManage = modelManageService.getById(modelManage.getModelId());
if (originalModelManage == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!modelManageService.update(modelManage, originalModelManage)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
return ResponseResult.success();
}
/**
* 删除模型管理数据。
*
* @param modelId 删除对象主键Id。
* @return 应答结果对象。
*/
@OperationLog(type = SysOperationLogType.DELETE)
@PostMapping("/delete")
public ResponseResult<Void> delete(@MyRequestBody Long modelId) {
if (MyCommonUtil.existBlankArgument(modelId)) {
return ResponseResult.error(ErrorCodeEnum.ARGUMENT_NULL_EXIST);
}
return this.doDelete(modelId);
}
/**
* 列出符合过滤条件的模型管理列表。
*
* @param modelManageDtoFilter 过滤对象。
* @param modelVersionDtoFilter 一对多从表过滤对象。
* @param modelTaskDtoFilter 一对多从表过滤对象。
* @param modelDeployDtoFilter 一对多从表过滤对象。
* @param orderParam 排序参数。
* @param pageParam 分页参数。
* @return 应答结果对象,包含查询结果集。
*/
@PostMapping("/list")
public ResponseResult<MyPageData<ModelManageVo>> list(
@MyRequestBody ModelManageDto modelManageDtoFilter,
@MyRequestBody ModelVersionDto modelVersionDtoFilter,
@MyRequestBody ModelTaskDto modelTaskDtoFilter,
@MyRequestBody ModelDeployDto modelDeployDtoFilter,
@MyRequestBody MyOrderParam orderParam,
@MyRequestBody MyPageParam pageParam) {
if (pageParam != null) {
PageMethod.startPage(pageParam.getPageNum(), pageParam.getPageSize());
}
ModelManage modelManageFilter = MyModelUtil.copyTo(modelManageDtoFilter, ModelManage.class);
ModelVersion modelVersionFilter = MyModelUtil.copyTo(modelVersionDtoFilter, ModelVersion.class);
ModelTask modelTaskFilter = MyModelUtil.copyTo(modelTaskDtoFilter, ModelTask.class);
ModelDeploy modelDeployFilter = MyModelUtil.copyTo(modelDeployDtoFilter, ModelDeploy.class);
String orderBy = MyOrderParam.buildOrderBy(orderParam, ModelManage.class);
List<ModelManage> modelManageList =
modelManageService.getModelManageListWithRelation(modelManageFilter, modelVersionFilter, modelTaskFilter, modelDeployFilter, orderBy);
return ResponseResult.success(MyPageUtil.makeResponseData(modelManageList, ModelManage.INSTANCE));
}
/**
* 查看指定模型管理对象详情。
*
* @param modelId 指定对象主键Id。
* @return 应答结果对象,包含对象详情。
*/
@GetMapping("/view")
public ResponseResult<ModelManageVo> view(@RequestParam Long modelId) {
ModelManage modelManage = modelManageService.getByIdWithRelation(modelId, MyRelationParam.full());
if (modelManage == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
ModelManageVo modelManageVo = ModelManage.INSTANCE.fromModel(modelManage);
return ResponseResult.success(modelManageVo);
}
private ResponseResult<Tuple2<ModelManage, JSONObject>> doBusinessDataVerifyAndConvert(
ModelManageDto modelManageDto,
boolean forUpdate,
List<ModelVersionDto> modelVersionDtoList) {
ErrorCodeEnum errorCode = ErrorCodeEnum.DATA_VALIDATED_FAILED;
String errorMessage = MyCommonUtil.getModelValidationError(modelManageDto, false);
if (errorMessage != null) {
return ResponseResult.error(errorCode, errorMessage);
}
errorMessage = MyCommonUtil.getModelValidationError(modelVersionDtoList);
if (errorMessage != null) {
return ResponseResult.error(errorCode, "参数 [modelVersionDtoList] " + errorMessage);
}
// 全部关联从表数据的验证和转换
JSONObject relationData = new JSONObject();
CallResult verifyResult;
// 下面是输入参数中,主表关联数据的验证。
ModelManage modelManage = MyModelUtil.copyTo(modelManageDto, ModelManage.class);
ModelManage originalData;
if (forUpdate && modelManage != null) {
originalData = modelManageService.getById(modelManage.getModelId());
if (originalData == null) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
}
relationData.put("originalData", originalData);
}
// 处理主表的一对多关联 [ModelVersion]
List<ModelVersion> modelVersionList = MyModelUtil.copyCollectionTo(modelVersionDtoList, ModelVersion.class);
verifyResult = modelVersionService.verifyRelatedData(modelVersionList);
if (!verifyResult.isSuccess()) {
return ResponseResult.errorFrom(verifyResult);
}
relationData.put("modelVersionList", modelVersionList);
return ResponseResult.success(new Tuple2<>(modelManage, relationData));
}
private ResponseResult<Void> doDelete(Long modelId) {
String errorMessage;
// 验证关联Id的数据合法性
ModelManage originalModelManage = modelManageService.getById(modelId);
if (originalModelManage == null) {
// NOTE: 修改下面方括号中的话述
errorMessage = "数据验证失败,当前 [对象] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
if (!modelManageService.remove(modelId)) {
errorMessage = "数据操作失败,删除的对象不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
}
return ResponseResult.success();
}
}
...@@ -49,6 +49,11 @@ public class ModelTaskController { ...@@ -49,6 +49,11 @@ public class ModelTaskController {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
} }
ModelTask modelTask = MyModelUtil.copyTo(modelTaskDto, ModelTask.class); ModelTask modelTask = MyModelUtil.copyTo(modelTaskDto, ModelTask.class);
// 验证关联Id的数据合法性
CallResult callResult = modelTaskService.verifyRelatedData(modelTask, null);
if (!callResult.isSuccess()) {
return ResponseResult.errorFrom(callResult);
}
modelTask = modelTaskService.saveNew(modelTask); modelTask = modelTaskService.saveNew(modelTask);
return ResponseResult.success(modelTask.getTaskId()); return ResponseResult.success(modelTask.getTaskId());
} }
...@@ -73,6 +78,11 @@ public class ModelTaskController { ...@@ -73,6 +78,11 @@ public class ModelTaskController {
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
} }
// 验证关联Id的数据合法性
CallResult callResult = modelTaskService.verifyRelatedData(modelTask, originalModelTask);
if (!callResult.isSuccess()) {
return ResponseResult.errorFrom(callResult);
}
if (!modelTaskService.update(modelTask, originalModelTask)) { if (!modelTaskService.update(modelTask, originalModelTask)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
} }
......
...@@ -49,6 +49,11 @@ public class ModelVersionController { ...@@ -49,6 +49,11 @@ public class ModelVersionController {
return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage); return ResponseResult.error(ErrorCodeEnum.DATA_VALIDATED_FAILED, errorMessage);
} }
ModelVersion modelVersion = MyModelUtil.copyTo(modelVersionDto, ModelVersion.class); ModelVersion modelVersion = MyModelUtil.copyTo(modelVersionDto, ModelVersion.class);
// 验证关联Id的数据合法性
CallResult callResult = modelVersionService.verifyRelatedData(modelVersion, null);
if (!callResult.isSuccess()) {
return ResponseResult.errorFrom(callResult);
}
modelVersion = modelVersionService.saveNew(modelVersion); modelVersion = modelVersionService.saveNew(modelVersion);
return ResponseResult.success(modelVersion.getVersionId()); return ResponseResult.success(modelVersion.getVersionId());
} }
...@@ -73,6 +78,11 @@ public class ModelVersionController { ...@@ -73,6 +78,11 @@ public class ModelVersionController {
errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!"; errorMessage = "数据验证失败,当前 [数据] 并不存在,请刷新后重试!";
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage); return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST, errorMessage);
} }
// 验证关联Id的数据合法性
CallResult callResult = modelVersionService.verifyRelatedData(modelVersion, originalModelVersion);
if (!callResult.isSuccess()) {
return ResponseResult.errorFrom(callResult);
}
if (!modelVersionService.update(modelVersion, originalModelVersion)) { if (!modelVersionService.update(modelVersion, originalModelVersion)) {
return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST); return ResponseResult.error(ErrorCodeEnum.DATA_NOT_EXIST);
} }
......
package com.yice.webadmin.app.dao;
import com.yice.common.core.base.dao.BaseDaoMapper;
import com.yice.webadmin.app.model.ModelManage;
import com.yice.webadmin.app.model.ModelVersion;
import com.yice.webadmin.app.model.ModelTask;
import com.yice.webadmin.app.model.ModelDeploy;
import org.apache.ibatis.annotations.Param;
import java.util.*;
/**
* 模型管理数据操作访问接口。
*
* @author linking
* @date 2023-04-13
*/
public interface ModelManageMapper extends BaseDaoMapper<ModelManage> {
/**
* 批量插入对象列表。
*
* @param modelManageList 新增对象列表。
*/
void insertList(List<ModelManage> modelManageList);
/**
* 获取过滤后的对象列表。
*
* @param modelManageFilter 主表过滤对象。
* @param orderBy 排序字符串,order by从句的参数。
* @return 对象列表。
*/
List<ModelManage> getModelManageList(
@Param("modelManageFilter") ModelManage modelManageFilter, @Param("orderBy") String orderBy);
/**
* 获取过滤后的对象列表。同时支持基于一对一从表字段的过滤条件。
*
* @param modelManageFilter 主表过滤对象。
* @param modelVersionFilter 一对多从表过滤对象。
* @param modelTaskFilter 一对多从表过滤对象。
* @param modelDeployFilter 一对多从表过滤对象。
* @param orderBy 排序字符串,order by从句的参数。
* @return 对象列表。
*/
List<ModelManage> getModelManageListEx(
@Param("modelManageFilter") ModelManage modelManageFilter,
@Param("modelVersionFilter") ModelVersion modelVersionFilter,
@Param("modelTaskFilter") ModelTask modelTaskFilter,
@Param("modelDeployFilter") ModelDeploy modelDeployFilter,
@Param("orderBy") String orderBy);
}
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<mapper namespace="com.yice.webadmin.app.dao.DatasetVersionMapper"> <mapper namespace="com.yice.webadmin.app.dao.DatasetVersionMapper">
<resultMap id="BaseResultMap" type="com.yice.webadmin.app.model.DatasetVersion"> <resultMap id="BaseResultMap" type="com.yice.webadmin.app.model.DatasetVersion">
<id column="version_id" jdbcType="BIGINT" property="versionId"/> <id column="version_id" jdbcType="BIGINT" property="versionId"/>
<result column="dataset_version" jdbcType="VARCHAR" property="datasetVersion"/> <result column="dataset_version" jdbcType="TINYINT" property="datasetVersion"/>
<result column="input_status" jdbcType="TINYINT" property="inputStatus"/> <result column="input_status" jdbcType="TINYINT" property="inputStatus"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/> <result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/> <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
...@@ -17,6 +17,11 @@ ...@@ -17,6 +17,11 @@
<result column="release_status" jdbcType="TINYINT" property="releaseStatus"/> <result column="release_status" jdbcType="TINYINT" property="releaseStatus"/>
<result column="mark_progress" jdbcType="TINYINT" property="markProgress"/> <result column="mark_progress" jdbcType="TINYINT" property="markProgress"/>
<result column="data_volume" jdbcType="BIGINT" property="dataVolume"/> <result column="data_volume" jdbcType="BIGINT" property="dataVolume"/>
<result column="dimension_type" jdbcType="TINYINT" property="dimensionType"/>
<result column="template" jdbcType="TINYINT" property="template"/>
<result column="is_inherit" jdbcType="TINYINT" property="isInherit"/>
<result column="his_version" jdbcType="TINYINT" property="hisVersion"/>
<result column="file_url" jdbcType="VARCHAR" property="fileUrl"/>
</resultMap> </resultMap>
<insert id="insertList"> <insert id="insertList">
...@@ -35,7 +40,11 @@ ...@@ -35,7 +40,11 @@
enhance_status, enhance_status,
release_status, release_status,
mark_progress, mark_progress,
data_volume) data_volume,
dimension_type,
template,
is_inherit,
his_version)
VALUES VALUES
<foreach collection="list" index="index" item="item" separator="," > <foreach collection="list" index="index" item="item" separator="," >
(#{item.versionId}, (#{item.versionId},
...@@ -52,7 +61,12 @@ ...@@ -52,7 +61,12 @@
#{item.enhanceStatus}, #{item.enhanceStatus},
#{item.releaseStatus}, #{item.releaseStatus},
#{item.markProgress}, #{item.markProgress},
#{item.dataVolume}) #{item.dataVolume},
#{item.dimensionType},
#{item.template},
#{item.isInherit},
#{item.hisVersion}
)
</foreach> </foreach>
</insert> </insert>
......
...@@ -11,6 +11,10 @@ ...@@ -11,6 +11,10 @@
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/> <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/> <result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="model_version" jdbcType="TINYINT" property="modelVersion"/>
<result column="service_id" jdbcType="BIGINT" property="serviceId"/>
<result column="service_name" jdbcType="VARCHAR" property="serviceName"/>
<result column="service_version" jdbcType="TINYINT" property="serviceVersion"/>
</resultMap> </resultMap>
<insert id="insertList"> <insert id="insertList">
...@@ -23,7 +27,11 @@ ...@@ -23,7 +27,11 @@
create_user_id, create_user_id,
create_time, create_time,
update_user_id, update_user_id,
update_time) update_time,
model_version,
service_id,
service_name,
service_version)
VALUES VALUES
<foreach collection="list" index="index" item="item" separator="," > <foreach collection="list" index="index" item="item" separator="," >
(#{item.deployId}, (#{item.deployId},
...@@ -34,7 +42,11 @@ ...@@ -34,7 +42,11 @@
#{item.createUserId}, #{item.createUserId},
#{item.createTime}, #{item.createTime},
#{item.updateUserId}, #{item.updateUserId},
#{item.updateTime}) #{item.updateTime},
#{item.modelVersion},
#{item.serviceId},
#{item.serviceName},
#{item.serviceVersion})
</foreach> </foreach>
</insert> </insert>
......
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yice.webadmin.app.dao.ModelManageMapper">
<resultMap id="BaseResultMap" type="com.yice.webadmin.app.model.ModelManage">
<id column="model_id" jdbcType="BIGINT" property="modelId"/>
<result column="model_name" jdbcType="VARCHAR" property="modelName"/>
<result column="model_type" jdbcType="TINYINT" property="modelType"/>
<result column="model_describe" jdbcType="VARCHAR" property="modelDescribe"/>
<result column="version_count" jdbcType="TINYINT" property="versionCount"/>
<result column="business_label" jdbcType="VARCHAR" property="businessLabel"/>
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="is_base_model" jdbcType="TINYINT" property="isBaseModel"/>
<result column="last_version_source" jdbcType="VARCHAR" property="lastVersionSource"/>
</resultMap>
<insert id="insertList">
INSERT INTO lmp_model_manage
(model_id,
model_name,
model_type,
model_describe,
version_count,
business_label,
create_time,
create_user_id,
update_user_id,
update_time,
is_base_model,
last_version_source)
VALUES
<foreach collection="list" index="index" item="item" separator="," >
(#{item.modelId},
#{item.modelName},
#{item.modelType},
#{item.modelDescribe},
#{item.versionCount},
#{item.businessLabel},
#{item.createTime},
#{item.createUserId},
#{item.updateUserId},
#{item.updateTime},
#{item.isBaseModel},
#{item.lastVersionSource})
</foreach>
</insert>
<!-- 如果有逻辑删除字段过滤,请写到这里 -->
<sql id="filterRef">
<!-- 这里必须加上全包名,否则当filterRef被其他Mapper.xml包含引用的时候,就会调用Mapper.xml中的该SQL片段 -->
<include refid="com.yice.webadmin.app.dao.ModelManageMapper.inputFilterRef"/>
</sql>
<!-- 这里仅包含调用接口输入的主表过滤条件 -->
<sql id="inputFilterRef">
<if test="modelManageFilter != null">
<if test="modelManageFilter.searchString != null and modelManageFilter.searchString != ''">
<bind name = "safeModelManageSearchString" value = "'%' + modelManageFilter.searchString + '%'" />
AND CONCAT(IFNULL(lmp_model_manage.model_name,''), IFNULL(lmp_model_manage.business_label,'')) LIKE #{safeModelManageSearchString}
</if>
</if>
</sql>
<select id="getModelManageList" resultMap="BaseResultMap" parameterType="com.yice.webadmin.app.model.ModelManage">
SELECT * FROM lmp_model_manage
<where>
<include refid="filterRef"/>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
<!-- 支持基于一对一或者一对多从表字段过滤的SQL_ID -->
<select id="getModelManageListEx" resultMap="BaseResultMap" >
SELECT
lmp_model_manage.*
FROM
lmp_model_manage
<where>
<include refid="filterRef"/>
<if test="modelVersionFilter != null">
AND EXISTS (SELECT * FROM lmp_model_version
<where>
lmp_model_manage.model_id = lmp_model_version.model_id
<include refid="com.yice.webadmin.app.dao.ModelVersionMapper.filterRef"/>
</where>)
</if>
<if test="modelTaskFilter != null">
AND EXISTS (SELECT * FROM lmp_model_task
<where>
lmp_model_manage.model_id = lmp_model_task.model_id
<include refid="com.yice.webadmin.app.dao.ModelTaskMapper.filterRef"/>
</where>)
</if>
<if test="modelDeployFilter != null">
AND EXISTS (SELECT * FROM lmp_model_deploy
<where>
lmp_model_manage.model_id = lmp_model_deploy.model_id
<include refid="com.yice.webadmin.app.dao.ModelDeployMapper.filterRef"/>
</where>)
</if>
</where>
<if test="orderBy != null and orderBy != ''">
ORDER BY ${orderBy}
</if>
</select>
</mapper>
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
<result column="create_user_id" jdbcType="BIGINT" property="createUserId"/> <result column="create_user_id" jdbcType="BIGINT" property="createUserId"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/> <result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="model_version" jdbcType="TINYINT" property="modelVersion"/>
</resultMap> </resultMap>
<insert id="insertList"> <insert id="insertList">
...@@ -27,7 +28,8 @@ ...@@ -27,7 +28,8 @@
complete_time, complete_time,
create_user_id, create_user_id,
update_user_id, update_user_id,
update_time) update_time,
model_version)
VALUES VALUES
<foreach collection="list" index="index" item="item" separator="," > <foreach collection="list" index="index" item="item" separator="," >
(#{item.taskId}, (#{item.taskId},
...@@ -40,7 +42,8 @@ ...@@ -40,7 +42,8 @@
#{item.completeTime}, #{item.completeTime},
#{item.createUserId}, #{item.createUserId},
#{item.updateUserId}, #{item.updateUserId},
#{item.updateTime}) #{item.updateTime},
#{item.modelVersion})
</foreach> </foreach>
</insert> </insert>
......
...@@ -14,6 +14,15 @@ ...@@ -14,6 +14,15 @@
<result column="create_time" jdbcType="TIMESTAMP" property="createTime"/> <result column="create_time" jdbcType="TIMESTAMP" property="createTime"/>
<result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/> <result column="update_user_id" jdbcType="BIGINT" property="updateUserId"/>
<result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/> <result column="update_time" jdbcType="TIMESTAMP" property="updateTime"/>
<result column="model_version" jdbcType="TINYINT" property="modelVersion"/>
<result column="status" jdbcType="TINYINT" property="status"/>
<result column="version_source" jdbcType="VARCHAR" property="versionSource"/>
<result column="base_model" jdbcType="VARCHAR" property="baseModel"/>
<result column="business_label" jdbcType="VARCHAR" property="businessLabel"/>
<result column="base_id" jdbcType="BIGINT" property="baseId"/>
<result column="model_training_method" jdbcType="VARCHAR" property="modelTrainingMethod"/>
<result column="run_name" jdbcType="VARCHAR" property="runName"/>
<result column="training_task" jdbcType="VARCHAR" property="trainingTask"/>
</resultMap> </resultMap>
<insert id="insertList"> <insert id="insertList">
...@@ -29,7 +38,19 @@ ...@@ -29,7 +38,19 @@
create_user_id, create_user_id,
create_time, create_time,
update_user_id, update_user_id,
update_time) update_time,
model_version,
status,
version_source,
base_model,
business_label,
base_id,
model_training_method,
run_name,
training_task,
model_url,
is_compress
)
VALUES VALUES
<foreach collection="list" index="index" item="item" separator="," > <foreach collection="list" index="index" item="item" separator="," >
(#{item.versionId}, (#{item.versionId},
...@@ -43,7 +64,18 @@ ...@@ -43,7 +64,18 @@
#{item.createUserId}, #{item.createUserId},
#{item.createTime}, #{item.createTime},
#{item.updateUserId}, #{item.updateUserId},
#{item.updateTime}) #{item.updateTime},
#{item.modelVersion},
#{item.status},
#{item.versionSource},
#{item.baseModel},
#{item.businessLabel},
#{item.baseId},
#{item.modelTrainingMethod},
#{item.runName},
#{item.trainingTask},
#{item.modelUrl},
#{item.isCompress})
</foreach> </foreach>
</insert> </insert>
......
...@@ -25,11 +25,12 @@ public class DatasetVersionDto { ...@@ -25,11 +25,12 @@ public class DatasetVersionDto {
@NotNull(message = "数据验证失败,版本ID不能为空!", groups = {UpdateGroup.class}) @NotNull(message = "数据验证失败,版本ID不能为空!", groups = {UpdateGroup.class})
private Long versionId; private Long versionId;
/** /**
* 版本。 * 版本。
*/ */
@ApiModelProperty(value = "版本") @ApiModelProperty(value = "版本")
private String datasetVersion; private Integer datasetVersion;
/** /**
* 导入状态。 * 导入状态。
...@@ -79,4 +80,34 @@ public class DatasetVersionDto { ...@@ -79,4 +80,34 @@ public class DatasetVersionDto {
*/ */
@ApiModelProperty(value = "数据量") @ApiModelProperty(value = "数据量")
private Long dataVolume; private Long dataVolume;
/**
* 标注类型。
*/
@ApiModelProperty(value = "标注类型")
private Integer dimensionType;
/**
* 模板。
*/
@ApiModelProperty(value = "模板")
private Integer template;
/**
* 是否继承历史版本。
*/
@ApiModelProperty(value = "是否继承历史版本")
private Integer isInherit;
/**
* 历史版本。
*/
@ApiModelProperty(value = "历史版本")
private Integer hisVersion;
/**
* 文件地址。
*/
@ApiModelProperty(value = "文件地址")
private String fileUrl;
} }
...@@ -48,4 +48,28 @@ public class ModelDeployDto { ...@@ -48,4 +48,28 @@ public class ModelDeployDto {
*/ */
@ApiModelProperty(value = "部署状态") @ApiModelProperty(value = "部署状态")
private Integer deployStatus; private Integer deployStatus;
/**
* 模型版本号。
*/
@ApiModelProperty(value = "模型版本号")
private Integer modelVersion;
/**
* 服务ID。
*/
@ApiModelProperty(value = "服务ID")
private Long serviceId;
/**
* 服务名称。
*/
@ApiModelProperty(value = "服务名称")
private String serviceName;
/**
* 服务版本。
*/
@ApiModelProperty(value = "服务版本")
private Integer serviceVersion;
} }
package com.yice.webadmin.app.dto;
import com.yice.common.core.validator.UpdateGroup;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.*;
/**
* ModelManageDto对象。
*
* @author linking
* @date 2023-04-13
*/
@ApiModel("ModelManageDto对象")
@Data
public class ModelManageDto {
/**
* 模型ID。
*/
@ApiModelProperty(value = "模型ID", required = true)
@NotNull(message = "数据验证失败,模型ID不能为空!", groups = {UpdateGroup.class})
private Long modelId;
/**
* 模型名称。
*/
@ApiModelProperty(value = "模型名称")
private String modelName;
/**
* 模型类型。
*/
@ApiModelProperty(value = "模型类型")
private Integer modelType;
/**
* 模型描述。
*/
@ApiModelProperty(value = "模型描述")
private String modelDescribe;
/**
* 版本数量。
*/
@ApiModelProperty(value = "版本数量")
private Integer versionCount;
/**
* 业务标签。
*/
@ApiModelProperty(value = "业务标签")
private String businessLabel;
/**
* 是否为基础模型。
*/
@ApiModelProperty(value = "是否为基础模型")
private Integer isBaseModel;
/**
* 最新版本来源。
*/
@ApiModelProperty(value = "最新版本来源")
private String lastVersionSource;
/**
* model_name / business_label LIKE搜索字符串。
*/
@ApiModelProperty(value = "LIKE模糊搜索字符串")
private String searchString;
}
...@@ -62,4 +62,10 @@ public class ModelTaskDto { ...@@ -62,4 +62,10 @@ public class ModelTaskDto {
*/ */
@ApiModelProperty(value = "完成时间") @ApiModelProperty(value = "完成时间")
private Date completeTime; private Date completeTime;
/**
* 模型版本号。
*/
@ApiModelProperty(value = "模型版本号")
private Integer modelVersion;
} }
...@@ -66,4 +66,64 @@ public class ModelVersionDto { ...@@ -66,4 +66,64 @@ public class ModelVersionDto {
*/ */
@ApiModelProperty(value = "版权信息") @ApiModelProperty(value = "版权信息")
private String copyright; private String copyright;
/**
* 模型版本号。
*/
@ApiModelProperty(value = "模型版本号")
private Integer modelVersion;
/**
* 版本状态。
*/
@ApiModelProperty(value = "版本状态")
private Integer status;
/**
* 版本来源。
*/
@ApiModelProperty(value = "版本来源")
private String versionSource;
/**
* 基础模型。
*/
@ApiModelProperty(value = "基础模型")
private String baseModel;
/**
* 业务标签。
*/
@ApiModelProperty(value = "业务标签")
private String businessLabel;
/**
* 基础模型ID。
*/
@ApiModelProperty(value = "基础模型ID")
private Long baseId;
/**
* 模型训练方式。
*/
@ApiModelProperty(value = "模型训练方式")
private String modelTrainingMethod;
/**
* 运行名称。
*/
@ApiModelProperty(value = "运行名称")
private String runName;
/**
* 训练任务。
*/
@ApiModelProperty(value = "训练任务")
private String trainingTask;
/**
* 模型地址。
*/
@ApiModelProperty(value = "模型地址")
private String modelUrl;
} }
...@@ -30,7 +30,7 @@ public class DatasetVersion extends BaseModel { ...@@ -30,7 +30,7 @@ public class DatasetVersion extends BaseModel {
/** /**
* 版本。 * 版本。
*/ */
private String datasetVersion; private Integer datasetVersion;
/** /**
* 导入状态。 * 导入状态。
...@@ -77,6 +77,29 @@ public class DatasetVersion extends BaseModel { ...@@ -77,6 +77,29 @@ public class DatasetVersion extends BaseModel {
* 数据量。 * 数据量。
*/ */
private Long dataVolume; private Long dataVolume;
/**
* 标注类型。
*/
private Integer dimensionType;
/**
* 模板。
*/
private Integer template;
/**
* 是否继承历史版本。
*/
private Integer isInherit;
/**
* 历史版本。
*/
private Integer hisVersion;
/**
* 文件地址。
*/
private String fileUrl;
@RelationOneToOne( @RelationOneToOne(
masterIdField = "versionId", masterIdField = "versionId",
......
...@@ -46,6 +46,26 @@ public class ModelDeploy extends BaseModel { ...@@ -46,6 +46,26 @@ public class ModelDeploy extends BaseModel {
*/ */
private Integer deployStatus; private Integer deployStatus;
/**
* 模型版本号。
*/
private Integer modelVersion;
/**
* 服务ID。
*/
private Long serviceId;
/**
* 服务名称。
*/
private String serviceName;
/**
* 服务版本。
*/
private Integer serviceVersion;
@Mapper @Mapper
public interface ModelDeployModelMapper extends BaseModelMapper<ModelDeployVo, ModelDeploy> { public interface ModelDeployModelMapper extends BaseModelMapper<ModelDeployVo, ModelDeploy> {
} }
......
package com.yice.webadmin.app.model;
import com.baomidou.mybatisplus.annotation.*;
import com.yice.common.core.constant.AggregationType;
import com.yice.common.core.util.MyCommonUtil;
import com.yice.common.core.annotation.*;
import com.yice.common.core.base.model.BaseModel;
import com.yice.common.core.base.mapper.BaseModelMapper;
import com.yice.webadmin.app.vo.ModelManageVo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.mapstruct.*;
import org.mapstruct.factory.Mappers;
import java.util.List;
/**
* ModelManage实体对象。
*
* @author linking
* @date 2023-04-13
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName(value = "lmp_model_manage")
public class ModelManage extends BaseModel {
/**
* 模型ID。
*/
@TableId(value = "model_id")
private Long modelId;
/**
* 模型名称。
*/
private String modelName;
/**
* 模型类型。
*/
private Integer modelType;
/**
* 模型描述。
*/
private String modelDescribe;
/**
* 版本数量。
*/
/**
* 版本数量 (一对多聚合计算字段)。
*/
@RelationOneToManyAggregation(
masterIdField = "modelId",
slaveModelClass = ModelVersion.class,
slaveIdField = "modelId",
aggregationType = AggregationType.COUNT,
aggregationField = "modelId")
@TableField(exist = false)
private Integer versionCount;
/**
* 业务标签。
*/
private String businessLabel;
/**
* 是否为基础模型。
*/
private Integer isBaseModel;
/**
* 最新版本来源。
*/
private String lastVersionSource;
/**
* model_name / business_label LIKE搜索字符串。
*/
@TableField(exist = false)
private String searchString;
public void setSearchString(String searchString) {
this.searchString = MyCommonUtil.replaceSqlWildcard(searchString);
}
/**
* ModelVersion 的一对多关联表数据对象。
* 通常在一对多的关联中,我们基于从表数据过滤主表数据,此时需要先对从表数据进行嵌套子查询过滤,并将从表过滤数据列表集成到该字段。
*/
@RelationOneToMany(
masterIdField = "modelId",
slaveModelClass = ModelVersion.class,
slaveIdField = "modelId")
@TableField(exist = false)
private List<ModelVersion> modelVersionList;
/**
* ModelTask 的一对多关联表数据对象。
* 通常在一对多的关联中,我们基于从表数据过滤主表数据,此时需要先对从表数据进行嵌套子查询过滤,并将从表过滤数据列表集成到该字段。
*/
@RelationOneToMany(
masterIdField = "modelId",
slaveModelClass = ModelTask.class,
slaveIdField = "modelId")
@TableField(exist = false)
private List<ModelTask> modelTaskList;
/**
* ModelDeploy 的一对多关联表数据对象。
* 通常在一对多的关联中,我们基于从表数据过滤主表数据,此时需要先对从表数据进行嵌套子查询过滤,并将从表过滤数据列表集成到该字段。
*/
@RelationOneToMany(
masterIdField = "modelId",
slaveModelClass = ModelDeploy.class,
slaveIdField = "modelId")
@TableField(exist = false)
private List<ModelDeploy> modelDeployList;
@Mapper
public interface ModelManageModelMapper extends BaseModelMapper<ModelManageVo, ModelManage> {
/**
* 转换Vo对象到实体对象。
*
* @param modelManageVo 域对象。
* @return 实体对象。
*/
@Mapping(target = "modelVersionList", expression = "java(mapToBean(modelManageVo.getModelVersionList(), com.yice.webadmin.app.model.ModelVersion.class))")
@Mapping(target = "modelTaskList", expression = "java(mapToBean(modelManageVo.getModelTaskList(), com.yice.webadmin.app.model.ModelTask.class))")
@Mapping(target = "modelDeployList", expression = "java(mapToBean(modelManageVo.getModelDeployList(), com.yice.webadmin.app.model.ModelDeploy.class))")
@Override
ModelManage toModel(ModelManageVo modelManageVo);
/**
* 转换实体对象到VO对象。
*
* @param modelManage 实体对象。
* @return 域对象。
*/
@Mapping(target = "modelVersionList", expression = "java(beanToMap(modelManage.getModelVersionList(), false))")
@Mapping(target = "modelTaskList", expression = "java(beanToMap(modelManage.getModelTaskList(), false))")
@Mapping(target = "modelDeployList", expression = "java(beanToMap(modelManage.getModelDeployList(), false))")
@Override
ModelManageVo fromModel(ModelManage modelManage);
}
public static final ModelManageModelMapper INSTANCE = Mappers.getMapper(ModelManageModelMapper.class);
}
...@@ -58,6 +58,11 @@ public class ModelTask extends BaseModel { ...@@ -58,6 +58,11 @@ public class ModelTask extends BaseModel {
*/ */
private Date completeTime; private Date completeTime;
/**
* 模型版本号。
*/
private Integer modelVersion;
@Mapper @Mapper
public interface ModelTaskModelMapper extends BaseModelMapper<ModelTaskVo, ModelTask> { public interface ModelTaskModelMapper extends BaseModelMapper<ModelTaskVo, ModelTask> {
} }
......
package com.yice.webadmin.app.model; package com.yice.webadmin.app.model;
import com.baomidou.mybatisplus.annotation.*; import com.baomidou.mybatisplus.annotation.*;
import com.yice.common.core.annotation.*;
import com.yice.common.core.base.model.BaseModel; import com.yice.common.core.base.model.BaseModel;
import com.yice.common.core.base.mapper.BaseModelMapper; import com.yice.common.core.base.mapper.BaseModelMapper;
import com.yice.webadmin.app.vo.ModelVersionVo; import com.yice.webadmin.app.vo.ModelVersionVo;
...@@ -61,8 +62,89 @@ public class ModelVersion extends BaseModel { ...@@ -61,8 +62,89 @@ public class ModelVersion extends BaseModel {
*/ */
private String copyright; private String copyright;
/**
* 模型版本号。
*/
private Integer modelVersion;
/**
* 版本状态。
*/
private Integer status;
/**
* 版本来源。
*/
private String versionSource;
/**
* 基础模型。
*/
private String baseModel;
/**
* 业务标签。
*/
private String businessLabel;
/**
* 基础模型ID。
*/
private Long baseId;
/**
* 模型训练方式。
*/
private String modelTrainingMethod;
/**
* 运行名称。
*/
private String runName;
/**
* 训练任务。
*/
private String trainingTask;
/**
* 模型地址。
*/
private String modelUrl;
/**
* 是否被压缩。
*/
private String isCompress;
@RelationOneToOne(
masterIdField = "modelId",
slaveModelClass = ModelManage.class,
slaveIdField = "modelId")
@TableField(exist = false)
private ModelManage modelManage;
@Mapper @Mapper
public interface ModelVersionModelMapper extends BaseModelMapper<ModelVersionVo, ModelVersion> { public interface ModelVersionModelMapper extends BaseModelMapper<ModelVersionVo, ModelVersion> {
/**
* 转换Vo对象到实体对象。
*
* @param modelVersionVo 域对象。
* @return 实体对象。
*/
@Mapping(target = "modelManage", expression = "java(mapToBean(modelVersionVo.getModelManage(), com.yice.webadmin.app.model.ModelManage.class))")
@Override
ModelVersion toModel(ModelVersionVo modelVersionVo);
/**
* 转换实体对象到VO对象。
*
* @param modelVersion 实体对象。
* @return 域对象。
*/
@Mapping(target = "modelManage", expression = "java(beanToMap(modelVersion.getModelManage(), false))")
@Override
ModelVersionVo fromModel(ModelVersion modelVersion);
} }
public static final ModelVersionModelMapper INSTANCE = Mappers.getMapper(ModelVersionModelMapper.class); public static final ModelVersionModelMapper INSTANCE = Mappers.getMapper(ModelVersionModelMapper.class);
} }
...@@ -28,6 +28,13 @@ public interface DatasetDetailService extends IBaseService<DatasetDetail, Long> ...@@ -28,6 +28,13 @@ public interface DatasetDetailService extends IBaseService<DatasetDetail, Long>
*/ */
void saveNewBatch(List<DatasetDetail> datasetDetailList); void saveNewBatch(List<DatasetDetail> datasetDetailList);
/**
* 利用数据库的insertList语法,批量插入对象列表。通常适用于更大的插入数据量,如批量导入。
*
* @param datasetDetailList 新增对象列表。
* @param batchSize 每批插入的数量。如果该值小于等于0,则使用缺省值10000。
*/
void saveNewBatch(List<DatasetDetail> datasetDetailList, int batchSize);
/** /**
* 更新数据对象。 * 更新数据对象。
* *
......
...@@ -66,4 +66,6 @@ public interface DatasetManageService extends IBaseService<DatasetManage, Long> ...@@ -66,4 +66,6 @@ public interface DatasetManageService extends IBaseService<DatasetManage, Long>
* @return 查询结果集。 * @return 查询结果集。
*/ */
List<DatasetManage> getDatasetManageListWithRelation(DatasetManage filter, DatasetVersion datasetVersionFilter, String orderBy); List<DatasetManage> getDatasetManageListWithRelation(DatasetManage filter, DatasetVersion datasetVersionFilter, String orderBy);
DatasetManage saveAndCreateVersion(DatasetManage datasetManage);
} }
...@@ -45,6 +45,14 @@ public interface ModelDeployService extends IBaseService<ModelDeploy, Long> { ...@@ -45,6 +45,14 @@ public interface ModelDeployService extends IBaseService<ModelDeploy, Long> {
*/ */
boolean remove(Long deployId); boolean remove(Long deployId);
/**
* 当前服务的支持表为从表,根据主表的关联Id,删除一对多的从表数据。
*
* @param modelId 从表关联字段。
* @return 删除数量。
*/
int removeByModelId(Long modelId);
/** /**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getModelDeployListWithRelation)方法。 * 如果需要同时获取关联数据,请移步(getModelDeployListWithRelation)方法。
......
package com.yice.webadmin.app.service;
import com.alibaba.fastjson.JSONObject;
import com.yice.webadmin.app.model.*;
import com.yice.common.core.base.service.IBaseService;
import java.util.*;
/**
* 模型管理数据操作服务接口。
*
* @author linking
* @date 2023-04-13
*/
public interface ModelManageService extends IBaseService<ModelManage, Long> {
/**
* 保存新增对象。
*
* @param modelManage 新增对象。
* @return 返回新增对象。
*/
ModelManage saveNew(ModelManage modelManage);
/**
* 利用数据库的insertList语法,批量插入对象列表。
*
* @param modelManageList 新增对象列表。
*/
void saveNewBatch(List<ModelManage> modelManageList);
/**
* 保存新增主表对象及关联对象。
*
* @param modelManage 新增主表对象。
* @param relationData 全部关联从表数据。
* @return 返回新增主表对象。
*/
ModelManage saveNewWithRelation(ModelManage modelManage, JSONObject relationData);
/**
* 更新数据对象。
*
* @param modelManage 更新的对象。
* @param originalModelManage 原有数据对象。
* @return 成功返回true,否则false。
*/
boolean update(ModelManage modelManage, ModelManage originalModelManage);
/**
* 删除指定数据。
*
* @param modelId 主键Id。
* @return 成功返回true,否则false。
*/
boolean remove(Long modelId);
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getModelManageListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<ModelManage> getModelManageList(ModelManage filter, String orderBy);
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
* 如果仅仅需要获取主表数据,请移步(getModelManageList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param modelVersionFilter 一对多从表过滤对象。
* @param modelTaskFilter 一对多从表过滤对象。
* @param modelDeployFilter 一对多从表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
List<ModelManage> getModelManageListWithRelation(ModelManage filter, ModelVersion modelVersionFilter, ModelTask modelTaskFilter, ModelDeploy modelDeployFilter, String orderBy);
ModelManage saveAndCreateVersion(ModelManage modelManage, ModelVersion modelVersion);
}
...@@ -45,6 +45,14 @@ public interface ModelTaskService extends IBaseService<ModelTask, Long> { ...@@ -45,6 +45,14 @@ public interface ModelTaskService extends IBaseService<ModelTask, Long> {
*/ */
boolean remove(Long taskId); boolean remove(Long taskId);
/**
* 当前服务的支持表为从表,根据主表的关联Id,删除一对多的从表数据。
*
* @param modelId 从表关联字段。
* @return 删除数量。
*/
int removeByModelId(Long modelId);
/** /**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getModelTaskListWithRelation)方法。 * 如果需要同时获取关联数据,请移步(getModelTaskListWithRelation)方法。
......
...@@ -45,6 +45,22 @@ public interface ModelVersionService extends IBaseService<ModelVersion, Long> { ...@@ -45,6 +45,22 @@ public interface ModelVersionService extends IBaseService<ModelVersion, Long> {
*/ */
boolean remove(Long versionId); boolean remove(Long versionId);
/**
* 当前服务的支持表为从表,根据主表的关联Id,删除一对多的从表数据。
*
* @param modelId 从表关联字段。
* @return 删除数量。
*/
int removeByModelId(Long modelId);
/**
* 批量更新一对多从表的数据。
*
* @param modelId 从表关联字段。
* @param dataList 本次批量更新的一对多从表数据。
*/
void updateBatchByModelId(Long modelId, List<ModelVersion> dataList);
/** /**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getModelVersionListWithRelation)方法。 * 如果需要同时获取关联数据,请移步(getModelVersionListWithRelation)方法。
......
...@@ -70,7 +70,30 @@ public class DatasetDetailServiceImpl extends BaseService<DatasetDetail, Long> i ...@@ -70,7 +70,30 @@ public class DatasetDetailServiceImpl extends BaseService<DatasetDetail, Long> i
datasetDetailMapper.insertList(datasetDetailList); datasetDetailMapper.insertList(datasetDetailList);
} }
} }
@Transactional(rollbackFor = Exception.class)
@Override
public void saveNewBatch(List<DatasetDetail> datasetDetailList, int batchSize) {
if (CollUtil.isEmpty(datasetDetailList)) {
return;
}
if (batchSize <= 0) {
batchSize = 10000;
}
int start = 0;
do {
int end = Math.min(datasetDetailList.size(), start + batchSize);
List<DatasetDetail> subList = datasetDetailList.subList(start, end);
// TODO 如果数据量过大,同时当前表中存在createTime或updateTime等字段,可以考虑在外部创建一次 new Date(),
// 然后传入buildDefaultValue,这样可以减少对象的创建次数,降低GC,提升效率。橙单之所以没有这样生成,是因为
// 有些业务场景下需要按照这两个日期字段排序,因此我们只是在这里给出优化建议。
subList.forEach(this::buildDefaultValue);
datasetDetailMapper.insertList(subList);
if (end == datasetDetailList.size()) {
break;
}
start += batchSize;
} while (true);
}
/** /**
* 更新数据对象。 * 更新数据对象。
* *
......
...@@ -122,22 +122,48 @@ public class DatasetManageServiceImpl extends BaseService<DatasetManage, Long> i ...@@ -122,22 +122,48 @@ public class DatasetManageServiceImpl extends BaseService<DatasetManage, Long> i
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。 * 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
* 如果仅仅需要获取主表数据,请移步(getDatasetManageList),以便获取更好的查询性能。 * 如果仅仅需要获取主表数据,请移步(getDatasetManageList),以便获取更好的查询性能。
* *
* @param filter 主表过滤对象。 * @param filter 主表过滤对象。
* @param datasetVersionFilter 一对多从表过滤对象。 * @param datasetVersionFilter 一对多从表过滤对象。
* @param orderBy 排序参数。 * @param orderBy 排序参数。
* @return 查询结果集。 * @return 查询结果集。
*/ */
@Override @Override
public List<DatasetManage> getDatasetManageListWithRelation(DatasetManage filter, DatasetVersion datasetVersionFilter, String orderBy) { public List<DatasetManage> getDatasetManageListWithRelation(DatasetManage filter, DatasetVersion datasetVersionFilter, String orderBy) {
List<DatasetManage> resultList = List<DatasetManage> resultList =
datasetManageMapper.getDatasetManageListEx(filter, datasetVersionFilter, orderBy); datasetManageMapper.getDatasetManageListEx(filter, datasetVersionFilter, orderBy);
// 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。 // 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。 // 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
int batchSize = resultList instanceof Page ? 0 : 1000; int batchSize = resultList instanceof Page ? 0 : 1000;
this.buildRelationForDataList(resultList, MyRelationParam.normal(), batchSize); this.buildRelationForDataList(resultList, MyRelationParam.full(), batchSize);
return resultList; return resultList;
} }
@Transactional
@Override
public DatasetManage saveAndCreateVersion(DatasetManage datasetManage) {
DatasetManage reDatasetManage = this.saveNew(datasetManage);
DatasetVersion datasetVersion = new DatasetVersion();
datasetVersion.setDatasetId(reDatasetManage.getDatasetId());
List<DatasetVersion> datasetVersions = this.datasetVersionService.getDatasetVersionList(datasetVersion, "dataset_version");
Integer version = 1;
if (datasetVersions != null && datasetVersions.size() != 0) {
version = datasetVersions.get(datasetVersions.size() - 1).getDatasetVersion() + 1;
}
datasetVersion.setDatasetVersion(version);
datasetVersion.setCleanStatus(0);
datasetVersion.setDataVolume(0L);
datasetVersion.setEnhanceStatus(0);
datasetVersion.setInputStatus(0);
datasetVersion.setMarkProgress(0);
datasetVersion.setOutputStatus(0);
datasetVersion.setReleaseStatus(0);
datasetVersion.setTemplate(datasetManage.getTemplate());
datasetVersion.setDimensionType(datasetManage.getDimensionType());
this.datasetVersionService.saveNew(datasetVersion);
return reDatasetManage;
}
private DatasetManage buildDefaultValue(DatasetManage datasetManage) { private DatasetManage buildDefaultValue(DatasetManage datasetManage) {
if (datasetManage.getDatasetId() == null) { if (datasetManage.getDatasetId() == null) {
datasetManage.setDatasetId(idGenerator.nextLongId()); datasetManage.setDatasetId(idGenerator.nextLongId());
......
package com.yice.webadmin.app.service.impl; package com.yice.webadmin.app.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.*;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yice.webadmin.app.service.*; import com.yice.webadmin.app.service.*;
import com.yice.webadmin.app.dao.*; import com.yice.webadmin.app.dao.*;
import com.yice.webadmin.app.model.*; import com.yice.webadmin.app.model.*;
import com.yice.common.core.base.dao.BaseDaoMapper; import com.yice.common.core.base.dao.BaseDaoMapper;
import com.yice.common.core.object.MyRelationParam; import com.yice.common.core.object.MyRelationParam;
import com.yice.common.core.object.CallResult;
import com.yice.common.core.base.service.BaseService; import com.yice.common.core.base.service.BaseService;
import com.yice.common.core.util.MyModelUtil; import com.yice.common.core.util.MyModelUtil;
import com.yice.common.sequence.wrapper.IdGeneratorWrapper; import com.yice.common.sequence.wrapper.IdGeneratorWrapper;
...@@ -31,6 +33,8 @@ public class ModelDeployServiceImpl extends BaseService<ModelDeploy, Long> imple ...@@ -31,6 +33,8 @@ public class ModelDeployServiceImpl extends BaseService<ModelDeploy, Long> imple
@Autowired @Autowired
private ModelDeployMapper modelDeployMapper; private ModelDeployMapper modelDeployMapper;
@Autowired @Autowired
private ModelManageService modelManageService;
@Autowired
private IdGeneratorWrapper idGenerator; private IdGeneratorWrapper idGenerator;
/** /**
...@@ -98,6 +102,20 @@ public class ModelDeployServiceImpl extends BaseService<ModelDeploy, Long> imple ...@@ -98,6 +102,20 @@ public class ModelDeployServiceImpl extends BaseService<ModelDeploy, Long> imple
return modelDeployMapper.deleteById(deployId) == 1; return modelDeployMapper.deleteById(deployId) == 1;
} }
/**
* 当前服务的支持表为从表,根据主表的关联Id,删除一对多的从表数据。
*
* @param modelId 从表关联字段。
* @return 删除数量。
*/
@Transactional(rollbackFor = Exception.class)
@Override
public int removeByModelId(Long modelId) {
ModelDeploy deletedObject = new ModelDeploy();
deletedObject.setModelId(modelId);
return modelDeployMapper.delete(new QueryWrapper<>(deletedObject));
}
/** /**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getModelDeployListWithRelation)方法。 * 如果需要同时获取关联数据,请移步(getModelDeployListWithRelation)方法。
...@@ -130,6 +148,24 @@ public class ModelDeployServiceImpl extends BaseService<ModelDeploy, Long> imple ...@@ -130,6 +148,24 @@ public class ModelDeployServiceImpl extends BaseService<ModelDeploy, Long> imple
return resultList; return resultList;
} }
/**
* 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。
*
* @param modelDeploy 最新数据对象。
* @param originalModelDeploy 原有数据对象。
* @return 数据全部正确返回true,否则false。
*/
@Override
public CallResult verifyRelatedData(ModelDeploy modelDeploy, ModelDeploy originalModelDeploy) {
String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!";
//这里是一对多的验证
if (this.needToVerify(modelDeploy, originalModelDeploy, ModelDeploy::getModelId)
&& !modelManageService.existId(modelDeploy.getModelId())) {
return CallResult.error(String.format(errorMessageFormat, "模型ID"));
}
return CallResult.ok();
}
private ModelDeploy buildDefaultValue(ModelDeploy modelDeploy) { private ModelDeploy buildDefaultValue(ModelDeploy modelDeploy) {
if (modelDeploy.getDeployId() == null) { if (modelDeploy.getDeployId() == null) {
modelDeploy.setDeployId(idGenerator.nextLongId()); modelDeploy.setDeployId(idGenerator.nextLongId());
......
package com.yice.webadmin.app.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yice.webadmin.app.service.*;
import com.yice.webadmin.app.dao.*;
import com.yice.webadmin.app.model.*;
import com.yice.common.core.base.dao.BaseDaoMapper;
import com.yice.common.core.object.MyRelationParam;
import com.yice.common.core.base.service.BaseService;
import com.yice.common.core.util.MyModelUtil;
import com.yice.common.sequence.wrapper.IdGeneratorWrapper;
import com.github.pagehelper.Page;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
/**
* 模型管理数据操作服务类。
*
* @author linking
* @date 2023-04-13
*/
@Slf4j
@Service("modelManageService")
public class ModelManageServiceImpl extends BaseService<ModelManage, Long> implements ModelManageService {
@Autowired
private ModelManageMapper modelManageMapper;
@Autowired
private ModelVersionService modelVersionService;
@Autowired
private ModelTaskService modelTaskService;
@Autowired
private ModelDeployService modelDeployService;
@Autowired
private IdGeneratorWrapper idGenerator;
/**
* 返回当前Service的主表Mapper对象。
*
* @return 主表Mapper对象。
*/
@Override
protected BaseDaoMapper<ModelManage> mapper() {
return modelManageMapper;
}
/**
* 保存新增对象。
*
* @param modelManage 新增对象。
* @return 返回新增对象。
*/
@Transactional(rollbackFor = Exception.class)
@Override
public ModelManage saveNew(ModelManage modelManage) {
modelManageMapper.insert(this.buildDefaultValue(modelManage));
return modelManage;
}
/**
* 利用数据库的insertList语法,批量插入对象列表。
*
* @param modelManageList 新增对象列表。
*/
@Transactional(rollbackFor = Exception.class)
@Override
public void saveNewBatch(List<ModelManage> modelManageList) {
if (CollUtil.isNotEmpty(modelManageList)) {
modelManageList.forEach(this::buildDefaultValue);
modelManageMapper.insertList(modelManageList);
}
}
@Transactional(rollbackFor = Exception.class)
@Override
public ModelManage saveNewWithRelation(ModelManage modelManage, JSONObject relationData) {
this.saveNew(modelManage);
this.saveOrUpdateRelationData(modelManage, relationData);
return modelManage;
}
/**
* 更新数据对象。
*
* @param modelManage 更新的对象。
* @param originalModelManage 原有数据对象。
* @return 成功返回true,否则false。
*/
@Transactional(rollbackFor = Exception.class)
@Override
public boolean update(ModelManage modelManage, ModelManage originalModelManage) {
MyModelUtil.fillCommonsForUpdate(modelManage, originalModelManage);
// 这里重点提示,在执行主表数据更新之前,如果有哪些字段不支持修改操作,请用原有数据对象字段替换当前数据字段。
UpdateWrapper<ModelManage> uw = this.createUpdateQueryForNullValue(modelManage, modelManage.getModelId());
return modelManageMapper.update(modelManage, uw) == 1;
}
private void saveOrUpdateRelationData(ModelManage modelManage, JSONObject relationData) {
List<ModelVersion> modelVersionList =
relationData.getObject("modelVersionList", new TypeReference<List<ModelVersion>>() {});
// 对于一对多更新,分为以下三步:
// 1. 在关联从表中,删除掉与主表字段关联,但是又没有出现在本地更新中的数据。我们将这些数据视为需要删除的数据。
// 2. 在本次更新数据列表中,如果从表的对象没有主键Id,我们视为新数据,可以批量插入。
// 3. 在本次更新数据列表中,如果从表的对象存在主键Id,我们视为已有数据,逐条更新。
if (modelVersionList != null) {
modelVersionService.updateBatchByModelId(modelManage.getModelId(), modelVersionList);
}
}
/**
* 删除指定数据。
*
* @param modelId 主键Id。
* @return 成功返回true,否则false。
*/
@Transactional(rollbackFor = Exception.class)
@Override
public boolean remove(Long modelId) {
if (modelManageMapper.deleteById(modelId) == 0) {
return false;
}
modelVersionService.removeByModelId(modelId);
modelTaskService.removeByModelId(modelId);
modelDeployService.removeByModelId(modelId);
return true;
}
/**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getModelManageListWithRelation)方法。
*
* @param filter 过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
@Override
public List<ModelManage> getModelManageList(ModelManage filter, String orderBy) {
return modelManageMapper.getModelManageList(filter, orderBy);
}
/**
* 获取主表的查询结果,以及主表关联的字典数据和一对一从表数据,以及一对一从表的字典数据。
* 该查询会涉及到一对一从表的关联过滤,或一对多从表的嵌套关联过滤,因此性能不如单表过滤。
* 如果仅仅需要获取主表数据,请移步(getModelManageList),以便获取更好的查询性能。
*
* @param filter 主表过滤对象。
* @param modelVersionFilter 一对多从表过滤对象。
* @param modelTaskFilter 一对多从表过滤对象。
* @param modelDeployFilter 一对多从表过滤对象。
* @param orderBy 排序参数。
* @return 查询结果集。
*/
@Override
public List<ModelManage> getModelManageListWithRelation(ModelManage filter, ModelVersion modelVersionFilter, ModelTask modelTaskFilter, ModelDeploy modelDeployFilter, String orderBy) {
List<ModelManage> resultList =
modelManageMapper.getModelManageListEx(filter, modelVersionFilter, modelTaskFilter, modelDeployFilter, orderBy);
// 在缺省生成的代码中,如果查询结果resultList不是Page对象,说明没有分页,那么就很可能是数据导出接口调用了当前方法。
// 为了避免一次性的大量数据关联,规避因此而造成的系统运行性能冲击,这里手动进行了分批次读取,开发者可按需修改该值。
int batchSize = resultList instanceof Page ? 0 : 1000;
this.buildRelationForDataList(resultList, MyRelationParam.full(), batchSize);
return resultList;
}
@Transactional
@Override
public ModelManage saveAndCreateVersion(ModelManage modelManage, ModelVersion modelVersion) {
ModelManage reModelManage = this.saveNew(modelManage);
modelVersion.setModelId(reModelManage.getModelId());
if (modelVersion.getBusinessLabel() == null && modelManage.getBusinessLabel() != null) {
modelVersion.setBusinessLabel(modelManage.getBusinessLabel());
}
modelVersion.setVersionId(1L);
this.modelVersionService.saveNew(modelVersion);
return reModelManage;
}
private ModelManage buildDefaultValue(ModelManage modelManage) {
if (modelManage.getModelId() == null) {
modelManage.setModelId(idGenerator.nextLongId());
}
MyModelUtil.fillCommonsForInsert(modelManage);
return modelManage;
}
}
package com.yice.webadmin.app.service.impl; package com.yice.webadmin.app.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.*;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yice.webadmin.app.service.*; import com.yice.webadmin.app.service.*;
import com.yice.webadmin.app.dao.*; import com.yice.webadmin.app.dao.*;
import com.yice.webadmin.app.model.*; import com.yice.webadmin.app.model.*;
import com.yice.common.core.base.dao.BaseDaoMapper; import com.yice.common.core.base.dao.BaseDaoMapper;
import com.yice.common.core.object.MyRelationParam; import com.yice.common.core.object.MyRelationParam;
import com.yice.common.core.object.CallResult;
import com.yice.common.core.base.service.BaseService; import com.yice.common.core.base.service.BaseService;
import com.yice.common.core.util.MyModelUtil; import com.yice.common.core.util.MyModelUtil;
import com.yice.common.sequence.wrapper.IdGeneratorWrapper; import com.yice.common.sequence.wrapper.IdGeneratorWrapper;
...@@ -31,6 +33,8 @@ public class ModelTaskServiceImpl extends BaseService<ModelTask, Long> implement ...@@ -31,6 +33,8 @@ public class ModelTaskServiceImpl extends BaseService<ModelTask, Long> implement
@Autowired @Autowired
private ModelTaskMapper modelTaskMapper; private ModelTaskMapper modelTaskMapper;
@Autowired @Autowired
private ModelManageService modelManageService;
@Autowired
private IdGeneratorWrapper idGenerator; private IdGeneratorWrapper idGenerator;
/** /**
...@@ -98,6 +102,20 @@ public class ModelTaskServiceImpl extends BaseService<ModelTask, Long> implement ...@@ -98,6 +102,20 @@ public class ModelTaskServiceImpl extends BaseService<ModelTask, Long> implement
return modelTaskMapper.deleteById(taskId) == 1; return modelTaskMapper.deleteById(taskId) == 1;
} }
/**
* 当前服务的支持表为从表,根据主表的关联Id,删除一对多的从表数据。
*
* @param modelId 从表关联字段。
* @return 删除数量。
*/
@Transactional(rollbackFor = Exception.class)
@Override
public int removeByModelId(Long modelId) {
ModelTask deletedObject = new ModelTask();
deletedObject.setModelId(modelId);
return modelTaskMapper.delete(new QueryWrapper<>(deletedObject));
}
/** /**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getModelTaskListWithRelation)方法。 * 如果需要同时获取关联数据,请移步(getModelTaskListWithRelation)方法。
...@@ -130,6 +148,24 @@ public class ModelTaskServiceImpl extends BaseService<ModelTask, Long> implement ...@@ -130,6 +148,24 @@ public class ModelTaskServiceImpl extends BaseService<ModelTask, Long> implement
return resultList; return resultList;
} }
/**
* 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。
*
* @param modelTask 最新数据对象。
* @param originalModelTask 原有数据对象。
* @return 数据全部正确返回true,否则false。
*/
@Override
public CallResult verifyRelatedData(ModelTask modelTask, ModelTask originalModelTask) {
String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!";
//这里是一对多的验证
if (this.needToVerify(modelTask, originalModelTask, ModelTask::getModelId)
&& !modelManageService.existId(modelTask.getModelId())) {
return CallResult.error(String.format(errorMessageFormat, "模型ID"));
}
return CallResult.ok();
}
private ModelTask buildDefaultValue(ModelTask modelTask) { private ModelTask buildDefaultValue(ModelTask modelTask) {
if (modelTask.getTaskId() == null) { if (modelTask.getTaskId() == null) {
modelTask.setTaskId(idGenerator.nextLongId()); modelTask.setTaskId(idGenerator.nextLongId());
......
package com.yice.webadmin.app.service.impl; package com.yice.webadmin.app.service.impl;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.*;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.yice.webadmin.app.service.*; import com.yice.webadmin.app.service.*;
import com.yice.webadmin.app.dao.*; import com.yice.webadmin.app.dao.*;
import com.yice.webadmin.app.model.*; import com.yice.webadmin.app.model.*;
import com.yice.common.core.base.dao.BaseDaoMapper; import com.yice.common.core.base.dao.BaseDaoMapper;
import com.yice.common.core.object.MyRelationParam; import com.yice.common.core.object.MyRelationParam;
import com.yice.common.core.object.CallResult;
import com.yice.common.core.base.service.BaseService; import com.yice.common.core.base.service.BaseService;
import com.yice.common.core.util.MyModelUtil; import com.yice.common.core.util.MyModelUtil;
import com.yice.common.sequence.wrapper.IdGeneratorWrapper; import com.yice.common.sequence.wrapper.IdGeneratorWrapper;
...@@ -31,6 +33,8 @@ public class ModelVersionServiceImpl extends BaseService<ModelVersion, Long> imp ...@@ -31,6 +33,8 @@ public class ModelVersionServiceImpl extends BaseService<ModelVersion, Long> imp
@Autowired @Autowired
private ModelVersionMapper modelVersionMapper; private ModelVersionMapper modelVersionMapper;
@Autowired @Autowired
private ModelManageService modelManageService;
@Autowired
private IdGeneratorWrapper idGenerator; private IdGeneratorWrapper idGenerator;
/** /**
...@@ -98,6 +102,27 @@ public class ModelVersionServiceImpl extends BaseService<ModelVersion, Long> imp ...@@ -98,6 +102,27 @@ public class ModelVersionServiceImpl extends BaseService<ModelVersion, Long> imp
return modelVersionMapper.deleteById(versionId) == 1; return modelVersionMapper.deleteById(versionId) == 1;
} }
/**
* 当前服务的支持表为从表,根据主表的关联Id,删除一对多的从表数据。
*
* @param modelId 从表关联字段。
* @return 删除数量。
*/
@Transactional(rollbackFor = Exception.class)
@Override
public int removeByModelId(Long modelId) {
ModelVersion deletedObject = new ModelVersion();
deletedObject.setModelId(modelId);
return modelVersionMapper.delete(new QueryWrapper<>(deletedObject));
}
@Transactional(rollbackFor = Exception.class)
@Override
public void updateBatchByModelId(Long modelId, List<ModelVersion> dataList) {
this.updateBatchOneToManyRelation("modelId", modelId,
null, null, dataList, this::saveNewBatch);
}
/** /**
* 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。 * 获取单表查询结果。由于没有关联数据查询,因此在仅仅获取单表数据的场景下,效率更高。
* 如果需要同时获取关联数据,请移步(getModelVersionListWithRelation)方法。 * 如果需要同时获取关联数据,请移步(getModelVersionListWithRelation)方法。
...@@ -130,6 +155,24 @@ public class ModelVersionServiceImpl extends BaseService<ModelVersion, Long> imp ...@@ -130,6 +155,24 @@ public class ModelVersionServiceImpl extends BaseService<ModelVersion, Long> imp
return resultList; return resultList;
} }
/**
* 根据最新对象和原有对象的数据对比,判断关联的字典数据和多对一主表数据是否都是合法数据。
*
* @param modelVersion 最新数据对象。
* @param originalModelVersion 原有数据对象。
* @return 数据全部正确返回true,否则false。
*/
@Override
public CallResult verifyRelatedData(ModelVersion modelVersion, ModelVersion originalModelVersion) {
String errorMessageFormat = "数据验证失败,关联的%s并不存在,请刷新后重试!";
//这里是一对多的验证
if (this.needToVerify(modelVersion, originalModelVersion, ModelVersion::getModelId)
&& !modelManageService.existId(modelVersion.getModelId())) {
return CallResult.error(String.format(errorMessageFormat, "模型ID"));
}
return CallResult.ok();
}
private ModelVersion buildDefaultValue(ModelVersion modelVersion) { private ModelVersion buildDefaultValue(ModelVersion modelVersion) {
if (modelVersion.getVersionId() == null) { if (modelVersion.getVersionId() == null) {
modelVersion.setVersionId(idGenerator.nextLongId()); modelVersion.setVersionId(idGenerator.nextLongId());
......
...@@ -30,7 +30,7 @@ public class DatasetVersionVo extends BaseVo { ...@@ -30,7 +30,7 @@ public class DatasetVersionVo extends BaseVo {
* 版本。 * 版本。
*/ */
@ApiModelProperty(value = "版本") @ApiModelProperty(value = "版本")
private String datasetVersion; private Integer datasetVersion;
/** /**
* 导入状态。 * 导入状态。
...@@ -80,6 +80,36 @@ public class DatasetVersionVo extends BaseVo { ...@@ -80,6 +80,36 @@ public class DatasetVersionVo extends BaseVo {
@ApiModelProperty(value = "数据量") @ApiModelProperty(value = "数据量")
private Long dataVolume; private Long dataVolume;
/**
* 标注类型。
*/
@ApiModelProperty(value = "标注类型")
private Integer dimensionType;
/**
* 模板。
*/
@ApiModelProperty(value = "模板")
private Integer template;
/**
* 是否继承历史版本。
*/
@ApiModelProperty(value = "是否继承历史版本")
private Integer isInherit;
/**
* 历史版本。
*/
@ApiModelProperty(value = "历史版本")
private Integer hisVersion;
/**
* 文件地址。
*/
@ApiModelProperty(value = "文件地址")
private String fileUrl;
/** /**
* versionId 的一对一关联数据对象,数据对应类型为DatasetDetailVo。 * versionId 的一对一关联数据对象,数据对应类型为DatasetDetailVo。
*/ */
......
...@@ -48,4 +48,28 @@ public class ModelDeployVo extends BaseVo { ...@@ -48,4 +48,28 @@ public class ModelDeployVo extends BaseVo {
*/ */
@ApiModelProperty(value = "部署状态") @ApiModelProperty(value = "部署状态")
private Integer deployStatus; private Integer deployStatus;
/**
* 模型版本号。
*/
@ApiModelProperty(value = "模型版本号")
private Integer modelVersion;
/**
* 服务ID。
*/
@ApiModelProperty(value = "服务ID")
private Long serviceId;
/**
* 服务名称。
*/
@ApiModelProperty(value = "服务名称")
private String serviceName;
/**
* 服务版本。
*/
@ApiModelProperty(value = "服务版本")
private Integer serviceVersion;
} }
package com.yice.webadmin.app.vo;
import com.yice.common.core.base.vo.BaseVo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.Date;
import java.util.Map;
import java.util.List;
/**
* ModelManageVO视图对象。
*
* @author linking
* @date 2023-04-13
*/
@ApiModel("ModelManageVO视图对象")
@Data
@EqualsAndHashCode(callSuper = true)
public class ModelManageVo extends BaseVo {
/**
* 模型ID。
*/
@ApiModelProperty(value = "模型ID")
private Long modelId;
/**
* 模型名称。
*/
@ApiModelProperty(value = "模型名称")
private String modelName;
/**
* 模型类型。
*/
@ApiModelProperty(value = "模型类型")
private Integer modelType;
/**
* 模型描述。
*/
@ApiModelProperty(value = "模型描述")
private String modelDescribe;
/**
* 版本数量。
*/
@ApiModelProperty(value = "版本数量")
private Integer versionCount;
/**
* 业务标签。
*/
@ApiModelProperty(value = "业务标签")
private String businessLabel;
/**
* 是否为基础模型。
*/
@ApiModelProperty(value = "是否为基础模型")
private Integer isBaseModel;
/**
* 最新版本来源。
*/
@ApiModelProperty(value = "最新版本来源")
private String lastVersionSource;
/**
* ModelVersion 的一对多关联表数据对象。数据对应类型为ModelVersion。
*/
@ApiModelProperty(value = "ModelVersion 的一对多关联表数据对象。数据对应类型为ModelVersion")
private List<Map<String, Object>> modelVersionList;
/**
* ModelTask 的一对多关联表数据对象。数据对应类型为ModelTask。
*/
@ApiModelProperty(value = "ModelTask 的一对多关联表数据对象。数据对应类型为ModelTask")
private List<Map<String, Object>> modelTaskList;
/**
* ModelDeploy 的一对多关联表数据对象。数据对应类型为ModelDeploy。
*/
@ApiModelProperty(value = "ModelDeploy 的一对多关联表数据对象。数据对应类型为ModelDeploy")
private List<Map<String, Object>> modelDeployList;
}
...@@ -60,4 +60,10 @@ public class ModelTaskVo extends BaseVo { ...@@ -60,4 +60,10 @@ public class ModelTaskVo extends BaseVo {
*/ */
@ApiModelProperty(value = "完成时间") @ApiModelProperty(value = "完成时间")
private Date completeTime; private Date completeTime;
/**
* 模型版本号。
*/
@ApiModelProperty(value = "模型版本号")
private Integer modelVersion;
} }
...@@ -7,6 +7,7 @@ import lombok.Data; ...@@ -7,6 +7,7 @@ import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import java.util.Date; import java.util.Date;
import java.util.Map;
/** /**
* ModelVersionVO视图对象。 * ModelVersionVO视图对象。
...@@ -66,4 +67,70 @@ public class ModelVersionVo extends BaseVo { ...@@ -66,4 +67,70 @@ public class ModelVersionVo extends BaseVo {
*/ */
@ApiModelProperty(value = "版权信息") @ApiModelProperty(value = "版权信息")
private String copyright; private String copyright;
/**
* 模型版本号。
*/
@ApiModelProperty(value = "模型版本号")
private Integer modelVersion;
/**
* 版本状态。
*/
@ApiModelProperty(value = "版本状态")
private Integer status;
/**
* 版本来源。
*/
@ApiModelProperty(value = "版本来源")
private String versionSource;
/**
* 基础模型。
*/
@ApiModelProperty(value = "基础模型")
private String baseModel;
/**
* 业务标签。
*/
@ApiModelProperty(value = "业务标签")
private String businessLabel;
/**
* 基础模型ID。
*/
@ApiModelProperty(value = "基础模型ID")
private Long baseId;
/**
* 模型训练方式。
*/
@ApiModelProperty(value = "模型训练方式")
private String modelTrainingMethod;
/**
* 运行名称。
*/
@ApiModelProperty(value = "运行名称")
private String runName;
/**
* 训练任务。
*/
@ApiModelProperty(value = "训练任务")
private String trainingTask;
/**
* 模型地址。
*/
@ApiModelProperty(value = "模型地址")
private String modelUrl;
/**
* modelId 的一对一关联数据对象,数据对应类型为ModelManageVo。
*/
@ApiModelProperty(value = "modelId 的一对一关联数据对象,数据对应类型为ModelManageVo")
private Map<String, Object> modelManage;
} }
...@@ -25,8 +25,8 @@ spring: ...@@ -25,8 +25,8 @@ spring:
active: dev active: dev
servlet: servlet:
multipart: multipart:
max-file-size: 50MB max-file-size: 1024MB
max-request-size: 50MB max-request-size: 1024MB
mvc: mvc:
converters: converters:
preferred-json-mapper: fastjson preferred-json-mapper: fastjson
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment