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