潘志宝
2024-12-12 bd90850664bfe4b43df094321e811f3bb398f97f
提交 | 用户 | 时间
449017 1 package com.iailab.module.model.mpk.service.impl;
D 2
3 import cn.hutool.core.io.FileUtil;
4 import cn.hutool.core.util.ZipUtil;
5 import com.alibaba.fastjson.JSON;
8b3ee3 6 import com.baomidou.dynamic.datasource.annotation.DSTransactional;
449017 7 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
D 8 import com.baomidou.mybatisplus.core.metadata.IPage;
9 import com.iailab.framework.common.page.PageData;
c12dae 10 import com.iailab.framework.common.pojo.CommonResult;
449017 11 import com.iailab.framework.common.service.impl.BaseServiceImpl;
D 12 import com.iailab.framework.common.util.date.DateUtils;
13 import com.iailab.framework.common.util.object.ConvertUtils;
14 import com.iailab.framework.security.core.util.SecurityFrameworkUtils;
558ffc 15 import com.iailab.framework.tenant.core.context.TenantContextHolder;
449017 16 import com.iailab.module.infra.api.config.ConfigApi;
D 17 import com.iailab.module.model.mpk.common.MdkConstant;
011e9e 18 import com.iailab.module.model.mpk.common.utils.CmdUtils;
c12dae 19 import com.iailab.module.model.mpk.common.utils.DllUtils;
449017 20 import com.iailab.module.model.mpk.common.utils.GenUtils;
D 21 import com.iailab.module.model.mpk.dao.MpkFileDao;
1fea3e 22 import com.iailab.module.model.mpk.dto.GeneratorCodeHistoryDTO;
0425a3 23 import com.iailab.module.model.mpk.dto.MethodSettingDTO;
1fea3e 24 import com.iailab.module.model.mpk.dto.ModelMethodDTO;
D 25 import com.iailab.module.model.mpk.dto.MpkFileDTO;
26 import com.iailab.module.model.mpk.entity.GeneratorCodeHistoryEntity;
27 import com.iailab.module.model.mpk.entity.MpkFileEntity;
558ffc 28 import com.iailab.module.model.mpk.entity.ProjectPackageHistoryEntity;
1fea3e 29 import com.iailab.module.model.mpk.entity.ProjectPackageHistoryModelEntity;
449017 30 import com.iailab.module.model.mpk.service.*;
D 31 import lombok.extern.slf4j.Slf4j;
32 import org.apache.commons.io.FileUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.apache.velocity.VelocityContext;
35 import org.apache.velocity.app.Velocity;
36 import org.springframework.beans.factory.annotation.Autowired;
a27351 37 import org.springframework.beans.factory.annotation.Value;
449017 38 import org.springframework.stereotype.Service;
D 39 import org.springframework.util.CollectionUtils;
40 import org.springframework.web.multipart.MultipartFile;
41
011e9e 42 import java.io.File;
D 43 import java.io.IOException;
c12dae 44 import java.net.URLClassLoader;
912a1e 45 import java.nio.file.Files;
449017 46 import java.util.*;
011e9e 47 import java.util.function.Function;
449017 48 import java.util.stream.Collectors;
D 49
50 /**
51  * @author PanZhibao
52  * @Description
53  * @createTime 2024年08月14日
54  */
55 @Slf4j
56 @Service
0255ea 57 public class MpkFileServiceImpl extends BaseServiceImpl<MpkFileDao, MpkFileEntity> implements MpkFileService {
449017 58
D 59     @Autowired
60     private GeneratorCodeHistoryService generatorCodeHistoryService;
8b3ee3 61
449017 62     @Autowired
D 63     private ProjectPackageHistoryService projectPackageHistoryService;
8b3ee3 64
449017 65     @Autowired
D 66     private ModelMethodService modelMethodService;
8b3ee3 67
449017 68     @Autowired
D 69     private ProjectPackageHistoryModelService projectPackageHistoryModelService;
70
71     @Autowired
72     private ConfigApi configApi;
73
1fea3e 74     @Value("${mpk.bak-file-path}")
a27351 75     private String mpkBakFilePath;
1fea3e 76
D 77     @Value("${mpk.bak-resources}")
78     private String mpkResources;
449017 79
D 80     @Override
81     public PageData<MpkFileDTO> page(Map<String, Object> params) {
82         IPage<MpkFileEntity> page = baseDao.selectPage(
83                 getPage(params, "create_date", false),
84                 getWrapper(params)
85         );
86
87         return getPageData(page, MpkFileDTO.class);
88     }
89
90     @Override
91     public List<MpkFileDTO> list(Map<String, Object> params) {
4f4b05 92 //        List<MpkFileEntity> entityList = baseDao.selectList(getWrapper(params).orderByDesc("create_date"));
D 93         List<MpkFileDTO> list = baseDao.list(params);
449017 94
4f4b05 95         return list;
449017 96     }
D 97
8b3ee3 98     private QueryWrapper<MpkFileEntity> getWrapper(Map<String, Object> params) {
2c7af4 99         String pyChineseName = (String) params.get("pyChineseName");
449017 100         String pyName = (String) params.get("pyName");
D 101         String pyType = (String) params.get("pyType");
102         String remark = (String) params.get("remark");
d8db4b 103         String label = (String) params.get("label");
449017 104
D 105         QueryWrapper<MpkFileEntity> wrapper = new QueryWrapper<>();
2c7af4 106         wrapper.like(StringUtils.isNotBlank(pyChineseName), "py_chinese_name", pyChineseName)
107                 .like(StringUtils.isNotBlank(pyName), "py_name", pyName)
449017 108                 .eq(StringUtils.isNotBlank(pyType), "py_type", pyType)
D 109                 .like(StringUtils.isNotBlank(remark), "remark", remark);
d8db4b 110
111         if (StringUtils.isNotBlank(label)) {
112             wrapper.and(w -> {
113                 w.eq(StringUtils.isNotBlank(label),"menu_name", label)
114                         .or().eq(StringUtils.isNotBlank(label),"group_name", label);
115             });
116         }
449017 117         return wrapper;
D 118     }
119
120     @Override
121     public MpkFileDTO get(String id) {
122         MpkFileDTO entity = baseDao.get(id);
123
124         return entity;
125     }
126
127     @Override
8b3ee3 128     @DSTransactional(rollbackFor = Exception.class)
449017 129     public void save(MpkFileDTO dto) {
D 130         MpkFileEntity entity = ConvertUtils.sourceToTarget(dto, MpkFileEntity.class);
8b3ee3 131         entity.setId(UUID.randomUUID().toString());
ed8ba3 132         entity.setPkgName(dto.getPkgName().trim());
133         entity.setFilePath(dto.getFilePath().trim());
449017 134         entity.setCreator(SecurityFrameworkUtils.getLoginUserId());
D 135         entity.setCreateDate(new Date());
136         insert(entity);
bb0155 137
0425a3 138         // 将备份的pyd文件,转移到MDK_PKGS环境变量下,并添加方法的默认参数(pyFile,模型路径)
D 139         String mdkPkgs = System.getenv("MDK_PKGS");
140         String fileName = entity.getFilePath().substring(entity.getFilePath().lastIndexOf("\\") + 1,entity.getFilePath().lastIndexOf(".pyd"));
141
142         String pyFilePath = mdkPkgs + File.separator + entity.getPyModule().replace(".", File.separator) + File.separator + fileName + ".pyd";
143         FileUtil.mkParentDirs(pyFilePath);
144         FileUtil.copy(entity.getFilePath(), pyFilePath, true);
145
146         // 添加参数
147         for (ModelMethodDTO method : dto.getModelMethods()) {
148             List<MethodSettingDTO> methodSettings = method.getMethodSettings();
149             if (methodSettings.stream().anyMatch(e -> e.getSettingKey().equals(MdkConstant.PY_FILE_KEY))) {
150                 methodSettings.forEach(e -> {
151                     if (e.getSettingKey().equals(MdkConstant.PY_FILE_KEY)) {
152                         e.setValue(entity.getPyModule() + "." + fileName);
153                     }
154                 });
155             }else {
156                 MethodSettingDTO setting = new MethodSettingDTO();
157                 setting.setId(UUID.randomUUID().toString());
158                 setting.setMethodId(method.getId());
159                 setting.setSettingKey(MdkConstant.PY_FILE_KEY);
160                 setting.setValue(entity.getPyModule() + "." + fileName);
161                 setting.setName("模型路径");
162                 setting.setType("input");
163                 setting.setValueType("string");
164                 methodSettings.add(setting);
165             }
166         }
167
168         modelMethodService.insertList(dto.getModelMethods(), entity.getId());
449017 169     }
D 170
171     @Override
8b3ee3 172     @DSTransactional(rollbackFor = Exception.class)
449017 173     public void update(MpkFileDTO dto) {
784ce3 174         // 添加方法的默认参数(pyFile,模型路径)
D 175         String mdkPkgs = System.getenv("MDK_PKGS");
176         String fileName = dto.getFilePath().substring(dto.getFilePath().lastIndexOf("\\") + 1,dto.getFilePath().lastIndexOf(".pyd"));
177         String pyFilePath = mdkPkgs + File.separator + dto.getPyModule().replace(".", File.separator) + File.separator + fileName + ".pyd";
178         // 判断文件是否存在,不存在的话将备份的pyd文件,转移到MDK_PKGS环境变量下
179         File pyFile = new File(pyFilePath);
180         if (!pyFile.exists()) {
0425a3 181             FileUtil.mkParentDirs(pyFilePath);
D 182             FileUtil.copy(dto.getFilePath(), pyFilePath, true);
784ce3 183         }
0425a3 184
784ce3 185         // 添加/修改参数
D 186         for (ModelMethodDTO method : dto.getModelMethods()) {
187             List<MethodSettingDTO> methodSettings = method.getMethodSettings();
188             if (methodSettings.stream().anyMatch(e -> e.getSettingKey().equals(MdkConstant.PY_FILE_KEY))) {
189                 methodSettings.forEach(e -> {
190                     if (e.getSettingKey().equals(MdkConstant.PY_FILE_KEY)) {
191                         e.setValue(dto.getPyModule() + "." + fileName);
192                     }
193                 });
194             }else {
195                 MethodSettingDTO setting = new MethodSettingDTO();
196                 setting.setId(UUID.randomUUID().toString());
197                 setting.setMethodId(method.getId());
198                 setting.setSettingKey(MdkConstant.PY_FILE_KEY);
199                 setting.setValue(dto.getPyModule() + "." + fileName);
200                 setting.setName("模型路径");
201                 setting.setType("input");
202                 setting.setValueType("string");
203                 methodSettings.add(setting);
0425a3 204             }
D 205         }
206
449017 207         MpkFileEntity entity = ConvertUtils.sourceToTarget(dto, MpkFileEntity.class);
D 208         entity.setUpdater(SecurityFrameworkUtils.getLoginUserId());
209         entity.setUpdateDate(new Date());
210         updateById(entity);
8b3ee3 211         modelMethodService.deleteModelMethod(entity.getId());
212         modelMethodService.insertList(dto.getModelMethods(), entity.getId());
449017 213     }
D 214
215     @Override
8b3ee3 216     @DSTransactional(rollbackFor = Exception.class)
449017 217     public void delete(String id) {
D 218
219         //删除源文件
220         MpkFileEntity mpkFileEntity = selectById(id);
221         if (StringUtils.isNoneBlank(mpkFileEntity.getFilePath())) {
222             File mpkFile = new File(mpkFileEntity.getFilePath());
223             if (mpkFile.exists()) {
224                 mpkFile.delete();
225                 log.info("删除源文件备份文件:" + mpkFileEntity.getFilePath());
226             }
227         }
228
229         //删除备份文件
8b3ee3 230         Map<String, Object> map1 = new HashMap<>();
231         map1.put("mdkId", id);
449017 232         List<GeneratorCodeHistoryDTO> list = generatorCodeHistoryService.list(map1);
D 233         list.forEach(e -> {
234             File file = new File(e.getFilePath());
235             if (file.exists()) {
236                 file.delete();
237                 log.info("删除生成代码备份文件:" + e.getFilePath());
238             }
239         });
240
0255ea 241         //删除 会级联删除掉关联表
D 242         deleteById(id);
449017 243     }
D 244
245     @Override
246     public byte[] generatorCode(String id, String remark, String zipFileName) {
558ffc 247         Long tenantId = TenantContextHolder.getTenantId();
D 248         // 备份文件 租户隔离
249         String mpkTenantBakFilePath = mpkBakFilePath + File.separator + tenantId;
250
449017 251         MpkFileDTO entity = baseDao.get(id);
D 252         //生成代码
1fea3e 253         //设置velocity资源加载器
D 254         Properties prop = new Properties();
255         prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
256         Velocity.init(prop);
449017 257
1fea3e 258         //封装模板数据
D 259         Map<String, Object> map = new HashMap<>();
260         map.put("pkgName",entity.getPkgName());
261         map.put("modelMethods",entity.getModelMethods());
262         map.put("pyName",entity.getPyName());
263         map.put("pyModule",entity.getPyModule());
264
265         VelocityContext dataContext = new VelocityContext(map);
266
267         //临时文件夹
912a1e 268         File dirPath = null;
D 269         try {
270             dirPath = Files.createTempDirectory("generatorCodeTmp").toFile();
271             log.info("生成临时文件夹," + dirPath.getAbsolutePath());
272         } catch (IOException e) {
273             throw new RuntimeException("创建临时文件夹异常",e);
274         }
1fea3e 275
D 276         List<String> javaFilePaths = new ArrayList<>();
277
278         //生成java文件
011e9e 279         File javaFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.IAILMDK + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + entity.getPyName() + ".java");
1fea3e 280         GenUtils.drawTemplate("abstract.java.vm", dataContext, javaFile);
D 281         javaFilePaths.add(javaFile.getAbsolutePath());
282
283         //生成Impl.java文件
011e9e 284         File implJavaFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.IAILMDK + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + MdkConstant.IMPL + File.separator + entity.getPyName() + "Impl.java");
1fea3e 285         GenUtils.drawTemplate("impl.java.vm", dataContext, implJavaFile);
D 286         javaFilePaths.add(implJavaFile.getAbsolutePath());
287
288         //生成.cpp文件
289         File cppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".cpp");
290         GenUtils.drawTemplate("cpp.vm", dataContext, cppFile);
291
292         //生成Jni.cpp文件
293         File jniCppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.cpp");
294         GenUtils.drawTemplate("Jni.cpp.vm", dataContext, jniCppFile);
295
296         //生成.h文件
297         File hFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".h");
298         GenUtils.drawTemplate("h.vm", dataContext, hFile);
299
300         //生成Jni.h文件
301         File jniHFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.h");
302         GenUtils.drawTemplate("Jni.h.vm", dataContext, jniHFile);
a8c6a6 303
D 304         // 添加python源文件
8c86a9 305         String pyFilePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.ALGS + File.separator + entity.getPyModule().replace(".", File.separator) + File.separator + entity.getFilePath().substring(entity.getFilePath().lastIndexOf("\\"));
a8c6a6 306         FileUtil.mkParentDirs(pyFilePath);
D 307         FileUtil.copy(entity.getFilePath(), pyFilePath, true);
1fea3e 308
D 309         // 资源文件
310         FileUtil.copy(mpkResources + File.separator + "libs", dirPath.getAbsolutePath(), true);
311
312         //生成dll文件
313         String dllSavePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.LIBS + File.separator + "IAIL.MDK.Mid.Jni.dll";
011e9e 314         createDllFile(dirPath.getAbsolutePath(),dllSavePath);
1fea3e 315         //备份dll文件,用于后续运行
558ffc 316         String dllBakPath = mpkTenantBakFilePath + File.separator + MdkConstant.DLL + File.separator + entity.getPyName() + ".dll";
1fea3e 317         FileUtil.mkParentDirs(dllBakPath);
D 318         FileUtil.copy(dllSavePath, dllBakPath, true);
319
320         //utils + env java文件
011e9e 321         File utilsJavaFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.IAILMDK + File.separator + "iail" + File.separator + "mdk" + File.separator + "model" + File.separator + "utils" + File.separator + "AlgsUtils.java");
1fea3e 322         FileUtil.mkParentDirs(utilsJavaFile);
D 323         FileUtil.copy(mpkResources + File.separator +"IAILMDK/utils/AlgsUtils.java", utilsJavaFile.getAbsolutePath(), true);
324         javaFilePaths.add(utilsJavaFile.getAbsolutePath());
011e9e 325         File envJavaFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.IAILMDK + File.separator + "iail" + File.separator + "mdk" + File.separator + "model" + File.separator + "common" + File.separator + "Environment.java");
1fea3e 326         FileUtil.mkParentDirs(envJavaFile);
D 327         FileUtil.copy(mpkResources + File.separator +"IAILMDK/common/Environment.java", envJavaFile.getAbsolutePath(), true);
328         javaFilePaths.add(envJavaFile.getAbsolutePath());
329         // 生成class文件
011e9e 330         createClassFile(dirPath.getAbsolutePath(),javaFilePaths);
1fea3e 331         // 删除java源文件
D 332         deleteJavaFile(javaFilePaths);
333         // 打jar包
334         String jarSavePath = pkgJar(dirPath.getAbsolutePath());
335         //备份jar文件,用于后续运行
558ffc 336         String jarBakPath = mpkTenantBakFilePath + File.separator + MdkConstant.JAR + File.separator + entity.getPyName() + ".jar";
1fea3e 337         FileUtil.mkParentDirs(dllBakPath);
D 338         FileUtil.copy(jarSavePath, jarBakPath, true);
339         // 打zip包
558ffc 340         String zipPath = mpkTenantBakFilePath + File.separator + zipFileName;
1fea3e 341         ZipUtil.zip(dirPath.getAbsolutePath(), zipPath);
D 342         byte[] bytes = FileUtil.readBytes(zipPath);
449017 343
D 344         //代码生成历史记录
345         GeneratorCodeHistoryEntity historyEntity = new GeneratorCodeHistoryEntity();
346         historyEntity.setId(UUID.randomUUID().toString());
347         historyEntity.setMdkId(id);
1fea3e 348         historyEntity.setFileName(zipFileName);
D 349         historyEntity.setFilePath(zipPath);
449017 350         historyEntity.setRemark(remark);
D 351         historyEntity.setCreateTime(new Date());
352         generatorCodeHistoryService.insert(historyEntity);
353
1fea3e 354         // 删除临时文件
3009e2 355         try {
D 356             FileUtils.deleteDirectory(dirPath);
357         } catch (IOException e) {
912a1e 358             throw new RuntimeException("删除临时文件异常",e);
3009e2 359         }
1fea3e 360         return bytes;
449017 361     }
D 362
363     @Override
8b3ee3 364     @DSTransactional(rollbackFor = Exception.class)
94c169 365     public byte[] packageModel(String projectId, String projectName, String zipFileName, String logs, String version) throws IOException {
558ffc 366         Long tenantId = TenantContextHolder.getTenantId();
D 367         // 备份文件 租户隔离
368         String mpkTenantBakFilePath = mpkBakFilePath + File.separator + tenantId;
369
94c169 370         List<MpkFileDTO> entities = baseDao.selectByProjectId(projectId);
449017 371
D 372         //模板数据
1fea3e 373 //        Map<String, Object> map = new HashMap<>();
D 374 //        map.put("entities", entities);
375 //        VelocityContext context = new VelocityContext(map);
449017 376
D 377         //临时文件夹
912a1e 378         File dirPath = null;
D 379         try {
380             dirPath = Files.createTempDirectory("packageModelTmp").toFile();
381             log.info("生成临时文件夹," + dirPath.getAbsolutePath());
382         } catch (IOException e) {
383             throw new RuntimeException("创建临时文件夹异常",e);
384         }
449017 385
D 386         //设置velocity资源加载器
387         Properties prop = new Properties();
388         prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
389         Velocity.init(prop);
390
a27351 391         //生成menu.xml文件
2cc235 392         LinkedHashMap<String, LinkedHashMap<String, List<MpkFileDTO>>> collect = entities.stream().collect(Collectors.groupingBy(MpkFileDTO::getMenuName, LinkedHashMap::new, Collectors.groupingBy(e -> StringUtils.isNotBlank(e.getGroupName()) ? e.getGroupName() : "default_group",LinkedHashMap::new,Collectors.toList())));
a27351 393         Map<String, Object> map1 = new HashMap<>();
8b3ee3 394         map1.put("collects", collect);
c7009e 395         File xmlFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.LIBS + File.separator + "menu.xml");
8b3ee3 396         GenUtils.drawTemplate("menu.xml.vm", new VelocityContext(map1), xmlFile);
449017 397
D 398         List<String> javaFilePaths = new ArrayList<>();
399
400         //生成java文件
401         for (MpkFileDTO entity : entities) {
402             //封装模板数据
403             Map<String, Object> data = new HashMap<>();
8b3ee3 404             data.put("pkgName", entity.getPkgName());
405             data.put("modelMethods", entity.getModelMethods());
406             data.put("pyName", entity.getPyName());
407             data.put("pyModule", entity.getPyModule());
449017 408             VelocityContext dataContext = new VelocityContext(data);
D 409             //生成java文件
011e9e 410             File javaFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.IAILMDK + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + entity.getPyName() + ".java");
8b3ee3 411             GenUtils.drawTemplate("abstract.java.vm", dataContext, javaFile);
449017 412             javaFilePaths.add(javaFile.getAbsolutePath());
D 413
414             //生成Impl.java文件
011e9e 415             File implJavaFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.IAILMDK + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + MdkConstant.IMPL + File.separator + entity.getPyName() + "Impl.java");
8b3ee3 416             GenUtils.drawTemplate("impl.java.vm", dataContext, implJavaFile);
449017 417             javaFilePaths.add(implJavaFile.getAbsolutePath());
D 418
f7932f 419             //生成.cpp文件
D 420             File cppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".cpp");
421             GenUtils.drawTemplate("cpp.vm", dataContext, cppFile);
422
423             //生成Jni.cpp文件
424             File jniCppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.cpp");
425             GenUtils.drawTemplate("Jni.cpp.vm", dataContext, jniCppFile);
426
427             //生成.h文件
428             File hFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".h");
429             GenUtils.drawTemplate("h.vm", dataContext, hFile);
430
431             //生成Jni.h文件
432             File jniHFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.h");
433             GenUtils.drawTemplate("Jni.h.vm", dataContext, jniHFile);
434
449017 435             // 添加python源文件
8c86a9 436             String pyFilePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.ALGS + File.separator + entity.getPyModule().replace(".", File.separator) + File.separator + entity.getFilePath().substring(entity.getFilePath().lastIndexOf("\\"));
449017 437             FileUtil.mkParentDirs(pyFilePath);
8b3ee3 438             FileUtil.copy(entity.getFilePath(), pyFilePath, true);
449017 439         }
D 440
1fea3e 441         // 资源文件
D 442         FileUtil.copy(mpkResources + File.separator + "libs", dirPath.getAbsolutePath(), true);
c7009e 443
f7932f 444         //生成dll文件
c7009e 445         String dllSavePath = dirPath.getAbsolutePath() + File.separator + MdkConstant.LIBS + File.separator + "IAIL.MDK.Mid.Jni.dll";
011e9e 446         createDllFile(dirPath.getAbsolutePath(),dllSavePath);
c12dae 447         // 打包历史id
D 448         String historyId = UUID.randomUUID().toString();
449         //备份dll,发布时使用
450         File dllFile = new File(dllSavePath);
451         if (dllFile.exists()) {
558ffc 452             File dllBakFile = new File(mpkBakFilePath + File.separator + MdkConstant.PROJECT_UNPUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".dll");
c12dae 453             FileUtil.copy(dllFile, dllBakFile, true);
D 454         }else {
455             log.error("dll文件不存在,无法备份。" + dllSavePath);
456         }
f7932f 457
449017 458         //utils + env java文件
011e9e 459         File utilsJavaFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.IAILMDK + File.separator + "iail" + File.separator + "mdk" + File.separator + "model" + File.separator + "utils" + File.separator + "AlgsUtils.java");
449017 460         FileUtil.mkParentDirs(utilsJavaFile);
1fea3e 461         FileUtil.copy(mpkResources + File.separator +"IAILMDK/utils/AlgsUtils.java", utilsJavaFile.getAbsolutePath(), true);
449017 462         javaFilePaths.add(utilsJavaFile.getAbsolutePath());
011e9e 463         File envJavaFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.IAILMDK + File.separator + "iail" + File.separator + "mdk" + File.separator + "model" + File.separator + "common" + File.separator + "Environment.java");
449017 464         FileUtil.mkParentDirs(envJavaFile);
1fea3e 465         FileUtil.copy(mpkResources + File.separator +"IAILMDK/common/Environment.java", envJavaFile.getAbsolutePath(), true);
449017 466         javaFilePaths.add(envJavaFile.getAbsolutePath());
D 467         // 生成class文件
011e9e 468         createClassFile(dirPath.getAbsolutePath(),javaFilePaths);
449017 469         // 删除java源文件
D 470         deleteJavaFile(javaFilePaths);
471         // 打jar包
c12dae 472         String jarSavePath = pkgJar(dirPath.getAbsolutePath());
D 473         //备份jar包,发布时使用
474         File jarFile = new File(jarSavePath);
475         if (jarFile.exists()) {
558ffc 476             File jarBakFile = new File(mpkBakFilePath + File.separator + MdkConstant.PROJECT_UNPUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".jar");
c12dae 477             FileUtil.copy(jarFile, jarBakFile, true);
D 478         }else {
479             log.error("jar文件不存在,无法备份。" + jarSavePath);
480         }
481
449017 482         // 本次更新日志
558ffc 483         ProjectPackageHistoryEntity projectPackageHistoryEntity = new ProjectPackageHistoryEntity();
D 484         projectPackageHistoryEntity.setId(historyId);
485         projectPackageHistoryEntity.setProjectId(projectId);
486         projectPackageHistoryEntity.setFileName(zipFileName);
487         projectPackageHistoryEntity.setLog(logs);
488         projectPackageHistoryEntity.setVersion(version);
489         projectPackageHistoryEntity.setModelNames(entities.stream().map(MpkFileDTO::getPyName).collect(Collectors.joining(",")));
490         projectPackageHistoryEntity.setCreateTime(new Date());
449017 491         // 生成更新日志
558ffc 492         createLog(projectId, projectName, dirPath.getAbsolutePath(), projectPackageHistoryEntity, version);
449017 493         // 打zip包
558ffc 494         String zipPath = mpkTenantBakFilePath + File.separator + zipFileName;
8b3ee3 495         ZipUtil.zip(dirPath.getAbsolutePath(), zipPath);
449017 496         byte[] bytes = FileUtil.readBytes(zipPath);
D 497         // 记录打包日志
558ffc 498         projectPackageHistoryEntity.setFilePath(zipPath);
D 499         projectPackageHistoryService.insert(projectPackageHistoryEntity);
449017 500         // 插入打包历史-模型关联表
D 501         List<ProjectPackageHistoryModelEntity> historyModelList = new ArrayList<>(entities.size());
502         entities.forEach(e -> {
503             ProjectPackageHistoryModelEntity entity = new ProjectPackageHistoryModelEntity();
504             entity.setId(UUID.randomUUID().toString());
505             entity.setProjectId(projectId);
506             entity.setPackageHistoryId(historyId);
507             entity.setPyName(e.getPyName());
067d7a 508             entity.setPyChineseName(e.getPyChineseName());
449017 509             entity.setPkgName(e.getPkgName());
D 510             entity.setPyModule(e.getPyModule());
511             entity.setRemark(e.getRemark());
0255ea 512             List<ModelMethodDTO> methods = e.getModelMethods();
449017 513             if (!CollectionUtils.isEmpty(methods)) {
D 514                 entity.setMethodInfo(JSON.toJSONString(methods));
515             }
516             historyModelList.add(entity);
517         });
558ffc 518         projectPackageHistoryModelService.insertList(historyModelList);
449017 519         // 删除临时文件
D 520         FileUtils.deleteDirectory(dirPath);
521         return bytes;
522     }
523
011e9e 524     private void createDllFile(String dirPath, String dllSavePath) {
1fea3e 525         try {
011e9e 526             String command = "cl /LD *.cpp /EHsc /o " + dllSavePath + " /link " + "IAIL.MDK.Mid.Windows.lib";
D 527             CmdUtils.exec(command,dirPath + File.separator + MdkConstant.C);
1fea3e 528         } catch (Exception e) {
912a1e 529             throw new RuntimeException("执行cmd命令生成dll异常",e);
f7932f 530         }
D 531     }
532
449017 533     @Override
8b3ee3 534     public Map<String, String> savePyFile(MultipartFile file) throws IOException {
558ffc 535         Long tenantId = TenantContextHolder.getTenantId();
D 536         // 备份文件 租户隔离
537         String mpkTenantBakFilePath = mpkBakFilePath + File.separator + tenantId;
a8c6a6 538         File bakDir = new File(mpkTenantBakFilePath);
D 539         if (!bakDir.exists()) {
540             bakDir.mkdirs();
541         }
542         //临时文件夹
543         File tempDir = null;
544         try {
545             tempDir = Files.createTempDirectory("pyFileTmp").toFile();
546             log.info("生成临时文件夹," + tempDir.getAbsolutePath());
547         } catch (IOException e) {
548             throw new RuntimeException("创建临时文件夹异常",e);
449017 549         }
D 550         String fileName = file.getOriginalFilename();
a8c6a6 551         String pyName = fileName.substring(0, fileName.lastIndexOf("."));
0425a3 552         String pyName_uuTime = pyName + "_" + new Date().getTime();
D 553
554         File pydBakFile = new File(bakDir.getAbsolutePath() + File.separator + pyName_uuTime + ".pyd");
a8c6a6 555         try {
D 556             // py文件存入临时文件夹
557             File saveFile = new File(tempDir.getAbsolutePath() + File.separator + fileName);
558             saveFile.createNewFile();
559             file.transferTo(saveFile);
560
561             // 临时文件夹中生成pyd文件
562             // 生成setup.py文件
0425a3 563             createSetUpFile(tempDir.getAbsolutePath(),fileName,pyName_uuTime);
a8c6a6 564             // 执行cmd命令编译pyd文件
D 565             createPydFile(tempDir.getAbsolutePath());
566
567             // 临时文件夹中pyd文件移到dir下,修改为uuid.pyd
0425a3 568             File pydFile = new File(tempDir.getAbsolutePath() + File.separator + pyName_uuTime + MdkConstant.PYD_SUFFIX);
a8c6a6 569             if (!pydFile.exists()) {
D 570                 throw new RuntimeException("编译pyd文件失败!");
571             }
572             log.info("备份pyd文件," + pydBakFile.getAbsolutePath());
573             FileUtil.copy(pydFile,pydBakFile,true);
574         } catch (Exception e) {
575             throw new RuntimeException("编译pyd文件异常");
576         } finally {
577             if (tempDir.exists()) {
578                 tempDir.delete();
579             }
580         }
449017 581
8b3ee3 582         Map<String, String> result = new HashMap<>(2);
a8c6a6 583         result.put("filePath", pydBakFile.getAbsolutePath());
D 584         result.put("fileName", pyName);
449017 585
D 586         return result;
587     }
588
a8c6a6 589     private void createPydFile(String dir) {
D 590         try {
591             String command = "python setup.py build_ext --inplace";
592             log.info("执行cmd命令编译pyd:" + command);
011e9e 593             CmdUtils.exec(command,dir);
a8c6a6 594         } catch (Exception e) {
D 595             throw new RuntimeException("执行cmd命令生成dll异常", e);
596         }
597     }
598
599     private void createSetUpFile(String dir, String pyFileName, String pyName) {
600         // 生成setup.py文件
601         HashMap<String,Object> map = new HashMap<>();
602         map.put("fileName",pyFileName);
603         map.put("pyName",pyName);
604         GenUtils.drawTemplate("setup.py.vm",map,new File(dir + File.separator + MdkConstant.SETUP_PY));
605     }
606
c12dae 607     @Override
D 608     public CommonResult<String> publish(Map<String, Object> params) {
609         String historyId = (String) params.get("historyId");
610         String projectId = (String) params.get("projectId");
611
612         // 判断新的dll和jar文件是否存在
558ffc 613         String jarFileBakPath = mpkBakFilePath + File.separator + MdkConstant.PROJECT_UNPUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".jar";
D 614         String dllFileBakPath = mpkBakFilePath + File.separator + MdkConstant.PROJECT_UNPUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".dll";
c12dae 615         if (!FileUtil.exist(jarFileBakPath)) {
D 616             throw new RuntimeException("jar文件不存在," + jarFileBakPath);
617         }
618         if (!FileUtil.exist(dllFileBakPath)) {
619             throw new RuntimeException("dll文件不存在" + dllFileBakPath);
620         }
621
622         try {
623             // 卸载之前的dll和jar
624             DllUtils.removeClassLoaderCache(projectId);
625             // 删除之前的dll和jar备份文件
626             DllUtils.removeOldFile(mpkBakFilePath + File.separator + MdkConstant.PROJECT_PUBLISH,projectId);
627         } catch (Exception e) {
628             throw new RuntimeException("卸载之前的dll和jar异常",e);
629         }
630
631         // 备份新的dll和jar
632         String jarFilePath = mpkBakFilePath + File.separator + MdkConstant.PROJECT_PUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".jar";
633         String dllFilePath = mpkBakFilePath + File.separator + MdkConstant.PROJECT_PUBLISH + File.separator + projectId + MdkConstant.SPLIT + historyId + ".dll";
634         FileUtil.copy(jarFileBakPath,jarFilePath,true);
635         FileUtil.copy(dllFileBakPath,dllFilePath,true);
636
637         URLClassLoader urlClassLoader = null;
638         try {
639             // 加载新的jar
640             urlClassLoader = DllUtils.loadJar(jarFilePath);
641         } catch (Exception e) {
642             throw new RuntimeException("加载新的jar异常",e);
643         }
644
645         try {
646             // 加载新的dll
647             DllUtils.loadDll(urlClassLoader.loadClass("iail.mdk.model.common.Environment"),dllFilePath);
648         } catch (Exception e) {
649             DllUtils.unloadJar(urlClassLoader);
650             throw new RuntimeException("加载新的dll异常",e);
651         }
652         // 都加载成功后加入缓存
653         DllUtils.addClassLoaderCache(projectId,urlClassLoader);
654
655         return CommonResult.success();
656     }
657
558ffc 658     private void createLog(String projectId, String projectName, String dirPath, ProjectPackageHistoryEntity projectPackageHistoryEntity, String version) {
8b3ee3 659         Map<String, Object> map = new HashMap<>();
660         map.put("projectId", projectId);
558ffc 661         List<ProjectPackageHistoryEntity> list = projectPackageHistoryService.list(map);
D 662         list.add(projectPackageHistoryEntity);
449017 663         // 按照日期分组再排序
558ffc 664         HashMap<String, List<ProjectPackageHistoryEntity>> dataMap = list.stream().collect(
449017 665                 Collectors.groupingBy(e -> DateUtils.format(e.getCreateTime(), DateUtils.DATE_PATTERN_POINT),
8b3ee3 666                         LinkedHashMap::new,
558ffc 667                         Collectors.collectingAndThen(Collectors.toList(), e -> e.stream().sorted(Comparator.comparing(ProjectPackageHistoryEntity::getCreateTime)).collect(Collectors.toList()))));
449017 668
D 669         Map<String, Object> data = new HashMap<>();
8b3ee3 670         data.put("dataMap", dataMap);
671         data.put("projectName", projectName);
672         data.put("version", version);
673         data.put("now", DateUtils.format(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
449017 674
D 675         File logFile = new File(dirPath + File.separator + "更新日志.txt");
8b3ee3 676         GenUtils.drawTemplate("log.txt.vm", data, logFile);
449017 677     }
D 678
3009e2 679     private String pkgJar(String dirPath) {
D 680         try {
681             String jarSavePath = dirPath + File.separator + MdkConstant.LIBS + File.separator + "IAILMDK.jar";
682             StringBuilder sb = new StringBuilder();
683             sb.append("jar -cvf");
684             sb.append(" ").append(jarSavePath);
011e9e 685             sb.append(" -C ").append(dirPath).append(File.separator).append(MdkConstant.IAILMDK).append(File.separator).append(" .");
D 686             CmdUtils.exec(sb.toString());
3009e2 687             return jarSavePath;
011e9e 688         } catch (Exception e) {
912a1e 689             throw new RuntimeException("执行cmd命令打jar包异常",e);
3009e2 690         }
449017 691     }
D 692
693     private void deleteJavaFile(List<String> javaFilePaths) {
694         for (String javaFilePath : javaFilePaths) {
695             FileUtil.del(javaFilePath);
696         }
697     }
698
011e9e 699     private void createClassFile(String dirPath,List<String> javaFilePaths){
3009e2 700         try {
011e9e 701             Set<String> pathSet = javaFilePaths.stream().map(path -> {
D 702                 // 替换为相对路径
703                 path = path.replace(dirPath + File.separator + MdkConstant.IAILMDK, ".");
704                 // 删除文件名,替换为通配符*
705                 path = path.substring(0, path.lastIndexOf("\\") + 1) + "*.java";
706                 return path;
707             }).collect(Collectors.toSet());
708
3009e2 709             StringBuilder sb = new StringBuilder();
D 710             sb.append("javac -encoding utf-8");
011e9e 711             for (String path : pathSet) {
3009e2 712                 sb.append(" ").append(path);
D 713             }
011e9e 714             CmdUtils.exec(sb.toString(),dirPath + File.separator + MdkConstant.IAILMDK);
D 715         } catch (Exception e) {
912a1e 716             throw new RuntimeException("执行cmd命令生成class异常",e);
449017 717         }
D 718     }
719 }