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