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