| @@ -8,5 +8,5 @@ import java.lang.annotation.Target; | |||||
| @Retention(RetentionPolicy.RUNTIME) | @Retention(RetentionPolicy.RUNTIME) | ||||
| public @interface CheckDuplicate { | public @interface CheckDuplicate { | ||||
| String value() default ""; | String value() default ""; | ||||
| String message() default "不能重复"; | |||||
| String message() default "不能重复!"; | |||||
| } | } | ||||
| @@ -66,7 +66,7 @@ public class DatasetVersionController extends BaseController { | |||||
| */ | */ | ||||
| @GetMapping("/versions") | @GetMapping("/versions") | ||||
| @ApiOperation("通过数据集id和version查询版本文件列表") | @ApiOperation("通过数据集id和version查询版本文件列表") | ||||
| public GenericsAjaxResult<List<DatasetVersion>> queryByDatasetIdAndVersion(@RequestParam("dataset_id") Integer datasetId, | |||||
| public GenericsAjaxResult<Map<String,Object>> queryByDatasetIdAndVersion(@RequestParam("dataset_id") Integer datasetId, | |||||
| @RequestParam("version") String version) { | @RequestParam("version") String version) { | ||||
| return genericsSuccess(this.datasetVersionService.queryByDatasetIdAndVersion(datasetId, version)); | return genericsSuccess(this.datasetVersionService.queryByDatasetIdAndVersion(datasetId, version)); | ||||
| } | } | ||||
| @@ -64,7 +64,7 @@ public class ModelsVersionController extends BaseController { | |||||
| * @return 匹配的模型版本记录列表 | * @return 匹配的模型版本记录列表 | ||||
| */ | */ | ||||
| @GetMapping("/versions") | @GetMapping("/versions") | ||||
| public GenericsAjaxResult<List<ModelsVersion>> queryByModelsIdAndVersion(@RequestParam("models_id") Integer modelsId, | |||||
| public GenericsAjaxResult<Map<String,Object>> queryByModelsIdAndVersion(@RequestParam("models_id") Integer modelsId, | |||||
| @RequestParam("version") String version) { | @RequestParam("version") String version) { | ||||
| return genericsSuccess(this.modelsVersionService.queryByModelsIdAndVersion(modelsId, version)); | return genericsSuccess(this.modelsVersionService.queryByModelsIdAndVersion(modelsId, version)); | ||||
| } | } | ||||
| @@ -1,15 +1,15 @@ | |||||
| package com.ruoyi.platform.domain; | package com.ruoyi.platform.domain; | ||||
| public enum TensorBoardStatus { | |||||
| Pending("Pending",1), Running("Running",2),Terminated("未运行",3); | |||||
| public enum PodStatus { | |||||
| Pending("Pending",1), Running("Running",2),Terminated("Terminated",3), Failed("Failed",4), Unknown("Unknown",5); | |||||
| private String name; | private String name; | ||||
| private int index; | private int index; | ||||
| private TensorBoardStatus(String name, int index) { | |||||
| private PodStatus(String name, int index) { | |||||
| this.name = name; | this.name = name; | ||||
| this.index = index; | this.index = index; | ||||
| } | } | ||||
| public static String getName(int index) { | public static String getName(int index) { | ||||
| for (TensorBoardStatus c : TensorBoardStatus.values()) { | |||||
| for (PodStatus c : PodStatus.values()) { | |||||
| if (c.getIndex() == index) { | if (c.getIndex() == index) { | ||||
| return c.name; | return c.name; | ||||
| } | } | ||||
| @@ -66,7 +66,7 @@ public interface DatasetVersionService { | |||||
| DatasetVersion queryByDatasetVersion(DatasetVersion datasetVersion); | DatasetVersion queryByDatasetVersion(DatasetVersion datasetVersion); | ||||
| List<DatasetVersion> queryByDatasetIdAndVersion(Integer datasetId, String version); | |||||
| Map<String,Object> queryByDatasetIdAndVersion(Integer datasetId, String version); | |||||
| Map<Integer,String> deleteDatasetVersion(Integer datasetId, String version); | Map<Integer,String> deleteDatasetVersion(Integer datasetId, String version); | ||||
| @@ -66,7 +66,7 @@ public interface ModelsVersionService { | |||||
| ModelsVersion queryByModelsVersion(ModelsVersion modelsVersion); | ModelsVersion queryByModelsVersion(ModelsVersion modelsVersion); | ||||
| List<ModelsVersion> queryByModelsIdAndVersion(Integer modelsId, String version); | |||||
| Map<String,Object> queryByModelsIdAndVersion(Integer modelsId, String version); | |||||
| Map<Integer, String> deleteModelsVersion(Integer modelsId, String version); | Map<Integer, String> deleteModelsVersion(Integer modelsId, String version); | ||||
| @@ -59,11 +59,9 @@ public class DatasetServiceImpl implements DatasetService { | |||||
| // 固定存储桶名 | // 固定存储桶名 | ||||
| private final String bucketName = "platform-data"; | private final String bucketName = "platform-data"; | ||||
| private final MinioUtil minioUtil; | |||||
| @Resource | |||||
| private MinioUtil minioUtil; | |||||
| public DatasetServiceImpl(MinioUtil minioUtil) { | |||||
| this.minioUtil = minioUtil; | |||||
| } | |||||
| /** | /** | ||||
| @@ -212,6 +210,9 @@ public class DatasetServiceImpl implements DatasetService { | |||||
| @Override | @Override | ||||
| public List<Map<String, String>> uploadDataset(MultipartFile[] files) throws Exception { | public List<Map<String, String>> uploadDataset(MultipartFile[] files) throws Exception { | ||||
| List<Map<String, String>> results = new ArrayList<>(); | List<Map<String, String>> results = new ArrayList<>(); | ||||
| //时间戳统一定在外面,一次上传就定好 | |||||
| Date createTime = new Date(); | |||||
| String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(createTime); | |||||
| for (MultipartFile file:files){ | for (MultipartFile file:files){ | ||||
| if (file.isEmpty()) { | if (file.isEmpty()) { | ||||
| @@ -224,8 +225,6 @@ public class DatasetServiceImpl implements DatasetService { | |||||
| // 其余操作基于 modelsVersionToUse | // 其余操作基于 modelsVersionToUse | ||||
| String username = SecurityUtils.getLoginUser().getUsername(); | String username = SecurityUtils.getLoginUser().getUsername(); | ||||
| String fileName = file.getOriginalFilename(); | String fileName = file.getOriginalFilename(); | ||||
| Date createTime = new Date(); | |||||
| String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(createTime); | |||||
| String objectName = "datasets/" + username + "/" + timestamp + "/" + fileName; | String objectName = "datasets/" + username + "/" + timestamp + "/" + fileName; | ||||
| // 上传文件到MinIO并将记录新增到数据库中 | // 上传文件到MinIO并将记录新增到数据库中 | ||||
| @@ -306,6 +305,8 @@ public class DatasetServiceImpl implements DatasetService { | |||||
| .filter(version -> version != null && !version.isEmpty()) //忽略null或空字符串的version | .filter(version -> version != null && !version.isEmpty()) //忽略null或空字符串的version | ||||
| .distinct() // 去重 | .distinct() // 去重 | ||||
| .collect(Collectors.toList()); // 收集到List中 | .collect(Collectors.toList()); // 收集到List中 | ||||
| } | } | ||||
| @@ -33,6 +33,9 @@ public class DatasetVersionServiceImpl implements DatasetVersionService { | |||||
| @Resource | @Resource | ||||
| private DatasetVersionDao datasetVersionDao; | private DatasetVersionDao datasetVersionDao; | ||||
| // 固定存储桶名 | |||||
| private final String bucketName = "platform-data"; | |||||
| /** | /** | ||||
| * 通过ID查询单条数据 | * 通过ID查询单条数据 | ||||
| * | * | ||||
| @@ -131,9 +134,21 @@ public class DatasetVersionServiceImpl implements DatasetVersionService { | |||||
| } | } | ||||
| @Override | @Override | ||||
| public Map<String,Object> queryByDatasetIdAndVersion(Integer datasetId, String version) { | |||||
| Map<String, Object> response = new HashMap<>(); | |||||
| List<DatasetVersion> datasetVersionList = this.datasetVersionDao.queryAllByDatasetVersion(datasetId, version); | |||||
| datasetVersionList.stream(). | |||||
| findFirst(). | |||||
| ifPresent(datasetVersion -> { | |||||
| String url = datasetVersion.getUrl(); | |||||
| String path = bucketName + '/' + url.substring(0, url.lastIndexOf('/')); | |||||
| response.put("path", path); | |||||
| }); | |||||
| public List<DatasetVersion> queryByDatasetIdAndVersion(Integer datasetId, String version) { | |||||
| return this.datasetVersionDao.queryAllByDatasetVersion(datasetId, version); | |||||
| response.put("content", datasetVersionList); | |||||
| return response; | |||||
| } | } | ||||
| @Override | @Override | ||||
| @@ -58,12 +58,9 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| // 固定存储桶名 | // 固定存储桶名 | ||||
| private final String bucketName = "platform-data"; | private final String bucketName = "platform-data"; | ||||
| @Resource | |||||
| private MinioUtil minioUtil; | |||||
| private final MinioUtil minioUtil; | |||||
| public ModelsServiceImpl(MinioUtil minioUtil) { | |||||
| this.minioUtil = minioUtil; | |||||
| } | |||||
| /** | /** | ||||
| * 通过ID查询单条数据 | * 通过ID查询单条数据 | ||||
| @@ -208,6 +205,9 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| public List<Map<String, String>> uploadModels(MultipartFile[] files) throws Exception { | public List<Map<String, String>> uploadModels(MultipartFile[] files) throws Exception { | ||||
| List<Map<String, String>> results = new ArrayList<>(); | List<Map<String, String>> results = new ArrayList<>(); | ||||
| //时间戳统一定在外面,一次上传就定好 | |||||
| Date createTime = new Date(); | |||||
| String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(createTime); | |||||
| for (MultipartFile file:files){ | for (MultipartFile file:files){ | ||||
| if (file.isEmpty()) { | if (file.isEmpty()) { | ||||
| @@ -220,8 +220,6 @@ public class ModelsServiceImpl implements ModelsService { | |||||
| // 其余操作基于 modelsVersionToUse | // 其余操作基于 modelsVersionToUse | ||||
| String username = SecurityUtils.getLoginUser().getUsername(); | String username = SecurityUtils.getLoginUser().getUsername(); | ||||
| String fileName = file.getOriginalFilename(); | String fileName = file.getOriginalFilename(); | ||||
| Date createTime = new Date(); | |||||
| String timestamp = new SimpleDateFormat("yyyyMMdd-HHmmss").format(createTime); | |||||
| String objectName = "models/" + username + "/" + timestamp + "/" + fileName; | String objectName = "models/" + username + "/" + timestamp + "/" + fileName; | ||||
| // 上传文件到MinIO并将记录新增到数据库中 | // 上传文件到MinIO并将记录新增到数据库中 | ||||
| @@ -34,6 +34,9 @@ public class ModelsVersionServiceImpl implements ModelsVersionService { | |||||
| @Resource | @Resource | ||||
| private ModelsDao modelsDao; | private ModelsDao modelsDao; | ||||
| // 固定存储桶名 | |||||
| private final String bucketName = "platform-data"; | |||||
| /** | /** | ||||
| * 通过ID查询单条数据 | * 通过ID查询单条数据 | ||||
| * | * | ||||
| @@ -159,8 +162,21 @@ public class ModelsVersionServiceImpl implements ModelsVersionService { | |||||
| * @return 新的模型版本记录列表 | * @return 新的模型版本记录列表 | ||||
| */ | */ | ||||
| @Override | @Override | ||||
| public List<ModelsVersion> queryByModelsIdAndVersion(Integer modelsId, String version) { | |||||
| return this.modelsVersionDao.queryAllByModelsVersion(modelsId, version) ; | |||||
| public Map<String,Object> queryByModelsIdAndVersion(Integer modelsId, String version) { | |||||
| Map<String,Object> response = new HashMap<>(); | |||||
| List<ModelsVersion> modelsVersionList = this.modelsVersionDao.queryAllByModelsVersion(modelsId, version); | |||||
| modelsVersionList.stream(). | |||||
| findFirst(). | |||||
| ifPresent(modelsVersion -> { | |||||
| String url = modelsVersion.getUrl(); | |||||
| String path = bucketName + '/' + url.substring(0, url.lastIndexOf('/')); | |||||
| response.put("path", path); | |||||
| }); | |||||
| response.put("content", modelsVersionList); | |||||
| return response; | |||||
| } | } | ||||
| @@ -2,19 +2,15 @@ package com.ruoyi.platform.service.impl; | |||||
| import com.ruoyi.common.core.utils.StringUtils; | import com.ruoyi.common.core.utils.StringUtils; | ||||
| import com.ruoyi.common.security.utils.SecurityUtils; | import com.ruoyi.common.security.utils.SecurityUtils; | ||||
| import com.ruoyi.platform.domain.TensorBoardStatus; | |||||
| import com.ruoyi.platform.domain.PodStatus; | |||||
| import com.ruoyi.platform.service.TensorBoardService; | import com.ruoyi.platform.service.TensorBoardService; | ||||
| import com.ruoyi.platform.utils.K8sClientUtil; | import com.ruoyi.platform.utils.K8sClientUtil; | ||||
| import com.ruoyi.platform.vo.FrameLogPathVo; | import com.ruoyi.platform.vo.FrameLogPathVo; | ||||
| import com.ruoyi.system.api.model.LoginUser; | import com.ruoyi.system.api.model.LoginUser; | ||||
| import io.kubernetes.client.openapi.models.V1Pod; | |||||
| import net.sf.jsqlparser.schema.Database; | |||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||
| import org.springframework.stereotype.Service; | import org.springframework.stereotype.Service; | ||||
| import javax.annotation.Resource; | import javax.annotation.Resource; | ||||
| import java.text.SimpleDateFormat; | |||||
| import java.util.Date; | |||||
| @Service | @Service | ||||
| public class TensorBoardServiceImpl implements TensorBoardService { | public class TensorBoardServiceImpl implements TensorBoardService { | ||||
| @@ -30,8 +26,8 @@ public class TensorBoardServiceImpl implements TensorBoardService { | |||||
| private K8sClientUtil k8sClientUtil; | private K8sClientUtil k8sClientUtil; | ||||
| @Override | @Override | ||||
| public String getTensorBoardStatus(FrameLogPathVo frameLogPathVo){ | public String getTensorBoardStatus(FrameLogPathVo frameLogPathVo){ | ||||
| String status = TensorBoardStatus.Terminated.getName(); | |||||
| if (StringUtils.isEmpty(frameLogPathVo.getPath())||StringUtils.isEmpty(frameLogPathVo.getPvcName())){ | |||||
| String status = PodStatus.Terminated.getName(); | |||||
| if (StringUtils.isEmpty(frameLogPathVo.getPath())){ | |||||
| return status; | return status; | ||||
| } | } | ||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| @@ -39,9 +35,14 @@ public class TensorBoardServiceImpl implements TensorBoardService { | |||||
| try { | try { | ||||
| String podStatus = k8sClientUtil.getPodStatus(podName, StringUtils.isEmpty(frameLogPathVo.getNamespace()) ? "default" : frameLogPathVo.getNamespace()); | String podStatus = k8sClientUtil.getPodStatus(podName, StringUtils.isEmpty(frameLogPathVo.getNamespace()) ? "default" : frameLogPathVo.getNamespace()); | ||||
| System.out.println(podStatus); | |||||
| for (PodStatus s : PodStatus.values()) { | |||||
| if (s.getName().equals(podStatus)) { | |||||
| status = s.getName(); | |||||
| break; | |||||
| } | |||||
| } | |||||
| } catch (Exception e) { | } catch (Exception e) { | ||||
| return TensorBoardStatus.Terminated.getName(); | |||||
| return PodStatus.Terminated.getName(); | |||||
| } | } | ||||
| return status; | return status; | ||||
| } | } | ||||
| @@ -91,7 +91,7 @@ public class K8sClientUtil { | |||||
| // try { | // try { | ||||
| // this.apiClient = new ClientBuilder(). | // this.apiClient = new ClientBuilder(). | ||||
| // setBasePath("https://172.20.32.181:6443").setVerifyingSsl(false). | // setBasePath("https://172.20.32.181:6443").setVerifyingSsl(false). | ||||
| // setAuthentication(new AccessTokenAuthentication("eyJhbGciOiJSUzI1NiIsImtpZCI6IjRWcFBPWl9YSFFxQ2tVanRuNHdRT1dnUlJNTnB2bG5TQlVSRjNKdExWNDQifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJkZWZhdWx0LXRva2VuLXNteGxuIiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZXJ2aWNlLWFjY291bnQubmFtZSI6ImRlZmF1bHQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiIyZWY1ZjdkMC0zMTdkLTQxN2UtOWY4Ni1mYjA1OTFhYWVhZDQiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6a3ViZS1zeXN0ZW06ZGVmYXVsdCJ9.GMpReYK7YJ0nNy-F6VrUJQzjWQiSauAOeq0-DT8ik2Lx8f2eznYEm_3cHX4kIn_nYgfxo857urcHt4Ft6IgVtWzxLzVTCQVaNP_H2J8bnJn8W2tUKXzF_3d_GwO75H7kN8P3aoShULrOLpiIf3o3Az28_gwHkwCnd42npcKrCXfAKj8A2U7-KUFQXXA-etrWSw81C5t8ziL-2xaiDgwD3ewH-TNYsOpyWjGopNTxJn1F7GyJ7xDlmMJOaZhSnOrDggB7lqDEsE68YmZtqB7lcSaZHnKzvNhEdbKri4R7_urpjttz_k6qcfIi-l6GwPtJLatsPDg3OL3FFnzjvArJ-A")).build(); | |||||
| // setAuthentication(new AccessTokenAuthentication("eyJhbGciOiJSUzI1NiIsImtpZCI6IjRWcFBPWl9YSFFxQ2tVanRuNHdRT1dnUlJNTnB2bG5TQlVSRjNKdExWNDQifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImFkbWluLXNlcnZpY2UtYWNjb3VudC10b2tlbi14ZDk5eiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJhZG1pbi1zZXJ2aWNlLWFjY291bnQiLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC51aWQiOiJmMGEzNmYyMS01MjQyLTQ4MTAtYWVmZS0xOTEwOTZlZjc5YmUiLCJzdWIiOiJzeXN0ZW06c2VydmljZWFjY291bnQ6ZGVmYXVsdDphZG1pbi1zZXJ2aWNlLWFjY291bnQifQ.fo-Wf0-5-IRC5fhRh65yfqCJqKfE9MrNFIXL2fd1CqVAHD7JBpWO2IsFiSmz9Bm7VfLmFAp2NB7DjW4ZLjC7ODiGhpSseBP8x4ceFuHL6pRGUsEBvHQBBBuQcGhNOcsxIDHnDqUdUzoLprj223lMZNTQowITuqYFU4GVbethyEuS6G5Wh9KHI3KYHFtG4_AeWBgI5Ppz8pDrhHzSFWTFbzxQ3RPGEwF0V-9wEtdrSYnfETi3rdRWif9W4a0RW8HwD9Gf7UCYcyFOs7e5_3-IvmctS85g87PYIfHXMhu_kOw-_Il4bkwPEK5uiBFDw0M1-s9YP-F9r5sXXvOJlsAr1g")).build(); | |||||
| // } catch (Exception e) { | // } catch (Exception e) { | ||||
| // log.error("构建K8s-Client异常", e); | // log.error("构建K8s-Client异常", e); | ||||
| // throw new RuntimeException("构建K8s-Client异常"); | // throw new RuntimeException("构建K8s-Client异常"); | ||||
| @@ -4,10 +4,11 @@ package com.ruoyi.platform.utils; | |||||
| import io.minio.*; | import io.minio.*; | ||||
| import io.minio.errors.MinioException; | import io.minio.errors.MinioException; | ||||
| import io.minio.messages.Item; | import io.minio.messages.Item; | ||||
| import lombok.extern.slf4j.Slf4j; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | |||||
| import org.springframework.beans.factory.annotation.Value; | import org.springframework.beans.factory.annotation.Value; | ||||
| import org.springframework.stereotype.Component; | import org.springframework.stereotype.Component; | ||||
| import javax.annotation.PostConstruct; | |||||
| import java.io.*; | import java.io.*; | ||||
| import java.nio.charset.StandardCharsets; | import java.nio.charset.StandardCharsets; | ||||
| import java.nio.file.Path; | import java.nio.file.Path; | ||||
| @@ -18,26 +19,20 @@ import java.util.List; | |||||
| import java.util.Map; | import java.util.Map; | ||||
| import java.util.zip.ZipEntry; | import java.util.zip.ZipEntry; | ||||
| import java.util.zip.ZipOutputStream; | import java.util.zip.ZipOutputStream; | ||||
| @Slf4j | |||||
| @Component | @Component | ||||
| public class MinioUtil { | public class MinioUtil { | ||||
| @Value("${minio.endpoint}") | |||||
| private String minioEndpoint; | |||||
| @Value("${minio.accessKey}") | |||||
| private String minioAccessKey; | |||||
| @Value("${minio.secretKey}") | |||||
| private String minioSecretKey; | |||||
| private MinioClient minioClient; | private MinioClient minioClient; | ||||
| @PostConstruct | |||||
| public void init() { | |||||
| @Autowired | |||||
| public MinioUtil(@Value("${minio.endpoint}")String minioEndpoint,@Value("${minio.accessKey}")String minioAccessKey,@Value("${minio.secretKey}") String minioSecretKey) { | |||||
| this.minioClient = MinioClient.builder() | this.minioClient = MinioClient.builder() | ||||
| .endpoint(minioEndpoint) | .endpoint(minioEndpoint) | ||||
| .credentials(minioAccessKey, minioSecretKey) | .credentials(minioAccessKey, minioSecretKey) | ||||
| .build(); | .build(); | ||||
| } | } | ||||
| public void createBucket(String bucketName) throws Exception { | public void createBucket(String bucketName) throws Exception { | ||||
| if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) { | if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) { | ||||
| minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); | minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); | ||||
| @@ -39,10 +39,10 @@ | |||||
| from models_version | from models_version | ||||
| <where> | <where> | ||||
| state = 1 | state = 1 | ||||
| <if test="modelsId != null"> | |||||
| <if test="modelsVersion.modelsId != null"> | |||||
| and models_id = #{modelsVersion.modelsId} | and models_id = #{modelsVersion.modelsId} | ||||
| </if> | </if> | ||||
| <if test="version != null and version != ''"> | |||||
| <if test="modelsVersion.version != null and modelsVersion.version != ''"> | |||||
| and version = #{modelsVersion.version} | and version = #{modelsVersion.version} | ||||
| </if> | </if> | ||||
| </where> | </where> | ||||