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;
|
import org.springframework.web.bind.annotation.*;
|
import com.alibaba.fastjson.JSONObject;
|
import org.springframework.web.multipart.MultipartFile;
|
|
import java.io.*;
|
import java.nio.charset.StandardCharsets;
|
import java.nio.file.*;
|
import java.util.*;
|
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipInputStream;
|
|
@RestController
|
@Slf4j
|
@RequestMapping("/plmOuter")
|
public class DncWebController {
|
|
@Autowired
|
private DncWebService dncWebService;
|
|
@Value("${fileHomePath}")
|
private String filePath;
|
|
// 定义关键文件类型
|
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("接收到的压缩文件为空");
|
return MesResultModel.error("接收到的压缩文件为空");
|
}
|
|
// 创建临时目录
|
String timestamp = String.valueOf(System.currentTimeMillis());
|
workDir = Paths.get(filePath, "plm_" + timestamp);
|
Files.createDirectories(workDir);
|
|
// 保存原始文件
|
Path originalPath = workDir.resolve(
|
Objects.requireNonNull(file.getOriginalFilename())
|
);
|
Files.copy(file.getInputStream(), originalPath, StandardCopyOption.REPLACE_EXISTING);
|
log.info("原始文件已保存: {} (大小: {} 字节)",
|
originalPath,
|
Files.size(originalPath));
|
|
// 解析外层压缩包
|
Map<String, byte[]> packageContents = extractOuterZipContents(originalPath);
|
log.info("外层压缩包解析成功,包含 {} 个文件", packageContents.size());
|
|
// 不再查找单个ZIP,改为查找所有ZIP文件
|
byte[] jsonData = findFileByExtension(packageContents, JSON_EXT);
|
// 使用扩展名".zip"查找所有ZIP压缩包
|
List<byte[]> zipFiles = findAllFilesByExtension(packageContents, ".zip");
|
|
// 检查是否存在至少一个ZIP文件
|
if (jsonData == null || zipFiles.isEmpty()) {
|
String message = "未找到必要文件: " +
|
(jsonData == null ? "JSON文件" : "") +
|
(zipFiles.isEmpty() ? (jsonData == null ? " 和 " : "") + "NC程序压缩包" : "");
|
return MesResultModel.error(message);
|
}
|
|
// 解析JSON
|
String jsonFileName = getFileNameByExtension(packageContents);
|
PlmProgramSource plmPrograms = parseJsonFile(jsonData);
|
log.info("解析JSON文件成功: {}", jsonFileName);
|
|
// 创建Map存储所有NC文件(文件名->内容)
|
Map<String, byte[]> allNcFiles = new HashMap<>();
|
|
//遍历并解压所有找到的ZIP文件
|
for (byte[] zipData : zipFiles) {
|
Map<String, byte[]> ncFiles = extractInnerZipContents(zipData);
|
|
// 合并文件并检查重复
|
for (Map.Entry<String, byte[]> entry : ncFiles.entrySet()) {
|
String fileName = entry.getKey();
|
if (allNcFiles.containsKey(fileName)) {
|
log.warn("检测到重复NC文件名: {}", fileName);
|
}
|
allNcFiles.put(fileName, entry.getValue());
|
}
|
}
|
log.info("共解析 {} 个内部压缩包,合并得到 {} 个NC文件",
|
zipFiles.size(), allNcFiles.size());
|
|
// 设置NC文件集合
|
plmPrograms.setNcfiles(allNcFiles);
|
plmPrograms.setFilePath(originalPath.getParent().toString());
|
plmPrograms.setFileName(originalPath.toString());
|
|
// 业务处理
|
return JSONObject.toJSONString(
|
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());
|
Enumeration<ZipArchiveEntry> entries = zipFile.getEntries();
|
|
while (entries.hasMoreElements()) {
|
ZipArchiveEntry entry = entries.nextElement();
|
if (entry.isDirectory()) continue;
|
|
try (InputStream is = zipFile.getInputStream(entry)) {
|
byte[] data = IOUtils.toByteArray(is);
|
contents.put(entry.getName(), data);
|
log.debug("提取文件: {} ({} 字节)", entry.getName(), data.length);
|
}
|
}
|
}
|
log.info("Apache Commons解析成功");
|
} catch (Exception e) {
|
log.warn("Apache Commons解析失败,尝试标准库回退: {}", e.getMessage());
|
try (InputStream is = Files.newInputStream(filePath);
|
ZipInputStream zis = new ZipInputStream(is, StandardCharsets.ISO_8859_1)) {
|
|
ZipEntry entry;
|
while ((entry = zis.getNextEntry()) != null) {
|
if (entry.isDirectory()) continue;
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
byte[] buffer = new byte[8192];
|
int len;
|
while ((len = zis.read(buffer)) > 0) {
|
baos.write(buffer, 0, len);
|
}
|
|
String name = entry.getName();
|
contents.put(name, baos.toByteArray());
|
log.debug("回退提取文件: {}", name);
|
}
|
} catch (Exception ex) {
|
throw new IOException("无法解析ZIP文件: " + filePath, ex);
|
}
|
}
|
return contents;
|
}
|
|
private List<byte[]> findAllFilesByExtension(Map<String, byte[]> contents, String extension) {
|
String extLower = extension.toLowerCase();
|
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解析方法
|
private Map<String, byte[]> extractInnerZipContents(byte[] zipData) throws IOException {
|
Map<String, byte[]> files = new HashMap<>();
|
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(zipData);
|
ZipInputStream zis = new ZipInputStream(bais)) {
|
|
ZipEntry entry;
|
while ((entry = zis.getNextEntry()) != null) {
|
if (entry.isDirectory()) continue;
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
byte[] buffer = new byte[8192];
|
int len;
|
while ((len = zis.read(buffer)) != -1) {
|
baos.write(buffer, 0, len);
|
}
|
|
files.put(entry.getName(), baos.toByteArray());
|
}
|
}
|
return files;
|
}
|
|
/**
|
* 根据扩展名查找文件
|
*/
|
private byte[] findFileByExtension(Map<String, byte[]> contents, String extension) {
|
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) {
|
for (String key : contents.keySet()) {
|
if (key.toLowerCase().endsWith(JSON_EXT)) {
|
return key;
|
}
|
}
|
return "Unknown";
|
}
|
|
/**
|
* 解析JSON文件内容
|
*/
|
private PlmProgramSource parseJsonFile(byte[] jsonData) {
|
String json = new String(jsonData, StandardCharsets.UTF_8);
|
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());
|
}
|
}
|
}
|