dengzedong
2024-09-26 587b438f50abb725f3dee63eaf6b586c09085f54
提交 | 用户 | 时间
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;
11 import com.iailab.framework.common.service.impl.BaseServiceImpl;
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;
15 import com.iailab.module.infra.api.config.ConfigApi;
16 import com.iailab.module.model.mpk.common.MdkConstant;
17 import com.iailab.module.model.mpk.common.utils.GenUtils;
18 import com.iailab.module.model.mpk.dao.MpkFileDao;
0255ea 19 import com.iailab.module.model.mpk.dto.*;
D 20 import com.iailab.module.model.mpk.entity.*;
449017 21 import com.iailab.module.model.mpk.service.*;
D 22 import lombok.extern.slf4j.Slf4j;
23 import org.apache.commons.io.FileUtils;
24 import org.apache.commons.io.IOUtils;
25 import org.apache.commons.lang3.StringUtils;
26 import org.apache.velocity.VelocityContext;
27 import org.apache.velocity.app.Velocity;
28 import org.springframework.beans.factory.annotation.Autowired;
a27351 29 import org.springframework.beans.factory.annotation.Value;
449017 30 import org.springframework.stereotype.Service;
D 31 import org.springframework.util.CollectionUtils;
32 import org.springframework.web.multipart.MultipartFile;
33
f7932f 34 import java.io.*;
449017 35 import java.nio.file.Files;
D 36 import java.util.*;
37 import java.util.stream.Collectors;
38 import java.util.zip.ZipOutputStream;
39
40 /**
41  * @author PanZhibao
42  * @Description
43  * @createTime 2024年08月14日
44  */
45 @Slf4j
46 @Service
0255ea 47 public class MpkFileServiceImpl extends BaseServiceImpl<MpkFileDao, MpkFileEntity> implements MpkFileService {
449017 48
D 49     @Autowired
50     private GeneratorCodeHistoryService generatorCodeHistoryService;
8b3ee3 51
449017 52     @Autowired
D 53     private ProjectPackageHistoryService projectPackageHistoryService;
8b3ee3 54
449017 55     @Autowired
D 56     private ModelMethodService modelMethodService;
8b3ee3 57
449017 58     @Autowired
D 59     private ProjectPackageHistoryModelService projectPackageHistoryModelService;
60
61     @Autowired
62     private ConfigApi configApi;
63
a27351 64     @Value("${mpk.bakFilePath}")
D 65     private String mpkBakFilePath;
449017 66
38e87c 67     /*@PostConstruct
449017 68     public void init() {
D 69         mpkBakFilePath = configApi.getConfigValueByKey("mpkBakFilePath").getCheckedData();
38e87c 70     }*/
449017 71
D 72     @Override
73     public PageData<MpkFileDTO> page(Map<String, Object> params) {
74         IPage<MpkFileEntity> page = baseDao.selectPage(
75                 getPage(params, "create_date", false),
76                 getWrapper(params)
77         );
78
79         return getPageData(page, MpkFileDTO.class);
80     }
81
82     @Override
83     public List<MpkFileDTO> list(Map<String, Object> params) {
84         List<MpkFileEntity> entityList = baseDao.selectList(getWrapper(params).orderByDesc("create_date"));
85
86         return ConvertUtils.sourceToTarget(entityList, MpkFileDTO.class);
87     }
88
8b3ee3 89     private QueryWrapper<MpkFileEntity> getWrapper(Map<String, Object> params) {
449017 90         String pyName = (String) params.get("pyName");
D 91         String pyType = (String) params.get("pyType");
92         String remark = (String) params.get("remark");
d8db4b 93         String label = (String) params.get("label");
449017 94
D 95         QueryWrapper<MpkFileEntity> wrapper = new QueryWrapper<>();
96         wrapper.like(StringUtils.isNotBlank(pyName), "py_name", pyName)
97                 .eq(StringUtils.isNotBlank(pyType), "py_type", pyType)
98                 .like(StringUtils.isNotBlank(remark), "remark", remark);
d8db4b 99
100         if (StringUtils.isNotBlank(label)) {
101             wrapper.and(w -> {
102                 w.eq(StringUtils.isNotBlank(label),"menu_name", label)
103                         .or().eq(StringUtils.isNotBlank(label),"group_name", label);
104             });
105         }
449017 106         return wrapper;
D 107     }
108
109     @Override
110     public MpkFileDTO get(String id) {
111         MpkFileDTO entity = baseDao.get(id);
112
113         return entity;
114     }
115
116     @Override
8b3ee3 117     @DSTransactional(rollbackFor = Exception.class)
449017 118     public void save(MpkFileDTO dto) {
D 119         MpkFileEntity entity = ConvertUtils.sourceToTarget(dto, MpkFileEntity.class);
8b3ee3 120         entity.setId(UUID.randomUUID().toString());
449017 121         entity.setCreator(SecurityFrameworkUtils.getLoginUserId());
D 122         entity.setCreateDate(new Date());
123         insert(entity);
8b3ee3 124         modelMethodService.insertList(dto.getModelMethods(), entity.getId());
449017 125     }
D 126
127     @Override
8b3ee3 128     @DSTransactional(rollbackFor = Exception.class)
449017 129     public void update(MpkFileDTO dto) {
D 130         MpkFileEntity entity = ConvertUtils.sourceToTarget(dto, MpkFileEntity.class);
131         entity.setUpdater(SecurityFrameworkUtils.getLoginUserId());
132         entity.setUpdateDate(new Date());
133         updateById(entity);
8b3ee3 134         modelMethodService.deleteModelMethod(entity.getId());
135         modelMethodService.insertList(dto.getModelMethods(), entity.getId());
449017 136     }
D 137
138     @Override
8b3ee3 139     @DSTransactional(rollbackFor = Exception.class)
449017 140     public void delete(String id) {
D 141
142         //删除源文件
143         MpkFileEntity mpkFileEntity = selectById(id);
144         if (StringUtils.isNoneBlank(mpkFileEntity.getFilePath())) {
145             File mpkFile = new File(mpkFileEntity.getFilePath());
146             if (mpkFile.exists()) {
147                 mpkFile.delete();
148                 log.info("删除源文件备份文件:" + mpkFileEntity.getFilePath());
149             }
150         }
151
152         //删除备份文件
8b3ee3 153         Map<String, Object> map1 = new HashMap<>();
154         map1.put("mdkId", id);
449017 155         List<GeneratorCodeHistoryDTO> list = generatorCodeHistoryService.list(map1);
D 156         list.forEach(e -> {
157             File file = new File(e.getFilePath());
158             if (file.exists()) {
159                 file.delete();
160                 log.info("删除生成代码备份文件:" + e.getFilePath());
161             }
162         });
163
0255ea 164         //删除 会级联删除掉关联表
D 165         deleteById(id);
449017 166     }
D 167
168     @Override
169     public byte[] generatorCode(String id, String remark, String zipFileName) {
170         ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
171         ZipOutputStream zip = new ZipOutputStream(outputStream);
172
173         MpkFileDTO entity = baseDao.get(id);
174         //生成代码
175         GenUtils.generatorCode(entity, zip);
176         IOUtils.closeQuietly(zip);
177
178         File file = null;
179         OutputStream fileOutputStream = null;
180         //文件备份
181         try {
182             String dirPath = mpkBakFilePath;
183             File dir = new File(dirPath);
184             if (!dir.exists()) {
185                 dir.mkdirs();
186             }
187             String filePath = dirPath + File.separator + zipFileName;
188             file = new File(filePath);
189             file.createNewFile();
190             fileOutputStream = Files.newOutputStream(file.toPath());
191             IOUtils.write(outputStream.toByteArray(), fileOutputStream);
192         } catch (IOException e) {
193             log.error("生成代码文件备份失败," + entity.getPyName(), e);
194             throw new RuntimeException(e);
195         } finally {
196             IOUtils.closeQuietly(fileOutputStream);
197         }
198
199         //代码生成历史记录
200         GeneratorCodeHistoryEntity historyEntity = new GeneratorCodeHistoryEntity();
201         historyEntity.setId(UUID.randomUUID().toString());
202         historyEntity.setMdkId(id);
203         historyEntity.setFileName(file.getName());
204         historyEntity.setFilePath(file.getAbsolutePath());
205         historyEntity.setRemark(remark);
206         historyEntity.setCreateTime(new Date());
207         generatorCodeHistoryService.insert(historyEntity);
208
209         return outputStream.toByteArray();
210     }
211
212     @Override
8b3ee3 213     @DSTransactional(rollbackFor = Exception.class)
f7932f 214     public byte[] packageModel(List<String> ids, String projectId, String projectName, String zipFileName, String logs, String version) throws IOException, InterruptedException {
449017 215         List<MpkFileDTO> entities = baseDao.selectByIds(ids);
D 216
217         //模板数据
218         Map<String, Object> map = new HashMap<>();
8b3ee3 219         map.put("entities", entities);
449017 220         VelocityContext context = new VelocityContext(map);
D 221
222         //临时文件夹
223         File dirPath = new File("C:/DLUT/tmp/");
224         if (!dirPath.exists()) {
225             dirPath.mkdirs();
226         }
227
228         //设置velocity资源加载器
229         Properties prop = new Properties();
230         prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
231         Velocity.init(prop);
232
a27351 233         //生成menu.xml文件
2cc235 234         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 235         Map<String, Object> map1 = new HashMap<>();
8b3ee3 236         map1.put("collects", collect);
a27351 237         File xmlFile = new File(dirPath.getAbsolutePath() + File.separator + "menu.xml");
8b3ee3 238         GenUtils.drawTemplate("menu.xml.vm", new VelocityContext(map1), xmlFile);
a27351 239
f7932f 240         // C++源文件
D 241         FileUtil.copy("bak/C++", dirPath.getAbsolutePath(), true);
449017 242
D 243         List<String> javaFilePaths = new ArrayList<>();
f7932f 244         List<String> cppFilePaths = new ArrayList<>();
449017 245
D 246         //生成java文件
247         for (MpkFileDTO entity : entities) {
248             //封装模板数据
249             Map<String, Object> data = new HashMap<>();
8b3ee3 250             data.put("pkgName", entity.getPkgName());
251             data.put("modelMethods", entity.getModelMethods());
252             data.put("pyName", entity.getPyName());
253             data.put("pyModule", entity.getPyModule());
449017 254             VelocityContext dataContext = new VelocityContext(data);
D 255             //生成java文件
256             File javaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + entity.getPkgName().replace(".", File.separator) + File.separator + entity.getPyName() + ".java");
8b3ee3 257             GenUtils.drawTemplate("abstract.java.vm", dataContext, javaFile);
449017 258             javaFilePaths.add(javaFile.getAbsolutePath());
D 259
260             //生成Impl.java文件
261             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 262             GenUtils.drawTemplate("impl.java.vm", dataContext, implJavaFile);
449017 263             javaFilePaths.add(implJavaFile.getAbsolutePath());
D 264
f7932f 265             //生成.cpp文件
D 266             File cppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".cpp");
267             GenUtils.drawTemplate("cpp.vm", dataContext, cppFile);
268             cppFilePaths.add(cppFile.getAbsolutePath());
269
270             //生成Jni.cpp文件
271             File jniCppFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.cpp");
272             GenUtils.drawTemplate("Jni.cpp.vm", dataContext, jniCppFile);
273             cppFilePaths.add(jniCppFile.getAbsolutePath());
274
275             //生成.h文件
276             File hFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + ".h");
277             GenUtils.drawTemplate("h.vm", dataContext, hFile);
278
279             //生成Jni.h文件
280             File jniHFile = new File(dirPath.getAbsolutePath() + File.separator + MdkConstant.C + File.separator + entity.getPyName() + "Jni.h");
281             GenUtils.drawTemplate("Jni.h.vm", dataContext, jniHFile);
282
449017 283             // 添加python源文件
8b3ee3 284             String pyFilePath = dirPath.getAbsolutePath() + File.separator + "py" + File.separator + entity.getPyName() + ".pyd";
449017 285             FileUtil.mkParentDirs(pyFilePath);
8b3ee3 286             FileUtil.copy(entity.getFilePath(), pyFilePath, true);
449017 287         }
D 288
f7932f 289         //生成dll文件
D 290         String dllSavePath = dirPath.getAbsolutePath() + File.separator + "IAIL.MDK.Mid.Windows.dll";
291         createDllFile(dirPath.getAbsolutePath(),cppFilePaths,dllSavePath);
292
449017 293         //utils + env java文件
D 294         File utilsJavaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + "utils" + File.separator + "AlgsUtils.java");
295         FileUtil.mkParentDirs(utilsJavaFile);
f7932f 296         FileUtil.copy("bak/IAILMDK/utils/AlgsUtils.java", utilsJavaFile.getAbsolutePath(), true);
449017 297         javaFilePaths.add(utilsJavaFile.getAbsolutePath());
D 298         File envJavaFile = new File(dirPath.getAbsolutePath() + File.separator + "IAILMDK" + File.separator + "common" + File.separator + "Environment.java");
299         FileUtil.mkParentDirs(envJavaFile);
f7932f 300         FileUtil.copy("bak/IAILMDK/common/Environment.java", envJavaFile.getAbsolutePath(), true);
449017 301         javaFilePaths.add(envJavaFile.getAbsolutePath());
D 302         // 生成class文件
303         createClassFile(javaFilePaths);
304         // 删除java源文件
305         deleteJavaFile(javaFilePaths);
306         // 打jar包
307         pkgJar(dirPath.getAbsolutePath());
308         // 本次更新日志
309         ProjectPackageHistoryDTO dto = new ProjectPackageHistoryDTO();
310         String historyId = UUID.randomUUID().toString();
311         dto.setId(historyId);
312         dto.setProjectId(projectId);
313         dto.setFileName(zipFileName);
f7932f 314         dto.setLog(logs);
449017 315         dto.setVersion(version);
D 316         dto.setModelNames(entities.stream().map(MpkFileDTO::getPyName).collect(Collectors.joining(",")));
317         dto.setCreateTime(new Date());
318         // 生成更新日志
8b3ee3 319         createLog(projectId, projectName, dirPath.getAbsolutePath(), dto, version);
449017 320         // 打zip包
D 321         String zipPath = mpkBakFilePath + File.separator + zipFileName;
8b3ee3 322         ZipUtil.zip(dirPath.getAbsolutePath(), zipPath);
449017 323         byte[] bytes = FileUtil.readBytes(zipPath);
D 324         // 记录打包日志
325         dto.setFilePath(zipPath);
326         projectPackageHistoryService.save(dto);
327         // 插入打包历史-模型关联表
328         List<ProjectPackageHistoryModelEntity> historyModelList = new ArrayList<>(entities.size());
329         entities.forEach(e -> {
330             ProjectPackageHistoryModelEntity entity = new ProjectPackageHistoryModelEntity();
331             entity.setId(UUID.randomUUID().toString());
332             entity.setProjectId(projectId);
333             entity.setPackageHistoryId(historyId);
334             entity.setPyName(e.getPyName());
067d7a 335             entity.setPyChineseName(e.getPyChineseName());
449017 336             entity.setPkgName(e.getPkgName());
D 337             entity.setPyModule(e.getPyModule());
338             entity.setRemark(e.getRemark());
0255ea 339             List<ModelMethodDTO> methods = e.getModelMethods();
449017 340             if (!CollectionUtils.isEmpty(methods)) {
D 341                 entity.setMethodInfo(JSON.toJSONString(methods));
342             }
343             historyModelList.add(entity);
344         });
345         projectPackageHistoryModelService.insertBatch(historyModelList);
346         // 删除临时文件
347         FileUtils.deleteDirectory(dirPath);
348 //        FileUtils.delete(new File(zipPath));
349         return bytes;
350     }
351
f7932f 352     private void createDllFile(String dirPath, List<String> cppFilePaths, String dllSavePath) throws InterruptedException, IOException {
D 353         cppFilePaths.add(dirPath + File.separator + "C++" + File.separator + "pch.cpp");
354         cppFilePaths.add(dirPath + File.separator + "C++" + File.separator + "dllmain.cpp");
355         cppFilePaths.add(dirPath + File.separator + "C++" + File.separator + "Environment.cpp");
356         cppFilePaths.add(dirPath + File.separator + "C++" + File.separator + "pyutils.cpp");
357         cppFilePaths.add(dirPath + File.separator + "C++" + File.separator + "convertutils.cpp");
358         String paths = cppFilePaths.stream().collect(Collectors.joining(" "));
359         String command = "cl /LD " + paths + " /EHsc /o " + dllSavePath;
360 //        String command = "cmd.exe /c cl -o " + dllSavePath + " /LD D:\\work\\mdk\\code\\makeDll\\src\\main\\java\\org\\example\\MakeDll.c D:\\work\\mdk\\code\\makeDll\\src\\main\\java\\org\\example\\MakeDll2.c";
361         log.info("执行cmd命令生成dll:" + command);
362         ProcessBuilder builder = new ProcessBuilder("cmd", "/c", command);
363         builder.directory(new File(dirPath + File.separator + "C++"));
364         Process process = builder.start();
365         // 获取命令输出结果
366         InputStream inputStream = process.getInputStream();
367         BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "GBK")); // 设置编码为GBK
368         String line;
369         while ((line = reader.readLine()) != null) {
370             System.out.println(line);
371         }
372         // 等待命令执行完成
373         process.waitFor();
374     }
375
449017 376     @Override
8b3ee3 377     public Map<String, String> savePyFile(MultipartFile file) throws IOException {
449017 378         File dir = new File(mpkBakFilePath);
D 379         if (!dir.exists()) {
380             dir.mkdirs();
381         }
382         String fileName = file.getOriginalFilename();
383         File saveFile = new File(dir.getAbsolutePath() + File.separator + fileName);
384         saveFile.createNewFile();
385         // 保存
386         file.transferTo(saveFile);
387
8b3ee3 388         Map<String, String> result = new HashMap<>(2);
389         result.put("filePath", saveFile.getAbsolutePath());
449017 390         result.put("fileName", fileName);
D 391
392         return result;
393     }
394
8b3ee3 395     private void createLog(String projectId, String projectName, String dirPath, ProjectPackageHistoryDTO dto, String version) throws IOException {
396         Map<String, Object> map = new HashMap<>();
397         map.put("projectId", projectId);
449017 398         List<ProjectPackageHistoryDTO> list = projectPackageHistoryService.list(map);
D 399         list.add(dto);
400         // 按照日期分组再排序
401         HashMap<String, List<ProjectPackageHistoryDTO>> dataMap = list.stream().collect(
402                 Collectors.groupingBy(e -> DateUtils.format(e.getCreateTime(), DateUtils.DATE_PATTERN_POINT),
8b3ee3 403                         LinkedHashMap::new,
404                         Collectors.collectingAndThen(Collectors.toList(), e -> e.stream().sorted(Comparator.comparing(ProjectPackageHistoryDTO::getCreateTime)).collect(Collectors.toList()))));
449017 405
D 406         Map<String, Object> data = new HashMap<>();
8b3ee3 407         data.put("dataMap", dataMap);
408         data.put("projectName", projectName);
409         data.put("version", version);
410         data.put("now", DateUtils.format(new Date(), DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND));
449017 411
D 412         File logFile = new File(dirPath + File.separator + "更新日志.txt");
8b3ee3 413         GenUtils.drawTemplate("log.txt.vm", data, logFile);
449017 414     }
D 415
416     private void pkgJar(String dirPath) throws InterruptedException {
417         StringBuilder sb = new StringBuilder();
418         sb.append("jar -cvf");
419         sb.append(" ").append(dirPath).append(File.separator).append("IAILMDK.jar");
420         sb.append(" -C ").append(dirPath).append(File.separator).append("IAILMDK").append(File.separator).append(" .");
421         log.info("执行cmd命令打jar包:" + sb);
422         Process process = RuntimeUtil.exec(sb.toString());
423         process.waitFor();
424     }
425
426     private void deleteJavaFile(List<String> javaFilePaths) {
427         for (String javaFilePath : javaFilePaths) {
428             FileUtil.del(javaFilePath);
429         }
430     }
431
432     private void createClassFile(List<String> javaFilePaths) throws InterruptedException {
433         StringBuilder sb = new StringBuilder();
434         sb.append("javac -encoding utf-8");
435         for (String path : javaFilePaths) {
436             sb.append(" ").append(path);
437         }
438         log.info("执行cmd命令生成class:" + sb);
439         Process process = RuntimeUtil.exec(sb.toString());
440         process.waitFor();
441     }
442 }