도면업로드 품번 디비에서 매칭

This commit is contained in:
2026-03-19 09:46:22 +09:00
parent 8d330d12ac
commit 6bc46161e8
2 changed files with 58 additions and 189 deletions

View File

@@ -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++) {

View File

@@ -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<ArrayList<String>>(){}.getType();
java.util.List<String> 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<String, Object> partParam = new HashMap<>();
partParam.put("IS_LAST", "1");
partParam.put("PART_NO_LIST", partNoList);
ArrayList<Map> partList = commonService.selectList("partMng.partMngListByPartNos", request, partParam);
if(partList == null || partList.isEmpty()) {
@@ -2802,7 +2767,7 @@ public class PartMngController {
return resultMap;
}
// 품번 기준 파트 맵 생성 (화면에 표시된 파트만)
// 품번 기준 파트 맵 생성
Map<String, 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<String> 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;
}
}