| | |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.springblade.core.log.exception.ServiceException; |
| | | import org.springblade.core.mp.base.BizServiceImpl; |
| | | import org.springblade.core.oss.OssTemplate; |
| | | import org.springblade.core.oss.model.BladeFile; |
| | | import org.springblade.core.redis.cache.BladeRedis; |
| | | import org.springblade.core.secure.utils.AuthUtil; |
| | | import org.springblade.core.tool.utils.Func; |
| | | import org.springblade.mdm.basesetting.machine.service.MachineService; |
| | | import org.springblade.mdm.basesetting.machine.entity.Machine; |
| | | import org.springblade.mdm.commons.contants.ZipConstants; |
| | | import org.springblade.mdm.gkw.programnode.vo.ProgramNameVO; |
| | | import org.springblade.mdm.gkw.task.entity.MachineBackTask; |
| | | import org.springblade.mdm.gkw.task.service.MachineBackTaskService; |
| | | import org.springblade.mdm.machinefile.entity.FileSendRecord; |
| | | import org.springblade.mdm.machinefile.service.FileSendRecordService; |
| | | import org.springblade.mdm.program.entity.NcProgramExchange; |
| | | import org.springblade.mdm.program.mapper.NcProgramExchangeMapper; |
| | | import org.springblade.mdm.program.service.programannotation.AnnotationProperties; |
| | | import org.springblade.mdm.program.service.programannotation.*; |
| | | import org.springblade.mdm.program.vo.MdmProgramImportVO; |
| | | import org.springblade.mdm.utils.FileContentUtil; |
| | | import org.springblade.mdm.utils.ProgramFileNameParser; |
| | | import org.springblade.system.pojo.entity.DictBiz; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.web.multipart.MultipartFile; |
| | | |
| | | import java.io.*; |
| | | import java.nio.charset.Charset; |
| | | import java.nio.charset.StandardCharsets; |
| | | import java.nio.file.Files; |
| | | import java.nio.file.Path; |
| | | import java.nio.file.Paths; |
| | | import java.time.Duration; |
| | | import java.util.*; |
| | | import java.nio.file.*; |
| | | import java.util.stream.Stream; |
| | | import java.util.zip.ZipEntry; |
| | | import java.util.zip.ZipInputStream; |
| | | /** |
| | |
| | | @Slf4j |
| | | @Service |
| | | public class MdmProgramImportService extends BizServiceImpl<NcProgramExchangeMapper, NcProgramExchange> { |
| | | |
| | | @Autowired |
| | | private BladeRedis bladeRedis; |
| | | |
| | | @Autowired |
| | | private ProgramAnnotationService programAnnotationService; |
| | | |
| | | @Autowired |
| | | private MachineService machineService; |
| | | |
| | | @Autowired |
| | | private FileSendRecordService fileSendRecordService; |
| | | @Autowired |
| | | private OssTemplate ossTemplate; |
| | | @Autowired |
| | | private AnnotationProcessorHelper annotationProcessorHelper; |
| | | @Autowired |
| | | private MachineBackTaskService machineBackTaskService; |
| | | |
| | | private String getFileKey(){ |
| | | return "mdmgkwimpfile-"+ AuthUtil.getUserId(); |
| | |
| | | * @return |
| | | */ |
| | | public List<MdmProgramImportVO> mdmImportUpload(MultipartFile file) { |
| | | List<MdmProgramImportVO> list = new ArrayList<>(); |
| | | List<MdmProgramImportVO> list; |
| | | try { |
| | | if(file == null || file.isEmpty()){ |
| | | throw new ServiceException("文件为空"); |
| | | } |
| | | |
| | | /* |
| | | if(!StringUtils.endsWith(file.getOriginalFilename(),".zip")){ |
| | | throw new ServiceException("文件必须为zip包"); |
| | | } |
| | | }*/ |
| | | String tempDir = System.getProperty("java.io.tmpdir"); |
| | | Path tempPath = Paths.get(tempDir); |
| | | |
| | | // 创建解压目标目录(在临时目录下创建一个唯一子目录) |
| | | Path tempZipFile = Files.createTempFile("mdmimpfile-"+System.currentTimeMillis(), ".zip"); |
| | | |
| | | file.transferTo(tempZipFile); |
| | | |
| | | // 创建解压目标目录(在临时目录下创建一个唯一子目录) |
| | | Path extractDir = Files.createTempDirectory(tempPath, "unzip_"); |
| | | |
| | | Path extractDir = Files.createTempDirectory(tempPath, "unzip_"+System.currentTimeMillis()); |
| | | bladeRedis.setEx(getFileKey(),extractDir.toString(), Duration.ofHours(2)); |
| | | |
| | | extractZipToTempDir(tempZipFile,extractDir); |
| | | if(StringUtils.endsWithIgnoreCase(file.getOriginalFilename(),".zip")){ |
| | | // 创建解压目标目录(在临时目录下创建一个唯一子目录) |
| | | Path tempZipFile = Files.createTempFile("mdmimpfile-"+System.currentTimeMillis(), ".zip"); |
| | | file.transferTo(tempZipFile); |
| | | extractZipToTempDir(tempZipFile,extractDir); |
| | | }else{ |
| | | //普通文件,直接放入extract文件夹 |
| | | file.transferTo(Paths.get(extractDir.toString()+File.separator+file.getOriginalFilename())); |
| | | } |
| | | |
| | | //读取文件目录 |
| | | list = readTempDir(extractDir); |
| | |
| | | return list; |
| | | } |
| | | |
| | | public void extractZipToTempDir(Path zipFilePath,Path extractDir) throws IOException { |
| | | /** |
| | | * 解压zip包到临时路径 |
| | | * @param zipFilePath zip包文件服务器上的路径 |
| | | * @param extractDir 目标目录 |
| | | * @throws IOException 文件操作异常 |
| | | */ |
| | | public void extractZipToTempDir(Path zipFilePath,Path extractDir) throws IOException{ |
| | | for (String encoding : ZipConstants.TRY_ENCODINGS) { |
| | | try { |
| | | extractZipToTempDirWithCharset(zipFilePath,extractDir,Charset.forName(encoding)); |
| | | log.error("使用编码 {} 解析成功 ",encoding); |
| | | break; |
| | | } catch (Exception e) { |
| | | log.error("使用编码 {} 解析失败: ",encoding,e); |
| | | } |
| | | } |
| | | } |
| | | public void extractZipToTempDirWithCharset(Path zipFilePath, Path extractDir, Charset charset) throws IOException { |
| | | // 获取系统临时目录 |
| | | String tempDir = System.getProperty("java.io.tmpdir"); |
| | | Path tempPath = Paths.get(tempDir); |
| | | |
| | | // 创建解压目标目录(在临时目录下创建一个唯一子目录) |
| | | try (InputStream fis = Files.newInputStream(zipFilePath); |
| | | ZipInputStream zis = new ZipInputStream(fis)) { |
| | | ZipInputStream zis = new ZipInputStream(fis,charset)) { |
| | | |
| | | ZipEntry zipEntry = zis.getNextEntry(); |
| | | while (zipEntry != null) { |
| | |
| | | |
| | | /** |
| | | * 防止ZIP Slip攻击 |
| | | * @param zipEntry |
| | | * @param targetDir |
| | | * @return |
| | | * @throws IOException |
| | | * @param zipEntry zip内部文件路径 |
| | | * @param targetDir 目标文件夹 |
| | | * @return 文件路径 |
| | | * @throws IOException 操作文件IO异常 |
| | | */ |
| | | Path zipSlipProtect(ZipEntry zipEntry, Path targetDir) throws IOException { |
| | | Path targetDirResolved = targetDir.resolve(zipEntry.getName()); |
| | |
| | | return normalizePath; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 读取解压文件夹下所有文件 解析成vo列表 |
| | | * @param extractDir 解压文件夹 |
| | | * @return vo列表 |
| | | * @throws IOException 解析文件的异常 |
| | | */ |
| | | public List<MdmProgramImportVO> readTempDir(Path extractDir) throws IOException { |
| | | List<MdmProgramImportVO> list = new ArrayList<>(); |
| | | try (Stream<Path> paths = Files.walk(extractDir)) { |
| | | List<Path> filePathList = paths |
| | | .filter(Files::isRegularFile).toList(); // 只保留普通文件,排除目录 |
| | | |
| | | //List<Machine> machines = machineService.getEnableMachines(); |
| | | for(Path path : filePathList){ |
| | | list.add(readFileToVO(path)); |
| | | } |
| | | } |
| | | /* |
| | | //读取所有文件夹 |
| | | try (DirectoryStream<Path> stream = Files.newDirectoryStream(extractDir)) { |
| | | for (Path path : stream) { |
| | | if (Files.isDirectory(path)) { |
| | | |
| | | // 如果是子目录,读取其中的文件 |
| | | try (DirectoryStream<Path> subStream = Files.newDirectoryStream(path)) { |
| | | for (Path subPath : subStream) { |
| | |
| | | } else if (Files.isRegularFile(path)) { |
| | | System.out.println("找到文件2: " + path); |
| | | //这里 找到的文件不是 |
| | | MdmProgramImportVO vo = new MdmProgramImportVO(); |
| | | vo.setFilename(path.getFileName().toString()); |
| | | vo.setDrawingNo(parseDrawingNo(vo.getFilename())); |
| | | |
| | | try (InputStream inputStream = Files.newInputStream(path)) { |
| | | // 使用输入流读取文件内容 |
| | | byte[] buffer = new byte[2000]; |
| | | inputStream.read(buffer); |
| | | vo.setMd5(DigestUtils.md5Hex(buffer)); |
| | | } catch (IOException e) { |
| | | log.error("读取文件md5失败",e); |
| | | } |
| | | |
| | | |
| | | try (InputStream inputStream = Files.newInputStream(path, StandardOpenOption.READ)) { |
| | | // 使用输入流读取文件内容 |
| | | ByteArrayInputStream bas = new ByteArrayInputStream(inputStream.readAllBytes()); |
| | | |
| | | AnnotationProperties defAnnoProperties = AnnotationProperties.getDefault(); |
| | | String sendPathLine = FileContentUtil.readLineAt(bas,defAnnoProperties.getSendPathLineIndex()); |
| | | //bas.mark(0); |
| | | bas.reset(); |
| | | String statusLine = FileContentUtil.readLineAt(bas,defAnnoProperties.getStatusLineIndex()); |
| | | log.info("sendPathLine={}", sendPathLine); |
| | | |
| | | Machine matchedMachine = machineService.getMachineBySendPathAnnotation(sendPathLine); |
| | | /* |
| | | for (Machine machine : machines) { |
| | | if(Func.isNotBlank(machine.getProgSendDir()) && sendPathLine.contains(machine.getProgSendDir())){ |
| | | matchedMachine = machine; |
| | | break; |
| | | } |
| | | |
| | | } |
| | | |
| | | */ |
| | | if (matchedMachine != null) { |
| | | vo.setName(parseProgramName(vo.getFilename())); |
| | | vo.setMachineCode(matchedMachine.getCode()); |
| | | |
| | | vo.setFullPath(path.toString());//文件地址 |
| | | vo.setSendPath(matchedMachine.getProgSendDir()); |
| | | vo.setId(vo.getFullPath()); |
| | | vo.setProgramStatus(programAnnotationService.removeAnnotation(matchedMachine.getControlSystem(),statusLine)); |
| | | |
| | | list.add(vo); |
| | | } |
| | | |
| | | } catch (IOException e) { |
| | | log.error("读取文件md5失败",e); |
| | | } |
| | | list.add(readFileToVO(path)); |
| | | } |
| | | } |
| | | } |
| | | }*/ |
| | | return list; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 解析出零组件好 |
| | | * @param filename |
| | | * @return |
| | | */ |
| | | String parseDrawingNo(String filename){ |
| | | String drawingNo = ""; |
| | | int idx = filename.lastIndexOf("-"); |
| | | String temp; |
| | | if(idx != -1){ |
| | | temp = filename.substring(0,idx); |
| | | |
| | | idx = temp.lastIndexOf("-"); |
| | | if(idx != -1){ |
| | | temp = temp.substring(0,idx); |
| | | |
| | | //去掉工序版次 |
| | | idx = temp.lastIndexOf("-"); |
| | | if(idx != -1){ |
| | | temp = temp.substring(0,idx); |
| | | |
| | | //去掉工序号 |
| | | idx = temp.lastIndexOf("-"); |
| | | if(idx != -1){ |
| | | drawingNo = temp.substring(0,idx); |
| | | } |
| | | } |
| | | public static byte[] getUTF8BytesFromGBKString(String gbkStr) { |
| | | int n = gbkStr.length(); |
| | | byte[] utfBytes = new byte[3 * n]; |
| | | int k = 0; |
| | | for (int i = 0; i < n; i++) { |
| | | int m = gbkStr.charAt(i); |
| | | if (m < 128 && m >= 0) { |
| | | utfBytes[k++] = (byte) m; |
| | | continue; |
| | | } |
| | | //以上去掉了最后2段段数和段号 |
| | | |
| | | |
| | | utfBytes[k++] = (byte) (0xe0 | (m >> 12)); |
| | | utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f)); |
| | | utfBytes[k++] = (byte) (0x80 | (m & 0x3f)); |
| | | } |
| | | return drawingNo; |
| | | if (k < utfBytes.length) { |
| | | byte[] tmp = new byte[k]; |
| | | System.arraycopy(utfBytes, 0, tmp, 0, k); |
| | | return tmp; |
| | | } |
| | | return utfBytes; |
| | | } |
| | | |
| | | String parseProgramName(String filename){ |
| | | String programName = ""; |
| | | int idx = filename.lastIndexOf("-"); |
| | | String temp; |
| | | if(idx != -1){ |
| | | temp = filename.substring(0,idx); |
| | | |
| | | idx = temp.lastIndexOf("-"); |
| | | if(idx != -1){ |
| | | temp = temp.substring(0,idx); |
| | | |
| | | //去掉工序版次 |
| | | idx = temp.lastIndexOf("-"); |
| | | if(idx != -1){ |
| | | programName = temp.substring(0,idx); |
| | | } |
| | | } |
| | | //以上去掉了最后2段段数和段号 |
| | | |
| | | |
| | | ProgramNameVO tryParseProgramName(String fiilename){ |
| | | ProgramNameVO pnmameVO = ProgramFileNameParser.parseProgramName(fiilename);//标准utf8编码 |
| | | if(pnmameVO.getDrawingNo() == null) { |
| | | //使用GBK编码解析 |
| | | pnmameVO = ProgramFileNameParser.parseProgramName(new String(getUTF8BytesFromGBKString(fiilename), StandardCharsets.UTF_8)); |
| | | } |
| | | return programName; |
| | | return pnmameVO; |
| | | } |
| | | /** |
| | | * 将文件组织成VO |
| | | * @param path 文件path |
| | | * @return vo |
| | | */ |
| | | MdmProgramImportVO readFileToVO(Path path) throws UnsupportedEncodingException { |
| | | MdmProgramImportVO vo = new MdmProgramImportVO(); |
| | | vo.setFilename(path.getFileName().toString()); |
| | | |
| | | ProgramNameVO progNmameVO = tryParseProgramName(vo.getFilename()); |
| | | vo.setDrawingNo(progNmameVO.getDrawingNo()); |
| | | |
| | | try (InputStream inputStream = Files.newInputStream(path)) { |
| | | // 使用输入流读取文件内容 |
| | | byte[] buffer = new byte[2000]; |
| | | inputStream.read(buffer); |
| | | vo.setMd5(DigestUtils.md5Hex(buffer)); |
| | | } catch (IOException e) { |
| | | log.error("读取文件md5失败",e); |
| | | } |
| | | |
| | | try (InputStream inputStream = Files.newInputStream(path, StandardOpenOption.READ)) { |
| | | // 使用输入流读取文件内容 |
| | | ByteArrayInputStream bas = new ByteArrayInputStream(inputStream.readAllBytes()); |
| | | |
| | | AnnotationProperties defAnnoProperties = AnnotationProperties.getDefault(); |
| | | String sendPathLine = FileContentUtil.readLineAt(bas,defAnnoProperties.getSendPathLineIndex()); |
| | | |
| | | bas.reset(); |
| | | String statusLine = FileContentUtil.readLineAt(bas,defAnnoProperties.getStatusLineIndex()); |
| | | log.info("sendPathLine={}", sendPathLine); |
| | | |
| | | Machine matchedMachine = machineService.getMachineBySendPathAnnotation(sendPathLine); |
| | | |
| | | if (matchedMachine != null) { |
| | | vo.setName(progNmameVO.logicProgramName()); |
| | | vo.setMachineCode(matchedMachine.getCode()); |
| | | |
| | | vo.setFullPath(path.toString());//文件地址 |
| | | vo.setSendPath(matchedMachine.getProgSendDir()); |
| | | vo.setId(vo.getFullPath()); |
| | | vo.setProgramStatus(programAnnotationService.removeAnnotation(matchedMachine.getControlSystem(),statusLine)); |
| | | } |
| | | } catch (IOException e) { |
| | | log.error("读取文件失败",e); |
| | | throw new ServiceException("导入程序失败"+path.getFileName().toString()+","+e.getMessage()); |
| | | } |
| | | return vo; |
| | | } |
| | | |
| | | /** |
| | | * 入库mdm涉密网文件 |
| | | * @param ids id列表逗号分隔 |
| | | * @return |
| | | */ |
| | | public void mdmFileAccept(String ids) throws IOException { |
| | | |
| | | List<FileSendRecord> importedRecords = new ArrayList<>(); |
| | | List<String> idList = Func.toStrList(ids); |
| | | |
| | | String dictStr = bladeRedis.get(getFileKey()); |
| | | if(dictStr == null){ |
| | | throw new ServiceException(""); |
| | | throw new ServiceException("文件缓存已过期,请重新上传文件。"); |
| | | } |
| | | Path extractDir = Paths.get(dictStr); |
| | | |
| | | List<MdmProgramImportVO> list = readTempDir(extractDir); |
| | | |
| | | //List<DictBiz> annoDictList = programAnnotationService.getAnnotionDictList(); |
| | | String destFileFull; |
| | | for(String str : idList){ |
| | | for(MdmProgramImportVO vo : list){ |
| | | if(StringUtils.equals(vo.getFullPath(),str)){ |
| | | destFileFull = vo.getSendPath()+File.separator+vo.getFilename(); |
| | | File destFile = new File(destFileFull); |
| | | FileUtils.forceMkdirParent(destFile); |
| | | FileUtils.copyFile(new File(str),destFile); |
| | | Optional<MdmProgramImportVO> optVO = list.stream().filter(vo -> vo.getId().equals(str)).findFirst(); |
| | | |
| | | FileSendRecord record = new FileSendRecord(); |
| | | record.setName(destFile.getName()); |
| | | Path destPath = Paths.get(destFileFull); |
| | | record.setMachineCode(vo.getMachineCode()); |
| | | record.setFileSize(Files.size(destPath)); |
| | | fileSendRecordService.save(record); |
| | | break; |
| | | } |
| | | if(optVO.isEmpty()){ |
| | | continue; |
| | | } |
| | | |
| | | MdmProgramImportVO vo = optVO.get(); |
| | | |
| | | destFileFull = vo.getSendPath()+File.separator+vo.getFilename(); |
| | | File destFile = new File(destFileFull); |
| | | |
| | | FileUtils.forceMkdirParent(destFile); |
| | | FileUtils.copyFile(new File(str),destFile); |
| | | |
| | | FileSendRecord record = new FileSendRecord(); |
| | | record.setName(destFile.getName()); |
| | | Path destPath = Paths.get(destFileFull); |
| | | record.setMachineCode(vo.getMachineCode()); |
| | | record.setFileSize(Files.size(destPath)); |
| | | |
| | | try(InputStream inputStream = new FileInputStream(destFile)){ |
| | | BladeFile bFile = ossTemplate.putFile(record.getName(), inputStream); |
| | | record.setOssName(bFile.getName()); |
| | | } |
| | | |
| | | try(InputStream inputStream = ossTemplate.statFileStream(record.getOssName())){ |
| | | //读取程序状态 |
| | | Machine machine = this.machineService.getByCode(record.getMachineCode()); |
| | | AnnotationProcessor processor = annotationProcessorHelper.getProcessor(machine.getControlSystem()); |
| | | AnnotationData annotationData = processor.readAnnotationData(inputStream); |
| | | |
| | | record.setDeviation(annotationData.getDeviation()); |
| | | ProgramNameVO nameVO = ProgramFileNameParser.parseProgramName(record.getName()); |
| | | record.setDeviationSerial(nameVO.lgSerial()); |
| | | |
| | | record.setProgramStatus(annotationData.getProgramStatus()); |
| | | } |
| | | fileSendRecordService.save(record); |
| | | |
| | | importedRecords.add(record); |
| | | } |
| | | |
| | | machineBackTaskService.saveBatch(parseMachineBackTask(importedRecords)); |
| | | } |
| | | |
| | | /** |
| | | * 创建机床回传任务 |
| | | * @param importedRecords 导入记录列表 |
| | | */ |
| | | List<MachineBackTask> parseMachineBackTask(List<FileSendRecord> importedRecords){ |
| | | List<FileSendRecord> recList = importedRecords.stream().filter(r -> AnnotationUtil.SQ.equals(r.getProgramStatus()) |
| | | || AnnotationUtil.LG.equals(r.getProgramStatus())).toList(); |
| | | |
| | | Map<String,FileSendRecord> map = new HashMap<>(); |
| | | for(FileSendRecord record : recList){ |
| | | ProgramNameVO nameVO = ProgramFileNameParser.parseProgramName(record.getName()); |
| | | String key = record.getMachineCode()+","+nameVO.logicProgramName(); |
| | | |
| | | map.put(key,record); |
| | | } |
| | | |
| | | List<MachineBackTask> backTasks = new ArrayList<>(); |
| | | for(String key : map.keySet()){ |
| | | MachineBackTask task = new MachineBackTask(); |
| | | task.setTaskType(MachineBackTask.TASK_TYPE_PROGRAM); |
| | | |
| | | FileSendRecord record = map.get(key); |
| | | task.setMachineCode(record.getMachineCode()); |
| | | |
| | | ProgramNameVO nameVO = ProgramFileNameParser.parseProgramName(record.getName()); |
| | | task.setDeviation(record.getDeviation()); |
| | | task.setDeviationSerial(record.getDeviationSerial()); |
| | | |
| | | task.setProgramName(nameVO.logicProgramName()); |
| | | task.setSegCount(nameVO.getSegmentCount()); |
| | | backTasks.add(task); |
| | | } |
| | | //提取程序包名,机床编码集合 |
| | | return backTasks; |
| | | } |
| | | } |