From 6bc46161e8c3ffd64fbeb85dbea181cfc383391c Mon Sep 17 00:00:00 2001 From: hjjeong Date: Thu, 19 Mar 2026 09:46:22 +0900 Subject: [PATCH] =?UTF-8?q?=EB=8F=84=EB=A9=B4=EC=97=85=EB=A1=9C=EB=93=9C?= =?UTF-8?q?=20=ED=92=88=EB=B2=88=20=EB=94=94=EB=B9=84=EC=97=90=EC=84=9C=20?= =?UTF-8?q?=EB=A7=A4=EC=B9=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../WEB-INF/view/partMng/partMngList.jsp | 32 --- src/com/pms/controller/PartMngController.java | 215 +++++------------- 2 files changed, 58 insertions(+), 189 deletions(-) diff --git a/WebContent/WEB-INF/view/partMng/partMngList.jsp b/WebContent/WEB-INF/view/partMng/partMngList.jsp index bf9a759..321a6c4 100644 --- a/WebContent/WEB-INF/view/partMng/partMngList.jsp +++ b/WebContent/WEB-INF/view/partMng/partMngList.jsp @@ -336,19 +336,6 @@ String connector = person.getUserId(); return; } - // 선택된 파트 확인 (필수 아님 - 전체 파트 대상) - var selectedParts = _tabulGrid.getSelectedData(); - if(!selectedParts || selectedParts.length === 0) { - // 선택 없으면 전체 파트 대상으로 진행 - var confirmMsg = '파트를 선택하지 않았습니다.\n'; - confirmMsg += '전체 파트를 대상으로 파일명과 일치하는 품번에 업로드됩니다.\n'; - confirmMsg += '계속하시겠습니까?'; - - if(!confirm(confirmMsg)) { - return; - } - } - // 파일 분류 및 처리 var filesByType = { '3D': [], // stp 파일 @@ -406,28 +393,9 @@ String connector = person.getUserId(); // 실제 업로드 처리 function fn_processDrawingUpload(filesByType) { - // 현재 그리드에 표시된 파트 데이터 가져오기 - var gridData = _tabulGrid.getData(); - if(!gridData || gridData.length === 0) { - Swal.fire('페이지에 표시된 파트가 없습니다.'); - return; - } - - // 품번 목록 생성 (현재 화면에 보이는 파트만) - var partNoList = []; - for(var i = 0; i < gridData.length; i++) { - var partNo = gridData[i].PART_NO; - if(partNo) { - partNoList.push(partNo); - } - } - // FormData 생성 var formData = new FormData(); - // 현재 화면의 품번 목록 전송 - formData.append('partNoList', JSON.stringify(partNoList)); - // 모든 파일을 files 이름으로 추가 var allFiles = filesByType['3D'].concat(filesByType['2D']).concat(filesByType['PDF']); for(var i = 0; i < allFiles.length; i++) { diff --git a/src/com/pms/controller/PartMngController.java b/src/com/pms/controller/PartMngController.java index 44ecad9..02f5cb8 100644 --- a/src/com/pms/controller/PartMngController.java +++ b/src/com/pms/controller/PartMngController.java @@ -2666,26 +2666,16 @@ public class PartMngController { continue; } - // 품번 추출 (맨 마지막 확장자만 제거 후 하이픈 기준 추출) - String extractedPartNo = extractPartNoFromFileName(originalFileName); - - // 품번과 정확히 일치하는 경우만 매칭 - String matchedPartNo = null; - System.out.println("품번 매칭 시작 - 추출된 품번: " + extractedPartNo); - - if(extractedPartNo != null && !extractedPartNo.isEmpty()) { - // 정확한 매칭 (추출된 품번과 DB 품번이 정확히 일치) - if(partNoMap.containsKey(extractedPartNo)) { - matchedPartNo = extractedPartNo; - System.out.println(" ✓ 품번 정확 매칭 성공: " + matchedPartNo); - } - } + // 파일명에서 확장자 제거 후 DB 품번과 매칭 + String fileNameWithoutExt = removeFileExtensions(originalFileName); + String matchedPartNo = findMatchingPartNo(fileNameWithoutExt, partNoMap.keySet()); if(matchedPartNo == null) { - System.out.println(" ✗ 품번 매칭 실패 - 파일명: " + originalFileName + ", 추출된 품번: " + extractedPartNo); + System.out.println(" ✗ 품번 매칭 실패 - 파일명: " + originalFileName + ", 확장자 제거: " + fileNameWithoutExt); notFoundCount++; continue; } + System.out.println(" ✓ 품번 매칭 성공: " + matchedPartNo + " (파일: " + originalFileName + ")"); // 해당 파트에 파일 정보 저장 Map partInfo = partNoMap.get(matchedPartNo); @@ -2766,34 +2756,9 @@ public class PartMngController { multi = new MultipartRequest(request, storagePath, maxSize, "UTF-8", frc); java.util.List fileList = frc.getFileList(); - // 화면에서 전달된 품번 목록 가져오기 - String partNoListJson = multi.getParameter("partNoList"); - if(partNoListJson == null || partNoListJson.isEmpty()) { - resultMap.put("result", "fail"); - resultMap.put("message", "품번 목록이 전달되지 않았습니다."); - return resultMap; - } - - // JSON 파싱 (Gson 사용) - Gson gson = new Gson(); - Type listType = new TypeToken>(){}.getType(); - java.util.List partNoList = gson.fromJson(partNoListJson, listType); - - if(partNoList.isEmpty()) { - resultMap.put("result", "fail"); - resultMap.put("message", "페이지에 표시된 파트가 없습니다."); - return resultMap; - } - - System.out.println("========== 화면에서 전달된 품번 목록 =========="); - System.out.println("품번 개수: " + partNoList.size()); - System.out.println("품번 목록: " + partNoList); - System.out.println("=========================================="); - - // 전달된 품번 목록에 해당하는 파트만 조회 + // 전체 파트 조회 (IS_LAST='1') Map partParam = new HashMap<>(); partParam.put("IS_LAST", "1"); - partParam.put("PART_NO_LIST", partNoList); ArrayList partList = commonService.selectList("partMng.partMngListByPartNos", request, partParam); if(partList == null || partList.isEmpty()) { @@ -2802,7 +2767,7 @@ public class PartMngController { return resultMap; } - // 품번 기준 파트 맵 생성 (화면에 표시된 파트만) + // 품번 기준 파트 맵 생성 Map partNoMap = new HashMap<>(); for(Map part : partList) { String partNo = CommonUtils.checkNull((String)part.get("PART_NO")); @@ -2811,7 +2776,9 @@ public class PartMngController { } } + System.out.println("========== 전체 파트 품번 매칭 대상 =========="); System.out.println("매칭 가능한 품번 개수: " + partNoMap.size()); + System.out.println("=========================================="); int successCount = 0; int failCount = 0; @@ -2863,31 +2830,20 @@ public class PartMngController { docType = "2D_PDF_CAD"; docTypeName = "2D(PDF) CAD 첨부파일"; } else { - // 지원하지 않는 확장자는 스킵 System.out.println("지원하지 않는 확장자: " + fileExt + ", 파일명: " + originalFileName); continue; } - // 품번 추출 (맨 마지막 확장자만 제거 후 하이픈 기준 추출) - String extractedPartNo = extractPartNoFromFileName(originalFileName); - - // 품번과 정확히 일치하는 경우만 매칭 - String matchedPartNo = null; - System.out.println("품번 매칭 시작 - 추출된 품번: " + extractedPartNo); - - if(extractedPartNo != null && !extractedPartNo.isEmpty()) { - // 정확한 매칭 (추출된 품번과 DB 품번이 정확히 일치) - if(partNoMap.containsKey(extractedPartNo)) { - matchedPartNo = extractedPartNo; - System.out.println(" ✓ 품번 정확 매칭 성공: " + matchedPartNo); - } - } + // 파일명에서 확장자 제거 후 DB 품번과 매칭 + String fileNameWithoutExt = removeFileExtensions(originalFileName); + String matchedPartNo = findMatchingPartNo(fileNameWithoutExt, partNoMap.keySet()); if(matchedPartNo == null) { - System.out.println(" ✗ 품번 매칭 실패 - 파일명: " + originalFileName + ", 추출된 품번: " + extractedPartNo); + System.out.println(" ✗ 품번 매칭 실패 - 파일명: " + originalFileName + ", 확장자 제거: " + fileNameWithoutExt); notFoundCount++; continue; } + System.out.println(" ✓ 품번 매칭 성공: " + matchedPartNo + " (파일: " + originalFileName + ")"); // 해당 파트에 파일 정보 저장 Map partInfo = partNoMap.get(matchedPartNo); @@ -2936,114 +2892,59 @@ public class PartMngController { } /** - * 파일명에서 품번을 추출하는 헬퍼 메서드 - * - * 품번 추출 규칙: - * 1. 모든 확장자 제거 (.idw.pdf → .idw도 제거) - * 2. 확장자 제거 후 첫 번째 하이픈(-) 위치 찾기 - * 3. 하이픈 앞 자릿수에 따라 품번 길이 결정 - * - 5자리: 하이픈 포함 10자리 추출 (예: 20002-0043) - * - 7자리: 하이픈 포함 16자리 추출 (예: 2000200-004300-01) - * - * @param fileName 원본 파일명 (예: "20002-0043.idw.pdf") - * @return 추출된 품번 (예: "20002-0043") 또는 null + * 파일명에서 알려진 확장자를 모두 제거 + * 이중/삼중 확장자 대응 (예: file.idw.pdf → file) */ - private String extractPartNoFromFileName(String fileName) { + private String removeFileExtensions(String fileName) { if(fileName == null || fileName.isEmpty()) { return null; } - try { - // 1단계: 모든 확장자 제거 (이중/삼중 확장자 대응) - // 알려진 CAD 확장자 목록 - String[] cadExtensions = {".idw", ".dwg", ".dxf", ".stp", ".step", ".pdf", ".chg"}; - - String fileNameWithoutExt = fileName; - - // 반복적으로 확장자 제거 (예: file.idw.pdf → file.idw → file) - boolean extensionRemoved = true; - while(extensionRemoved) { - extensionRemoved = false; - - // 마지막 점 찾기 - int lastDotIndex = fileNameWithoutExt.lastIndexOf('.'); - if(lastDotIndex > 0) { - String currentExt = fileNameWithoutExt.substring(lastDotIndex).toLowerCase(); - - // 알려진 CAD 확장자인 경우 제거 - for(String ext : cadExtensions) { - if(currentExt.equals(ext)) { - fileNameWithoutExt = fileNameWithoutExt.substring(0, lastDotIndex); - extensionRemoved = true; - System.out.println("[품번 추출] 확장자 제거: " + currentExt + " → " + fileNameWithoutExt); - break; - } + String[] knownExtensions = {".idw", ".dwg", ".dxf", ".stp", ".step", ".pdf", ".chg"}; + String result = fileName; + + boolean extensionRemoved = true; + while(extensionRemoved) { + extensionRemoved = false; + int lastDotIndex = result.lastIndexOf('.'); + if(lastDotIndex > 0) { + String currentExt = result.substring(lastDotIndex).toLowerCase(); + for(String ext : knownExtensions) { + if(currentExt.equals(ext)) { + result = result.substring(0, lastDotIndex); + extensionRemoved = true; + break; } } } - - System.out.println("[품번 추출] 1단계 완료 - 모든 확장자 제거: " + fileNameWithoutExt); - - // 2단계: 첫 번째 하이픈 위치 찾기 - int firstHyphenIndex = fileNameWithoutExt.indexOf('-'); - if(firstHyphenIndex == -1) { - System.out.println("[품번 추출] 하이픈이 없음 - 추출 실패"); - return null; - } - - // 3단계: 하이픈 앞 자릿수 확인 - String beforeHyphen = fileNameWithoutExt.substring(0, firstHyphenIndex); - int beforeHyphenLength = beforeHyphen.length(); - - System.out.println("[품번 추출] 2단계 - 하이픈 앞 문자열: " + beforeHyphen + " (길이: " + beforeHyphenLength + ")"); - - // 4단계: 자릿수에 따라 품번 추출 - String extractedPartNo = null; - - if(beforeHyphenLength == 5) { - // 스핀들 설계팀: 5자리 -> 하이픈 1개 (5-4 = 10자리) - // 예: 20002-0043 - int targetLength = 10; - if(fileNameWithoutExt.length() >= targetLength) { - extractedPartNo = fileNameWithoutExt.substring(0, targetLength); - System.out.println("[품번 추출] 3단계 - 5자리 패턴 (10자리 추출): " + extractedPartNo); - } else { - System.out.println("[품번 추출] 5자리 패턴이지만 총 길이가 10자리 미만 - 추출 실패"); - } - } else if(beforeHyphenLength == 7) { - // 장비 개발팀: 7자리 -> 하이픈이 1개 또는 2개 - // 하이픈 1개: 7-9 = 17자리 (예: 2000200-004300-0) - // 하이픈 2개: 7-6-2 = 18자리 (예: 2000200-004300-02) - - // 두 번째 하이픈이 있는지 확인 - int secondHyphenIndex = fileNameWithoutExt.indexOf('-', firstHyphenIndex + 1); - - if(secondHyphenIndex != -1) { - // 하이픈이 2개인 경우: 7-6-2 패턴 = 18자리 - // 예: 2000200-004300-02 - extractedPartNo = fileNameWithoutExt; - System.out.println("[품번 추출] 3단계 - 7자리 패턴 (하이픈 2개, 전체 품번): " + extractedPartNo); - } else { - // 하이픈이 1개인 경우: 7-9 패턴 = 17자리 - // 예: 2000200-004300-0 (16자리만 추출) - int targetLength = 16; - if(fileNameWithoutExt.length() >= targetLength) { - extractedPartNo = fileNameWithoutExt.substring(0, targetLength); - System.out.println("[품번 추출] 3단계 - 7자리 패턴 (하이픈 1개, 16자리 추출): " + extractedPartNo); - } else { - System.out.println("[품번 추출] 7자리 패턴이지만 총 길이가 16자리 미만 - 추출 실패"); - } - } - } else { - System.out.println("[품번 추출] 하이픈 앞이 5자리 또는 7자리가 아님 - 추출 실패"); - } - - return extractedPartNo; - - } catch(Exception e) { - System.out.println("[품번 추출] 예외 발생: " + e.getMessage()); - e.printStackTrace(); + } + return result; + } + + /** + * 확장자 제거된 파일명에서 DB 품번과 매칭 + * 파일명이 품번과 일치하거나 품번으로 시작하는 경우 매칭 + * 여러 품번이 매칭되면 가장 긴 품번 우선 (정확도 높은 매칭) + */ + private String findMatchingPartNo(String fileNameWithoutExt, java.util.Set partNoSet) { + if(fileNameWithoutExt == null || fileNameWithoutExt.isEmpty() || partNoSet == null) { return null; } + + // 정확 매칭 우선 + if(partNoSet.contains(fileNameWithoutExt)) { + return fileNameWithoutExt; + } + + // 파일명이 품번으로 시작하는지 확인 (가장 긴 품번 우선) + String bestMatch = null; + for(String partNo : partNoSet) { + if(fileNameWithoutExt.startsWith(partNo)) { + if(bestMatch == null || partNo.length() > bestMatch.length()) { + bestMatch = partNo; + } + } + } + return bestMatch; } }