| @@ -31,7 +31,7 @@ public interface ExperimentInsService { | |||||
| /** | /** | ||||
| * 根据实验ID查找所有具有相同ID的实例,并将它们添加到实验列表中 | * 根据实验ID查找所有具有相同ID的实例,并将它们添加到实验列表中 | ||||
| * | * | ||||
| * @param experimentId 实验id,不是实例id | |||||
| * @param experimentId 实验id,不是实验实例id | |||||
| * @return 实例列表 | * @return 实例列表 | ||||
| */ | */ | ||||
| List<ExperimentIns> getByExperimentId(Integer experimentId) throws IOException; | List<ExperimentIns> getByExperimentId(Integer experimentId) throws IOException; | ||||
| @@ -341,6 +341,9 @@ public class ImageServiceImpl implements ImageService { | |||||
| } | } | ||||
| } | } | ||||
| @Override | @Override | ||||
| public Map<String, String> uploadImageFiles(MultipartFile file) throws Exception { | public Map<String, String> uploadImageFiles(MultipartFile file) throws Exception { | ||||
| LoginUser loginUser = SecurityUtils.getLoginUser(); | LoginUser loginUser = SecurityUtils.getLoginUser(); | ||||
| @@ -99,10 +99,7 @@ public class JupyterServiceImpl implements JupyterService { | |||||
| // 调用修改后的 createPod 方法,传入额外的参数 | // 调用修改后的 createPod 方法,传入额外的参数 | ||||
| Integer podPort = k8sClientUtil.createConfiguredPod(podName, namespace, port, mountPath, pvc, image, minioPvcName, datasetPath, modelPath); | Integer podPort = k8sClientUtil.createConfiguredPod(podName, namespace, port, mountPath, pvc, image, minioPvcName, datasetPath, modelPath); | ||||
| // // 简单的延迟,以便 Pod 有时间启动 | |||||
| // Thread.sleep(2500); | |||||
| // //查询pod状态,更新到数据库 | |||||
| // String podStatus = k8sClientUtil.getPodStatus(podName, namespace); | |||||
| String url = masterIp + ":" + podPort; | String url = masterIp + ":" + podPort; | ||||
| redisService.setCacheObject(podName,masterIp + ":" + podPort); | redisService.setCacheObject(podName,masterIp + ":" + podPort); | ||||
| devEnvironment.setStatus("Pending"); | devEnvironment.setStatus("Pending"); | ||||
| @@ -129,7 +126,6 @@ public class JupyterServiceImpl implements JupyterService { | |||||
| // 使用 Kubernetes API 删除 Pod | // 使用 Kubernetes API 删除 Pod | ||||
| String deleteResult = k8sClientUtil.deletePod(podName, namespace); | String deleteResult = k8sClientUtil.deletePod(podName, namespace); | ||||
| devEnvironment.setStatus("Terminated"); | devEnvironment.setStatus("Terminated"); | ||||
| this.devEnvironmentService.update(devEnvironment); | this.devEnvironmentService.update(devEnvironment); | ||||
| return deleteResult + ",编辑器已停止"; | return deleteResult + ",编辑器已停止"; | ||||
| @@ -19,58 +19,90 @@ public class AIM64EncoderUtil { | |||||
| } | } | ||||
| public static String aim64encode(Map<String, Object> value) { | public static String aim64encode(Map<String, Object> value) { | ||||
| // 将Map对象转换为JSON字符串 | |||||
| String jsonEncoded = JSON.toJSONString(value); | String jsonEncoded = JSON.toJSONString(value); | ||||
| // 将JSON字符串进行Base64编码 | |||||
| String base64Encoded = Base64.getEncoder().encodeToString(jsonEncoded.getBytes()); | String base64Encoded = Base64.getEncoder().encodeToString(jsonEncoded.getBytes()); | ||||
| String aim64Encoded = base64Encoded; | String aim64Encoded = base64Encoded; | ||||
| // 替换Base64编码中的特定字符 | |||||
| for (Map.Entry<String, String> entry : BS64_REPLACE_CHARACTERS_ENCODING.entrySet()) { | for (Map.Entry<String, String> entry : BS64_REPLACE_CHARACTERS_ENCODING.entrySet()) { | ||||
| aim64Encoded = aim64Encoded.replace(entry.getKey(), entry.getValue()); | aim64Encoded = aim64Encoded.replace(entry.getKey(), entry.getValue()); | ||||
| } | } | ||||
| // 返回带有前缀的AIM64编码字符串 | |||||
| return AIM64_ENCODING_PREFIX + aim64Encoded; | return AIM64_ENCODING_PREFIX + aim64Encoded; | ||||
| } | } | ||||
| // 这是一个静态方法,用于将 Map 对象 value 编码为字符串 | |||||
| public static String encode(Map<String, Object> value, boolean oneWayHashing) { | public static String encode(Map<String, Object> value, boolean oneWayHashing) { | ||||
| // 如果 oneWayHashing 参数为 true,表示使用一种不可逆的哈希算法 | |||||
| if (oneWayHashing) { | if (oneWayHashing) { | ||||
| // 使用 MD5 算法将 value 对象转换为字符串 | |||||
| return md5(JSON.toJSONString(value)); | return md5(JSON.toJSONString(value)); | ||||
| } | } | ||||
| // 如果 oneWayHashing 参数为 false,表示使用一种可逆的编码算法 | |||||
| return aim64encode(value); | return aim64encode(value); | ||||
| } | } | ||||
| // MD5 加密函数,用于将输入字符串转换为 MD5 加密后的字符串。 | |||||
| private static String md5(String input) { | private static String md5(String input) { | ||||
| // 尝试获取 MD5 加密对象 | |||||
| try { | try { | ||||
| java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); | java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5"); | ||||
| // 使用 MD5 对象对输入字符串进行加密 | |||||
| byte[] array = md.digest(input.getBytes()); | byte[] array = md.digest(input.getBytes()); | ||||
| // 创建一个 StringBuilder 对象,用于将加密后的字节转换为字符串 | |||||
| StringBuilder sb = new StringBuilder(); | StringBuilder sb = new StringBuilder(); | ||||
| // 遍历加密后的字节数组 | |||||
| for (byte b : array) { | for (byte b : array) { | ||||
| // 将每个字节转换为 16 进制字符串 | |||||
| sb.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3)); | sb.append(Integer.toHexString((b & 0xFF) | 0x100).substring(1, 3)); | ||||
| } | } | ||||
| // 返回加密后的字符串 | |||||
| return sb.toString(); | return sb.toString(); | ||||
| } catch (java.security.NoSuchAlgorithmException e) { | } catch (java.security.NoSuchAlgorithmException e) { | ||||
| // 如果在获取 MD5 加密对象时出现了错误,则打印错误信息 | |||||
| e.printStackTrace(); | e.printStackTrace(); | ||||
| } | } | ||||
| // 如果出现了错误,则返回 null | |||||
| return null; | return null; | ||||
| } | } | ||||
| // 这是一个 decode 方法,用于将 runIds 列表转换为查询字符串 | |||||
| public static String decode(List<String> runIds) { | public static String decode(List<String> runIds) { | ||||
| // 确保 runIds 列表的大小为 3 | // 确保 runIds 列表的大小为 3 | ||||
| if (runIds == null || runIds.size() == 0) { | if (runIds == null || runIds.size() == 0) { | ||||
| // 如果 runIds 为空,抛出 IllegalArgumentException 异常 | |||||
| throw new IllegalArgumentException("runIds 不能为空"); | throw new IllegalArgumentException("runIds 不能为空"); | ||||
| } | } | ||||
| // 构建查询字符串 | // 构建查询字符串 | ||||
| StringBuilder queryBuilder = new StringBuilder("run.hash in ["); | StringBuilder queryBuilder = new StringBuilder("run.hash in ["); | ||||
| // 遍历 runIds 列表 | |||||
| for (int i = 0; i < runIds.size(); i++) { | for (int i = 0; i < runIds.size(); i++) { | ||||
| // 如果当前不是第一个元素,添加逗号 | |||||
| if (i > 0) { | if (i > 0) { | ||||
| queryBuilder.append(","); | queryBuilder.append(","); | ||||
| } | } | ||||
| // 将当前元素添加到查询字符串中,使用双引号括起来 | |||||
| queryBuilder.append("\"").append(runIds.get(i)).append("\""); | queryBuilder.append("\"").append(runIds.get(i)).append("\""); | ||||
| } | } | ||||
| // 将查询字符串闭合 | |||||
| queryBuilder.append("]"); | queryBuilder.append("]"); | ||||
| // 将查询字符串转换为字符串 | |||||
| String query = queryBuilder.toString(); | String query = queryBuilder.toString(); | ||||
| // 创建一个 Map 对象,用于存储查询参数 | |||||
| Map<String, Object> map = new HashMap<>(); | Map<String, Object> map = new HashMap<>(); | ||||
| // 将查询字符串添加到 Map 中 | |||||
| map.put("query", query); | map.put("query", query); | ||||
| // 将 advancedMode 设置为 true | |||||
| map.put("advancedMode", true); | map.put("advancedMode", true); | ||||
| // 将 advancedQuery 设置为查询字符串 | |||||
| map.put("advancedQuery", query); | map.put("advancedQuery", query); | ||||
| // 使用 encode 方法将 Map 对象转换为查询字符串 | |||||
| String searchQuery = encode(map, false); | String searchQuery = encode(map, false); | ||||
| // 返回查询字符串 | |||||
| return searchQuery; | return searchQuery; | ||||
| } | } | ||||
| } | } | ||||
| @@ -9,19 +9,30 @@ import java.util.Set; | |||||
| public class BeansUtils { | public class BeansUtils { | ||||
| // 获取一个 Java 对象中所有为空的属性名称。: | |||||
| public static String[] getNullPropertyNames(Object source) { | public static String[] getNullPropertyNames(Object source) { | ||||
| // 创建一个 BeanWrapper 对象,参数为给定的 Java 对象 | |||||
| final BeanWrapper src = new BeanWrapperImpl(source); | final BeanWrapper src = new BeanWrapperImpl(source); | ||||
| // 获取该对象所有属性描述符 | |||||
| java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); | java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); | ||||
| // 创建一个集合,用于存储为空的属性名称 | |||||
| Set<String> emptyNames = new HashSet<String>(); | Set<String> emptyNames = new HashSet<String>(); | ||||
| // 遍历所有属性描述符 | |||||
| for(java.beans.PropertyDescriptor pd : pds) { | for(java.beans.PropertyDescriptor pd : pds) { | ||||
| // 获取属性值 | |||||
| Object srcValue = src.getPropertyValue(pd.getName()); | Object srcValue = src.getPropertyValue(pd.getName()); | ||||
| // 如果属性值为空,则将属性名称添加到集合中 | |||||
| if (srcValue == null) emptyNames.add(pd.getName()); | if (srcValue == null) emptyNames.add(pd.getName()); | ||||
| } | } | ||||
| // 创建一个字符串数组,用于存储为空的属性名称 | |||||
| String[] result = new String[emptyNames.size()]; | String[] result = new String[emptyNames.size()]; | ||||
| // 将为空的属性名称存储到字符串数组中 | |||||
| return emptyNames.toArray(result); | return emptyNames.toArray(result); | ||||
| } | } | ||||
| public static void copyPropertiesIgnoreNull(Object src, Object target){ | public static void copyPropertiesIgnoreNull(Object src, Object target){ | ||||
| // 使用 BeanUtils 工具类将源对象中的非空属性复制到目标对象中 | |||||
| BeanUtils.copyProperties(src, target, getNullPropertyNames(src)); | BeanUtils.copyProperties(src, target, getNullPropertyNames(src)); | ||||
| } | } | ||||
| } | } | ||||
| @@ -19,6 +19,13 @@ import java.util.List; | |||||
| public class ConvertUtil { | public class ConvertUtil { | ||||
| public static final Logger logger = LoggerFactory.getLogger(ConvertUtil.class); | public static final Logger logger = LoggerFactory.getLogger(ConvertUtil.class); | ||||
| /** | |||||
| * 将实体对象转换为VO对象 | |||||
| * @param source 源实体对象 | |||||
| * @param target 目标VO对象的类 | |||||
| * @return 转换后的VO对象 | |||||
| */ | |||||
| public static <T> T entityToVo(Object source, Class<T> target) { | public static <T> T entityToVo(Object source, Class<T> target) { | ||||
| if (source == null) { | if (source == null) { | ||||
| return null; | return null; | ||||
| @@ -33,6 +40,8 @@ public class ConvertUtil { | |||||
| return targetObject; | return targetObject; | ||||
| } | } | ||||
| // 将实体对象列表转换为目标类型的列表 | |||||
| public static <T> List<T> entityToVoList(Collection<?> sourceList, Class<T> target) { | public static <T> List<T> entityToVoList(Collection<?> sourceList, Class<T> target) { | ||||
| if (sourceList == null) { | if (sourceList == null) { | ||||
| return null; | return null; | ||||
| @@ -50,5 +59,6 @@ public class ConvertUtil { | |||||
| } | } | ||||
| return targetList; | return targetList; | ||||
| } | } | ||||
| } | } | ||||
| @@ -2,20 +2,29 @@ package com.ruoyi.platform.utils; | |||||
| public class FileUtil { | public class FileUtil { | ||||
| // 格式化文件大小为可读的字符串表示 | |||||
| public static String formatFileSize(long sizeInBytes) { | public static String formatFileSize(long sizeInBytes) { | ||||
| // 检查文件大小是否为负数 | |||||
| if (sizeInBytes < 0) { | if (sizeInBytes < 0) { | ||||
| throw new IllegalArgumentException("File size cannot be negative."); | throw new IllegalArgumentException("File size cannot be negative."); | ||||
| } | } | ||||
| // 如果文件大小小于1KB,直接返回字节数 | |||||
| if (sizeInBytes < 1024) { | if (sizeInBytes < 1024) { | ||||
| return sizeInBytes + " B"; | return sizeInBytes + " B"; | ||||
| } else if (sizeInBytes < 1024 * 1024) { | |||||
| } | |||||
| // 如果文件大小小于1MB,转换为KB并返回 | |||||
| else if (sizeInBytes < 1024 * 1024) { | |||||
| double sizeInKB = sizeInBytes / 1024.0; | double sizeInKB = sizeInBytes / 1024.0; | ||||
| return String.format("%.2f KB", sizeInKB); | return String.format("%.2f KB", sizeInKB); | ||||
| } else if (sizeInBytes < 1024 * 1024 * 1024) { | |||||
| } | |||||
| // 如果文件大小小于1GB,转换为MB并返回 | |||||
| else if (sizeInBytes < 1024 * 1024 * 1024) { | |||||
| double sizeInMB = sizeInBytes / (1024.0 * 1024); | double sizeInMB = sizeInBytes / (1024.0 * 1024); | ||||
| return String.format("%.2f MB", sizeInMB); | return String.format("%.2f MB", sizeInMB); | ||||
| } else { | |||||
| } | |||||
| // 如果文件大小大于或等于1GB,转换为GB并返回 | |||||
| else { | |||||
| double sizeInGB = sizeInBytes / (1024.0 * 1024 * 1024); | double sizeInGB = sizeInBytes / (1024.0 * 1024 * 1024); | ||||
| return String.format("%.2f GB", sizeInGB); | return String.format("%.2f GB", sizeInGB); | ||||
| } | } | ||||
| @@ -37,10 +37,8 @@ public class JsonUtils { | |||||
| // 将JSON字符串转换为扁平化的Map | // 将JSON字符串转换为扁平化的Map | ||||
| public static Map<String, Object> flattenJson(String prefix, Map<String, Object> map) { | public static Map<String, Object> flattenJson(String prefix, Map<String, Object> map) { | ||||
| Map<String, Object> flatMap = new HashMap<>(); | Map<String, Object> flatMap = new HashMap<>(); | ||||
| Iterator<Map.Entry<String, Object>> entries = map.entrySet().iterator(); | |||||
| while (entries.hasNext()) { | |||||
| Map.Entry<String, Object> entry = entries.next(); | |||||
| for (Map.Entry<String, Object> entry : map.entrySet()) { | |||||
| String key = entry.getKey(); | String key = entry.getKey(); | ||||
| Object value = entry.getValue(); | Object value = entry.getValue(); | ||||
| @@ -375,7 +375,7 @@ public class K8sClientUtil { | |||||
| return service.getSpec().getPorts().get(0).getNodePort(); | return service.getSpec().getPorts().get(0).getNodePort(); | ||||
| } | } | ||||
| // 创建配置好的Pod | |||||
| public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, String image, String dataPvcName, String datasetPath, String modelPath) { | public Integer createConfiguredPod(String podName, String namespace, Integer port, String mountPath, V1PersistentVolumeClaim pvc, String image, String dataPvcName, String datasetPath, String modelPath) { | ||||
| Map<String, String> selector = new LinkedHashMap<>(); | Map<String, String> selector = new LinkedHashMap<>(); | ||||
| selector.put("k8s-jupyter", podName); | selector.put("k8s-jupyter", podName); | ||||