package com.iailab.module.model.matlab.service.impl; import cn.hutool.cache.CacheUtil; import cn.hutool.cache.impl.FIFOCache; import cn.hutool.core.io.FileUtil; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.iailab.framework.common.exception.enums.GlobalErrorCodeConstants; import com.iailab.framework.common.page.PageData; import com.iailab.framework.common.pojo.CommonResult; import com.iailab.framework.common.service.impl.BaseServiceImpl; import com.iailab.framework.common.util.object.ConvertUtils; import com.iailab.framework.security.core.util.SecurityFrameworkUtils; import com.iailab.framework.tenant.core.context.TenantContextHolder; import com.iailab.module.model.common.utils.DateUtils; import com.iailab.module.model.matlab.common.exceptions.IllegalityJarException; import com.iailab.module.model.matlab.common.utils.MatlabUtils; import com.iailab.module.model.matlab.dao.MlModelDao; import com.iailab.module.model.matlab.dto.MatlabJarFileInfoDTO; import com.iailab.module.model.matlab.dto.MatlabRunDTO; import com.iailab.module.model.matlab.dto.MlModelDTO; import com.iailab.module.model.matlab.entity.MlModelEntity; import com.iailab.module.model.matlab.service.MlModelMethodService; import com.iailab.module.model.matlab.service.MlModelService; import com.iailab.module.model.mpk.common.MdkConstant; import com.iailab.module.model.mpk.common.utils.Readtxt; import com.mathworks.toolbox.javabuilder.MWStructArray; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.net.URLClassLoader; import java.util.*; import static com.iailab.framework.common.pojo.CommonResult.error; import static com.iailab.framework.common.pojo.CommonResult.success; /** * * * @author Dzd * @since 1.0.0 2025-02-08 */ @Slf4j @Service public class MlModelServiceImpl extends BaseServiceImpl<MlModelDao, MlModelEntity> implements MlModelService { @Value("${matlab.bak-file-path}") private String matlabBakFilePath; @Autowired private MlModelMethodService mlModelMethodService; // å…ˆè¿›å…ˆå‡ºç¼“å˜ ä¸´æ—¶ä¿å˜å¯¼å…¥çš„æ•°æ® private static FIFOCache<String, String> cache = CacheUtil.newFIFOCache(100); @Override public PageData<MlModelDTO> page(Map<String, Object> params) { IPage<MlModelEntity> page = baseDao.selectPage( getPage(params, "create_date", false), getWrapper(params) ); return getPageData(page, MlModelDTO.class); } @Override public List<MlModelDTO> list(Map<String, Object> params) { List<MlModelDTO> list = baseDao.list(params); return list; } private QueryWrapper<MlModelEntity> getWrapper(Map<String, Object> params) { String modelName = (String) params.get("modelName"); String modelFileName = (String) params.get("modelFileName"); QueryWrapper<MlModelEntity> wrapper = new QueryWrapper<>(); wrapper.like(StringUtils.isNotBlank(modelName), "model_name", modelName) .like(StringUtils.isNotBlank(modelFileName), "model_file_name", modelFileName); return wrapper; } @Override public MlModelDTO get(String id) { MlModelDTO entity = baseDao.get(id); return entity; } @Override @DSTransactional(rollbackFor = Exception.class) public void save(MlModelDTO dto) { MlModelEntity entity = ConvertUtils.sourceToTarget(dto, MlModelEntity.class); entity.setId(UUID.randomUUID().toString()); entity.setModelFilePath(dto.getModelFilePath().trim()); entity.setModelFileName(dto.getModelFileName().trim()); entity.setCreator(SecurityFrameworkUtils.getLoginUserId()); entity.setCreateDate(new Date()); insert(entity); mlModelMethodService.insertList(dto.getModelMethods(), entity.getId()); saveJarFile(dto.getModelFilePath(),dto.getModelFileName()); } @Override @DSTransactional(rollbackFor = Exception.class) public void update(MlModelDTO dto) { MlModelEntity entity = ConvertUtils.sourceToTarget(dto, MlModelEntity.class); entity.setUpdater(SecurityFrameworkUtils.getLoginUserId()); entity.setUpdateDate(new Date()); updateById(entity); mlModelMethodService.deleteModelMethod(entity.getId()); mlModelMethodService.insertList(dto.getModelMethods(), entity.getId()); saveJarFile(dto.getModelFilePath(),dto.getModelFileName()); } /** * @description: ä¿å˜æœ€æ–°jar文件,用于测试è¿è¡Œ * @author: dzd * @date: 2025/2/24 16:25 **/ private void saveJarFile(String modelFilePath,String modelFileName) { String matlabTenantBakFilePath = getMatlabTenantBakFilePath(); String jarBakPath = matlabTenantBakFilePath + File.separator + MdkConstant.JAR + File.separator + modelFileName + ".jar"; FileUtil.copy(modelFilePath, jarBakPath, true); } @Override @DSTransactional(rollbackFor = Exception.class) public void delete(String id) { //åˆ é™¤æºæ–‡ä»¶ MlModelEntity MlModelEntity = selectById(id); if (StringUtils.isNoneBlank(MlModelEntity.getModelFilePath())) { File mpkFile = new File(MlModelEntity.getModelFilePath()); if (mpkFile.exists()) { mpkFile.delete(); log.info("åˆ é™¤æºæ–‡ä»¶å¤‡ä»½æ–‡ä»¶ï¼š" + MlModelEntity.getModelFilePath()); } } //åˆ é™¤ 会级è”åˆ é™¤æŽ‰å…³è”表 deleteById(id); } @Override public MatlabJarFileInfoDTO uploadJarFile(MultipartFile file) throws IllegalityJarException { String matlabTenantBakFilePath = getMatlabTenantBakFilePath(); File bakDir = new File(matlabTenantBakFilePath); String jarName = null; File jarBakFile = null; try { String fileName = file.getOriginalFilename(); jarName = fileName.substring(0, fileName.lastIndexOf(".")); String pyName_time = jarName + "_" + DateUtils.format(new Date(),DateUtils.DATE_TIME_STRING); jarBakFile = new File(bakDir.getAbsolutePath() + File.separator + pyName_time + ".jar"); file.transferTo(jarBakFile); } catch (IOException e) { throw new RuntimeException("ä¿å˜ç®—法å°è£…jar文件失败ï¼"); } //解æžjar info MatlabJarFileInfoDTO result = new MatlabJarFileInfoDTO(); result.setFilePath(jarBakFile.getAbsolutePath()); result.setFileName(jarName); result.setClassInfos(MatlabUtils.parseJarInfo(jarBakFile.getAbsolutePath(),jarName)); return result; } @Override public CommonResult<String> test(MatlabRunDTO dto) { String matlabTenantBakFilePath = getMatlabTenantBakFilePath(); Class<?> clazz; URLClassLoader classLoader; try { File jarFile = new File(matlabTenantBakFilePath + File.separator + MdkConstant.JAR + File.separator + dto.getModelFileName() + ".jar"); if (!jarFile.exists()) { throw new RuntimeException("jar包ä¸å˜åœ¨ï¼Œè¯·æ£€æŸ¥ã€‚jarPath:" + jarFile.getAbsolutePath()); } // åŠ è½½jar包 classLoader = MatlabUtils.loadJar(null,jarFile.getAbsolutePath()); // 实现类 clazz = classLoader.loadClass(dto.getClassName()); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("åŠ è½½è¿è¡ŒçŽ¯å¢ƒå¤±è´¥ã€‚"); } try { List<String> uuids = dto.getUuids(); Object[] paramsValueArray = new Object[uuids.size() + 1]; try { for (int i = 0; i < uuids.size(); i++) { String uuid = uuids.get(i); if (!cache.containsKey(uuid)) { return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"请é‡æ–°å¯¼å…¥æ¨¡åž‹å‚æ•°"); } JSONArray jsonArray = JSON.parseArray(cache.get(uuid)); double[][] data = new double[jsonArray.size()][jsonArray.getJSONArray(0).size()]; for (int j = 0; j < jsonArray.size(); j++) { for (int k = 0; k < jsonArray.getJSONArray(j).size(); k++) { data[j][k] = jsonArray.getJSONArray(j).getDoubleValue(k); } } paramsValueArray[i] = data; } } catch (Exception e) { e.printStackTrace(); return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"模型å‚数错误,请检查ï¼"); } MWStructArray mwStructArraySetting; try { HashMap<String, Object> settings = MatlabUtils.handleModelSettings(dto.getModelSettings()); mwStructArraySetting = MatlabUtils.convertMapToStruct(settings); paramsValueArray[uuids.size()] = mwStructArraySetting; } catch (Exception e) { e.printStackTrace(); return error(GlobalErrorCodeConstants.BAD_REQUEST.getCode(),"模型设置错误,请检查ï¼"); } Class<?>[] paramsArray = new Class[2]; paramsArray[0] = int.class; paramsArray[1] = Object[].class; Object[] objects = (Object[]) clazz.getDeclaredMethod(dto.getMethodName(), paramsArray).invoke(clazz.newInstance(), new Object[]{dto.getOutLength(), paramsValueArray}); mwStructArraySetting.dispose(); Map<String, Object> result = MatlabUtils.convertStructToMap((MWStructArray) objects[0]); return success(JSON.toJSONString(result)); } catch (Exception ex) { ex.printStackTrace(); return error(GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),"è¿è¡Œå¼‚常"); } finally { if (classLoader != null) { MatlabUtils.unloadJar(classLoader); } } } @Override public List<HashMap<String, Object>> importData(MultipartFile file) throws IOException { List<double[][]> datas = Readtxt.readMethodExcel(file); List<HashMap<String,Object>> result = new ArrayList<>(); if (!CollectionUtils.isEmpty(datas)) { for (double[][] data : datas) { if (data.length > 0) { HashMap<String,Object> map = new HashMap<>(); String uuid = UUID.randomUUID().toString(); map.put("uuid",uuid); map.put("data", JSON.toJSONString(data)); cache.put(uuid,JSON.toJSONString(data)); result.add(map); } } } return result; } private String getMatlabTenantBakFilePath() { Long tenantId = TenantContextHolder.getTenantId(); // 备份文件夹 租户隔离 String matlabTenantBakFilePath = matlabBakFilePath + File.separator + tenantId; File bakDir = new File(matlabTenantBakFilePath); if (!bakDir.exists()) { bakDir.mkdirs(); } return matlabTenantBakFilePath; } }