yangys
2025-08-14 a049dda2f63d59f5092994b44387fe0aa889d375
blade-service/blade-mdm/src/main/java/org/springblade/mdm/program/service/MdmProgramImportService.java
@@ -1,33 +1,24 @@
package org.springblade.mdm.program.service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.compress.utils.SeekableInMemoryByteChannel;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.base.BizEntity;
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.FileUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.IoUtil;
import org.springblade.mdm.flow.entity.ApproveRecord;
import org.springblade.mdm.flow.service.ApproveRecordService;
import org.springblade.mdm.flow.service.CureFlowService;
import org.springblade.mdm.program.entity.NcNode;
import org.springblade.mdm.program.entity.NcProgram;
import org.springblade.mdm.basesetting.machine.MachineService;
import org.springblade.mdm.basesetting.machine.entity.Machine;
import org.springblade.mdm.program.entity.NcProgramExchange;
import org.springblade.mdm.program.mapper.NcProgramExchangeMapper;
import org.springblade.mdm.program.vo.MdmProgramImportVO;
import org.springblade.mdm.utils.CustomBinaryReader;
import org.springblade.mdm.utils.FileContentUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.support.SimpleTriggerContext;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@@ -37,7 +28,9 @@
import java.nio.file.Paths;
import java.time.Duration;
import java.util.*;
import java.nio.file.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
/**
 * MDM程序导入(工控网功能)
 * 目前工控网展现形式未定,暂时实现暂停
@@ -45,37 +38,62 @@
 */
