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