lyh
3 天以前 2ab86210fb27787cb1be8976286b9b827f90997f
src/main/java/com/lxzn/webservice/controller/DncWebController.java
@@ -1,11 +1,14 @@
package com.lxzn.webservice.controller;
import com.lxzn.framework.domain.webservice.request.ThirdDeProgramSource;
import com.lxzn.framework.domain.webservice.request.PlmProgramSource;
import com.lxzn.webservice.DncWebService;
import com.lxzn.webservice.ext.MesResultModel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Transactional;
@@ -17,7 +20,6 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.util.*;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@@ -29,16 +31,22 @@
    @Autowired
    private DncWebService dncWebService;
    @Value("${ncPdm.file_path}")
    @Value("${fileHomePath}")
    private String filePath;
    // 定义关键文件类型
    private static final String INNER_ZIP_PREFIX = "【公开】NC程序文件 ";
    private static final String JSON_EXT = ".json";
    private static final String TXT_EXT = ".txt";
    /**
     * 集成plm数据,压缩包(里面是NC压缩包与JSON文件)
     * @param file
     * @return
     */
    @PostMapping(value = "/syncPlmNcLogProgram", consumes = "multipart/form-data")
    @Transactional
    public String processNcPackage(MultipartFile file) {
        Path workDir = null;
        try {
            if (file == null || file.isEmpty()) {
                log.error("接收到的压缩文件为空");
@@ -47,7 +55,7 @@
            // 创建临时目录
            String timestamp = String.valueOf(System.currentTimeMillis());
            Path workDir = Paths.get(filePath, timestamp);
            workDir = Paths.get(filePath, "plm_" + timestamp);
            Files.createDirectories(workDir);
            // 保存原始文件
@@ -92,7 +100,6 @@
                for (Map.Entry<String, byte[]> entry : ncFiles.entrySet()) {
                    String fileName = entry.getKey();
                    if (allNcFiles.containsKey(fileName)) {
                        // 修改点5:记录重复警告(实际业务中可能需要更严格处理)
                        log.warn("检测到重复NC文件名: {}", fileName);
                    }
                    allNcFiles.put(fileName, entry.getValue());
@@ -108,19 +115,183 @@
            // 业务处理
            return JSONObject.toJSONString(
                    dncWebService.setTree(plmPrograms)
                    dncWebService.setPlmTree(plmPrograms)
            );
        } catch (Exception e) {
            log.error("处理NC文件包失败", e);
            return MesResultModel.error("文件处理失败: " + e.getMessage());
        } finally {
            // 清理临时文件
            if (workDir != null) {
                deleteDirectory(workDir.toFile());
            }
        }
    }
    /**
    * 集成3DE数据,压缩包(单个压缩包包含多个NC文件、一个工艺数据.TXT)
     * @param file 上传的压缩包文件
     * @return 处理结果
     */
    @PostMapping(value = "/integration3DEData", consumes = "multipart/form-data")
    @Transactional
    public String integration3DEData(MultipartFile file) {
        Path workDir = null;
        try {
            if (file == null || file.isEmpty()) {
                log.error("接收到的3DE压缩文件为空");
                return MesResultModel.error("接收到的3DE压缩文件为空");
            }
            // 创建临时工作目录
            String timestamp = String.valueOf(System.currentTimeMillis());
            workDir = Paths.get(filePath, "3de_" + timestamp);
            Files.createDirectories(workDir);
            // 保存原始文件
            Path originalPath = workDir.resolve(
                    Objects.requireNonNull(file.getOriginalFilename())
            );
            Files.copy(file.getInputStream(), originalPath, StandardCopyOption.REPLACE_EXISTING);
            log.info("3DE原始文件已保存: {} (大小: {} 字节)",
                    originalPath, Files.size(originalPath));
            // 解压ZIP包获取所有文件
            Map<String, byte[]> packageContents = extractOuterZipContents(originalPath);
            log.info("3DE压缩包解析成功,包含 {} 个文件", packageContents.size());
            // 查找工艺数据TXT文件
            byte[] processData = findFileByExtension(packageContents, TXT_EXT);
            if (processData == null) {
                return MesResultModel.error("未找到工艺数据TXT文件");
            }
            // 解析工艺数据TXT文件
            ThirdDeProgramSource thirdDeProgramSource = parseProcessTxtFile(processData);
            if (thirdDeProgramSource == null) {
                return MesResultModel.error("解析工艺数据TXT文件失败");
            }
            // 提取所有NC文件
            Map<String, byte[]> ncFiles = extractNcFiles(packageContents);
            if (ncFiles.isEmpty()) {
                return MesResultModel.error("未找到NC程序文件");
            }
            log.info("找到 {} 个NC程序文件", ncFiles.size());
            // 设置NC文件集合和文件路径信息
            thirdDeProgramSource.setNcFiles(ncFiles);
            thirdDeProgramSource.setFilePath(workDir.toString());
            thirdDeProgramSource.setFileName(originalPath.getFileName().toString());
            // 调用服务处理3DE数据
            return JSONObject.toJSONString(
                    dncWebService.processThirdDEProgram(thirdDeProgramSource)
            );
        } catch (Exception e) {
            log.error("处理3DE数据包失败", e);
            return MesResultModel.error("3DE文件处理失败: " + e.getMessage());
        } finally {
            // 清理临时文件
            if (workDir != null) {
                deleteDirectory(workDir.toFile());
            }
        }
    }
    /**
     * 解析工艺数据TXT文件
     * @param txtData TXT文件内容
     * @return ThirdDeProgramSource对象
     */
    private ThirdDeProgramSource parseProcessTxtFile(byte[] txtData) {
        try {
            String content = new String(txtData, StandardCharsets.UTF_8);
            log.info("工艺数据TXT内容:\n{}", content);
            // 使用FastJSON解析JSON格式的TXT
            JSONObject json = JSONObject.parseObject(content);
            if (json == null) {
                log.error("解析工艺数据失败: 不是有效的JSON格式");
                return null;
            }
            // 创建对象并设置属性
            ThirdDeProgramSource programSource = new ThirdDeProgramSource();
            programSource.setPartName(json.getString("part_name"));
            programSource.setPartNo(json.getString("part_no"));
            programSource.setRevisionNo(json.getString("revision_no"));
            programSource.setSkgxId(json.getString("skgx_id"));
            programSource.setSkgxName(json.getString("skgx_name"));
            programSource.setNcJcid(json.getString("nc_jcid"));
            programSource.setNcOs(json.getString("nc_os"));
            programSource.setEquipmentId(json.getString("equipment_id"));
            programSource.setNcFileName(json.getString("nc_file_name"));
            programSource.setNcPlantNo(json.getString("nc_plant_no"));
            programSource.setNcPlantName(json.getString("nc_plant_name"));
            log.debug("解析的工艺数据: partName={}, partNo={}, revisionNo={}, skgxId={}, skgxName={}, " +
                            "ncJcid={}, ncOs={}, equipmentId={}, ncFileName={}, ncPlantNo={}, ncPlantName={}",
                    programSource.getPartName(), programSource.getPartNo(),
                    programSource.getRevisionNo(), programSource.getSkgxId(),
                    programSource.getSkgxName(), programSource.getNcJcid(),
                    programSource.getNcOs(), programSource.getEquipmentId(),
                    programSource.getNcFileName(), programSource.getNcPlantNo(),
                    programSource.getNcPlantName());
            return programSource;
        } catch (Exception e) {
            log.error("解析工艺数据TXT文件失败", e);
            return null;
        }
    }
    /**
     * 解析键值对格式的TXT文件
     * @param content TXT文件内容
     * @return 键值对映射
     */
    private Map<String, String> parseKeyValueTxt(String content) {
        Map<String, String> result = new HashMap<>();
        String[] lines = content.split("\\r?\\n");
        for (String line : lines) {
            line = line.trim();
            if (line.isEmpty() || line.startsWith("#") || line.startsWith("//")) {
                continue; // 跳过空行和注释
            }
            int separatorIndex = line.indexOf('=');
            if (separatorIndex > 0) {
                String key = line.substring(0, separatorIndex).trim();
                String value = line.substring(separatorIndex + 1).trim();
                result.put(key, value);
            }
        }
        return result;
    }
    /**
     * 从文件内容中提取NC文件
     * @param packageContents 包内容映射
     * @return NC文件映射
     */
    private Map<String, byte[]> extractNcFiles(Map<String, byte[]> packageContents) {
        Map<String, byte[]> ncFiles = new HashMap<>();
        for (Map.Entry<String, byte[]> entry : packageContents.entrySet()) {
            String fileName = entry.getKey();
            String fileExt = FilenameUtils.getExtension(fileName).toLowerCase();
            if (fileExt.equals("nc")) {
                ncFiles.put(fileName, entry.getValue());
                log.debug("找到NC文件: {}", fileName);
            }
        }
        return ncFiles;
    }
    // 优化后的解压方法(使用commons-compress)
    private Map<String, byte[]> extractOuterZipContents(Path filePath) throws IOException {
        Map<String, byte[]> contents = new HashMap<>();
        log.info("开始解析ZIP文件: {}", filePath);
        try {
            try (ZipFile zipFile = new ZipFile(filePath.toFile())) {
                log.info("ZIP文件格式检测: {}", zipFile.getEncoding());
@@ -131,17 +302,9 @@
                    if (entry.isDirectory()) continue;
                    try (InputStream is = zipFile.getInputStream(entry)) {
                        ByteArrayOutputStream baos = new ByteArrayOutputStream();
                        byte[] buffer = new byte[8192];
                        int len;
                        while ((len = is.read(buffer)) > 0) {
                            baos.write(buffer, 0, len);
                        }
                        // 保留原始文件名
                        String name = entry.getName();
                        contents.put(name, baos.toByteArray());
                        log.debug("提取文件: {} ({} 字节)", name, baos.size());
                        byte[] data = IOUtils.toByteArray(is);
                        contents.put(entry.getName(), data);
                        log.debug("提取文件: {} ({} 字节)", entry.getName(), data.length);
                    }
                }
            }
@@ -175,14 +338,15 @@
    private List<byte[]> findAllFilesByExtension(Map<String, byte[]> contents, String extension) {
        String extLower = extension.toLowerCase();
        return contents.entrySet().stream()
                .filter(e -> {
                    String fileName = e.getKey();
                    // 使用小写比较避免大小写敏感问题
                    return fileName.toLowerCase().endsWith(extLower);
                })
                .map(Map.Entry::getValue)
                .collect(Collectors.toList());
        List<byte[]> result = new ArrayList<>();
        for (Map.Entry<String, byte[]> entry : contents.entrySet()) {
            String fileName = entry.getKey().toLowerCase();
            if (fileName.endsWith(extLower)) {
                result.add(entry.getValue());
            }
        }
        return result;
    }
    // 内部ZIP解析方法
@@ -213,57 +377,25 @@
     * 根据扩展名查找文件
     */
    private byte[] findFileByExtension(Map<String, byte[]> contents, String extension) {
        return contents.entrySet().stream()
                .filter(e -> e.getKey().toLowerCase().endsWith(extension))
                .map(Map.Entry::getValue)
                .findFirst()
                .orElse(null);
        String extLower = extension.toLowerCase();
        for (Map.Entry<String, byte[]> entry : contents.entrySet()) {
            if (entry.getKey().toLowerCase().endsWith(extLower)) {
                return entry.getValue();
            }
        }
        return null;
    }
    /**
     * 获取文件名(根据扩展名)
     */
    private String getFileNameByExtension(Map<String, byte[]> contents) {
        return contents.keySet().stream()
                .filter(k -> k.toLowerCase().endsWith(DncWebController.JSON_EXT))
                .findFirst()
                .orElse("Unknown");
    }
    /**
     * 查找与指定前缀匹配的文件内容
    * @param contents 文件内容映射(文件名 -> 文件内容)
    * @param prefix 要匹配的文件名前缀
    * @return 匹配的第一个文件内容,未找到返回 null
    */
    private byte[] findFileByPrefix(Map<String, byte[]> contents, String prefix) {
        if (prefix == null || prefix.isEmpty()) {
            log.warn("文件前缀不能为空");
            return null;
        for (String key : contents.keySet()) {
            if (key.toLowerCase().endsWith(JSON_EXT)) {
                return key;
            }
        }
        return contents.entrySet().stream()
                .filter(entry -> {
                    String fileName = entry.getKey();
                    // 路径规范化处理
                    String normalizedKey = fileName.replace('\\', '/');
                    // 获取纯文件名
                    int lastSlash = normalizedKey.lastIndexOf('/');
                    String pureFileName = (lastSlash >= 0) ?
                            normalizedKey.substring(lastSlash + 1) :
                            normalizedKey;
                    // 调试日志
                    log.debug("检查文件: [原始: {}], [纯文件名: {}], 前缀: {}",
                            fileName, pureFileName, prefix);
                    return pureFileName.contains("NC");
                })
                .map(Map.Entry::getValue)
                .findFirst()
                .orElse(null);
        return "Unknown";
    }
    /**
@@ -274,4 +406,26 @@
        return JSONObject.parseObject(json, PlmProgramSource.class);
    }
    /**
     * 递归删除目录
     */
    private void deleteDirectory(File directory) {
        if (!directory.exists()) return;
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    deleteDirectory(file);
                } else {
                    if (!file.delete()) {
                        log.warn("无法删除文件: {}", file.getAbsolutePath());
                    }
                }
            }
        }
        if (!directory.delete()) {
            log.warn("无法删除目录: {}", directory.getAbsolutePath());
        }
    }
}