@Slf4j
@Service
@AllArgsConstructor
public class MdmProgramImportService extends BizServiceImpl<NcProgramExchangeMapper, NcProgramExchange> {
   private final CureFlowService cureFlowService;
   private final NcProgramService ncProgramService;
   private final NcNodeService ncNodeService;
   private final ApproveRecordService approveRecordService;
   private final BladeRedis bladeRedis;
   private final OssTemplate ossTemplate;
   @Autowired
   private BladeRedis bladeRedis;
   @Autowired
   private ProgramAnnotationService programAnnotationService;
   @Autowired
   private MachineService machineService;
   private String getFileKey(){
      return "mdmimpfile-"+ AuthUtil.getUserId();
      return "mdmgkwimpfile-"+ AuthUtil.getUserId();
   }
   /**
    * MDM导入文件上传
    * 工控MDM导入文件上传
    * @param file MDM涉密网导出文件
    * @return
    */
   public List<MdmProgramImportVO> mdmImportUpload(MultipartFile file) {
      List<MdmProgramImportVO> list;
      List<MdmProgramImportVO> list = new ArrayList<>();
      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");
         //Path extractDir = Files.createTempDirectory(tempPath, "unzip_");
         file.transferTo(tempZipFile);
         // 创建解压目标目录(在临时目录下创建一个唯一子目录)
         Path extractDir = Files.createTempDirectory(tempPath, "unzip_");
         bladeRedis.setEx(getFileKey(),extractDir.toString(), Duration.ofHours(2));
         extractZipToTempDir(tempZipFile,extractDir);
         //读取文件目录
         /*
         BladeFile bfile = ossTemplate.putFile(file);//上传,供后续入库使用
         //设置一个缓存,2小时过期
         bladeRedis.setEx(getFileKey(),bfile.getName(), Duration.ofHours(2));
         String pkgFileName = bladeRedis.get(getFileKey());
         InputStream zipFileInputStream = file.getInputStream();//test
         byte[] bytes = FileUtil.copyToByteArray(zipFileInputStream);
         list = parseMdmZipFromByteArray(bytes);
         */
         list = readTempDir(extractDir);
      } catch (IOException e) {
         log.error("导入涉密网摆渡文件失败",e);
         throw new ServiceException("解析DNC回传数据失败");
@@ -83,6 +101,65 @@
      return list;
   }
   public void extractZipToTempDir(Path zipFilePath,Path extractDir) throws IOException {
      // 获取系统临时目录
      String tempDir = System.getProperty("java.io.tmpdir");
      Path tempPath = Paths.get(tempDir);
      // 创建解压目标目录(在临时目录下创建一个唯一子目录)
      //Path extractDir = Files.createTempDirectory(tempPath, "unzip_");
      System.out.println("解压目录: " + extractDir.toString());
      //Files.newInputStream(Paths.get(zipFilePath));
      try (InputStream fis = Files.newInputStream(zipFilePath);
          ZipInputStream zis = new ZipInputStream(fis)) {
         ZipEntry zipEntry = zis.getNextEntry();
         while (zipEntry != null) {
            Path newPath = zipSlipProtect(zipEntry, extractDir);
            if (zipEntry.isDirectory()) {
               Files.createDirectories(newPath);
            } else {
               // 确保父目录存在
               if (newPath.getParent() != null) {
                  Files.createDirectories(newPath.getParent());
               }
               // 写入文件
               try (OutputStream fos = Files.newOutputStream(newPath)) {
                  byte[] buffer = new byte[1024];
                  int len;
                  while ((len = zis.read(buffer)) > 0) {
                     fos.write(buffer, 0, len);
                  }
               }
            }
            zipEntry = zis.getNextEntry();
         }
         zis.closeEntry();
      }
   }
   /**
    * 防止ZIP Slip攻击
    * @param zipEntry
    * @param targetDir
    * @return
    * @throws IOException
    */
   Path zipSlipProtect(ZipEntry zipEntry, Path targetDir) throws IOException {
      Path targetDirResolved = targetDir.resolve(zipEntry.getName());
      // 规范化路径
      Path normalizePath = targetDirResolved.normalize();
      if (!normalizePath.startsWith(targetDir)) {
         throw new IOException("恶意ZIP条目: " + zipEntry.getName());
      }
      return normalizePath;
   }
   /*
   public static List<MdmProgramImportVO> parseMdmZipFromByteArray(byte[] zipData) throws IOException {
      List<MdmProgramImportVO> list = new ArrayList<>();
      Map<String,String> fileMd5Map = new HashMap<>();
@@ -114,7 +191,155 @@
      });
      return list;
   }
   */
   public List<MdmProgramImportVO> readTempDir(Path extractDir) throws IOException {
      List<MdmProgramImportVO> list = new ArrayList<>();
      List<Machine> machines = machineService.lambdaQuery().eq(Machine::getStatus,Machine.STATUS_ENABLE).list();
      //读取所有文件夹
      //List<Path> dirs = Files.list(extractDir).filter(Files::isDirectory).toList();
      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) {
                     if (Files.isRegularFile(subPath)) {
                        System.out.println("找到文件: " + subPath);
                        //files.add(subPath.getFileName().toString());
                        // 这里可以添加对文件的处理逻辑
                     }
                  }
               }
               //vo.setFiles(files);
            } 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());
                  String line1 = FileContentUtil.readLineAt(bas,1);
                  //bas.mark(0);
                  bas.reset();
                  String line2 = FileContentUtil.readLineAt(bas,2);
                  System.out.println("line1="+line1);
                  Machine matchedMachine = null;
                  for (Machine machine : machines) {
                     if(Func.isNotBlank(machine.getProgSendDir()) && line1.contains(machine.getProgSendDir())){
                        matchedMachine = machine;
                        break;
                     }
                  }
                  if (matchedMachine != null) {
                     vo.setName(parseProgramName(vo.getFilename()));
                     vo.setMachineCode(matchedMachine.getCode());
                     //String sendPath = programAnnotationService.removeAnnotation(matchedMachine.getMachineGroupCode(),line1,"(",")");
                     vo.setFullPath(path.toString());//文件地址
                     vo.setSendPath(matchedMachine.getProgSendDir());
                     vo.setId(vo.getFullPath());
                     vo.setProgramStatus(programAnnotationService.removeAnnotation(matchedMachine.getMachineGroupCode(),line2,"(",")"));
                     list.add(vo);
                  }
               } catch (IOException e) {
                  log.error("读取文件md5失败",e);
               }
               //List<String> files = new ArrayList<>();
               // 这里可以添加对文件的处理逻辑
            }
         }
      }
      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);
               }
            }
         }
         //以上去掉了最后2段段数和段号
      }
      return drawingNo;
   }
   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段段数和段号
      }
      return programName;
   }
   /**
    * 入库mdm涉密网文件
@@ -123,77 +348,29 @@
    */
   public void mdmFileAccept(String ids) throws IOException {
      String pkgFileName = bladeRedis.get(getFileKey());
      List<String> idList = Func.toStrList(ids);
      List<Long> idList = Func.toLongList(ids);
      //
      updateProgramFile(pkgFileName,idList);
      String ditStr = bladeRedis.get(getFileKey());
      Path extractDir = Paths.get(ditStr);
      List<MdmProgramImportVO> list = readTempDir(extractDir);
      String destFileFull;
      for(String str : idList){
         System.out.println(str);
         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);
               break;
            }
         }
      }
   }
   /**
    * 更新程序文件
    * @param pkgFileName mdm程序包
    * @param idList 选定入库的
    */
   private void updateProgramFile(String pkgFileName,List<Long> idList) throws IOException {
      InputStream inputStream = this.ossTemplate.statFileStream(pkgFileName);
      byte[] bytes = FileUtil.copyToByteArray(inputStream);
      List<NcNode> nodeList = new ArrayList<>();
      List<NcProgram> progList = new ArrayList<>();
      List<ApproveRecord> recordList = new ArrayList<>();
      try (SeekableInMemoryByteChannel channel = new SeekableInMemoryByteChannel(bytes);
          ZipFile zipFile = new ZipFile(channel)) {
         ZipArchiveEntry entry;
         Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
         while (entries.hasMoreElements()) {
            entry = entries.nextElement();
            String entryName = entry.getName();
         }
      }
      for(NcNode node:nodeList){
         NcNode nodeTemp = this.ncNodeService.getById(node.getId());
         if(nodeTemp == null){
            ncNodeService.save(node);
         }else{
            ncNodeService.updateById(node);
         }
      }
      for(NcProgram prog:progList){
         NcProgram ncTemp = ncProgramService.getById(prog.getId());
         if(ncTemp == null){
            ncProgramService.save(prog);
         }else{
            ncProgramService.updateById(prog);
         }
      }
      for(ApproveRecord record:recordList) {
         ApproveRecord recordTemp = this.approveRecordService.getById(record.getId());
         if (recordTemp == null) {
            approveRecordService.save(record);
         } else {
            approveRecordService.updateById(record);
         }
      }
   }
   void setBaseProperties(BizEntity entity,JSONObject jsonObject){
      entity.setCreateTime(jsonObject.getDate("createTime"));
      entity.setUpdateTime(jsonObject.getDate("updateTime"));
      entity.setStatus(jsonObject.getInteger("status"));
      entity.setCreateUser(jsonObject.getLong("createUser"));
      entity.setUpdateUser(jsonObject.getLong("updateUser"));
   }
}