From 96c1135b98e321b0d592fa6b4e7e5239e59b47f4 Mon Sep 17 00:00:00 2001 From: eastargh Date: Thu, 17 Sep 2026 15:06:55 +0900 Subject: [PATCH] =?UTF-8?q?=EA=B1=B0=EB=9E=98=EB=A1=9C=EA=B7=B8=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=B2=98=EB=A6=AC=EA=B2=B0=EA=B3=BC(=EC=84=B1?= =?UTF-8?q?=EA=B3=B5/=EC=8B=A4=ED=8C=A8/=EC=98=A4=EB=A5=98)=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../onl/transaction/tracking/trackingMan.jsp | 76 ++++++++++++++++--- .../onl/logger/EAILogRepositoryImpl.java | 15 +++- .../tracking/DbTrackingService.java | 69 ++++++++++++++++- .../message/LocaleMessage_en.properties | 1 + .../message/LocaleMessage_ko.properties | 3 +- 5 files changed, 147 insertions(+), 17 deletions(-) diff --git a/WebContent/jsp/onl/transaction/tracking/trackingMan.jsp b/WebContent/jsp/onl/transaction/tracking/trackingMan.jsp index a9d0880..b25f31b 100644 --- a/WebContent/jsp/onl/transaction/tracking/trackingMan.jsp +++ b/WebContent/jsp/onl/transaction/tracking/trackingMan.jsp @@ -260,6 +260,59 @@ } + // 처리결과: ERRYN='Y'면 에러, 업무(BIZ) 오류코드(ERRCODE_BIZ)면 오류, 나머지는 성공 + // 단, SEQ(LOGPRCSSSERNO) 100/200은 아직 처리 완료 전 단계라 에러/오류가 아니면(=성공이면) 표시하지 않는다 + function computePrcsResult(errYn, eaiErrCd, logPrcssSerno) { + var isBizErr = eaiErrCd != null && bizErrCodeSet.has(String(eaiErrCd).trim()); + + // ERRYN은 EAIERRCTNT(에러내용)만 보고 Y/N을 매기므로 업무(BIZ) 오류도 Y가 된다. + // isBizErr을 먼저 봐야 업무오류가 "에러"로 잘못 표시되지 않는다. + if (isBizErr) { + return "오류"; + } else if (errYn == "Y") { + return "실패"; + } else if (logPrcssSerno == "100" || logPrcssSerno == "200") { + return ""; + } else { + return "성공"; + } + } + + // 같은 거래(EAISVCSERNO)의 400(응답)이 에러/오류면 300(요청)의 "성공" 표시를 지운다. + // jqGrid의 getCell/setCell은 formatter 결과가 아니라 원본 데이터를 읽고 쓰는데, PRCS_RESULT_TMP는 + // 서버 데이터에 없는 가상 컬럼이라 그 방식으로는 행 간 보정이 반영되지 않는다(직접 확인됨). + // 그래서 grid가 원본 JSON을 받는 시점(beforeProcessing)에 각 행에 PRCS_RESULT_TMP 값을 미리 계산해 + // 박아두고, formatter는 그 값을 그대로 꺼내 쓰기만 한다. + function applyPrcsResult(rows) { + var byEaiSvcSerno = {}; + rows.forEach(function (row) { + var key = row.EAISVCSERNO; + (byEaiSvcSerno[key] = byEaiSvcSerno[key] || []).push(row); + }); + + rows.forEach(function (row) { + var result = computePrcsResult(row.ERRYN, row.EAIERRCD, row.LOGPRCSSSERNO); + + if (row.LOGPRCSSSERNO == "300" && result == "성공") { + var siblings = byEaiSvcSerno[row.EAISVCSERNO] || []; + var has400Error = siblings.some(function (sib) { + if (sib.LOGPRCSSSERNO != "400") return false; + var sibResult = computePrcsResult(sib.ERRYN, sib.EAIERRCD, "400"); + return sibResult == "실패" || sibResult == "오류"; + }); + if (has400Error) { + result = ""; + } + } + + row.PRCS_RESULT_TMP = result; + }); + } + + function prcsResultFormatter(cellvalue, options, rowObject) { + return rowObject.PRCS_RESULT_TMP || ""; + } + $(document).ready(function () { console.log(roleString); @@ -306,7 +359,8 @@ '<%=localeMessage.getString("tracking.telgmrecvtrancd")%>', '<%= localeMessage.getString("eaiMessage.eaiSvcName")%>', '<%= localeMessage.getString("eaiMessage.eaiSvcDesc")%>', - '<%=localeMessage.getString("tracking.eaibzwkdstcd")%>', + '업무명', + '처리결과', '<%=localeMessage.getString("tracking.extBizName")%>', '<%=localeMessage.getString("tracking.ifDisKeyVal")%>', 'APP 명', @@ -330,14 +384,15 @@ {name: 'ERRYN', hidden: true}, {name: 'TRACKASISKEY1CTNT', hidden: true}, {name: 'TRACKASISKEY2CTNT', hidden: true}, - - {name: 'EAISVCSERNO_TMP', align: 'left', width: '220', formatter: trimFormatter}, + + {name: 'EAISVCSERNO_TMP', align: 'left', width: '120', formatter: trimFormatter}, {name: 'KEYMGTMSGCTNT', align: 'left', width: '300'}, {name: 'LOGPRCSSSERNO_TMP', align: 'center', width: '40'}, {name: 'TELGMRECVTRANCD', align: 'left', width: '135', hidden: true}, {name: 'EAISVCNAME', align: 'left', width: '160'}, {name: 'EAISVCDESC', align: 'left', width: '280'}, {name: 'EAIBZWKDSTCD_TMP', align: 'center', width: '50'}, + {name: 'PRCS_RESULT_TMP', align: 'center', width: '60', formatter: prcsResultFormatter}, {name: 'EXTBIZCD', align: 'center', width: '50', hidden: isApiGw}, {name: 'REFKEY', align: 'left', width: '280', hidden: isApiGw}, {name: 'CLIENTNAME', align: 'left', width: '120', hidden: !isApiGw}, @@ -356,6 +411,9 @@ jsonReader: { repeatitems: false }, + beforeProcessing: function (data) { + applyPrcsResult(data.rows || []); + }, rowNum: 10000, height: '520', viewrecords: true, @@ -394,21 +452,18 @@ var uniqueCount = calculateUniqueLogCount("#grid"); updateLogCountDisplay(uniqueCount, displayedLogs, totalLogs); - //에러 행 색상 표시 + //에러 행 색상 표시 (업무(BIZ) 오류는 배경색을 칠하지 않는다) var rows = $(this).getDataIDs(); for (var i = 0; i < rows.length; i++) { var errYn = $("#grid").getCell(rows[i], 'ERRYN'); var eaiErrCd = $("#grid").getCell(rows[i], 'EAIERRCD'); var isBizErr = eaiErrCd != null && bizErrCodeSet.has(String(eaiErrCd).trim()); - if (isBizErr) { - // 업무(BIZ) 오류코드(ERRCODE_BIZ) - 하늘색 배경 - $("#" + rows[i]).find("td").css("background-color", "#BEEDFF"); - } else if (errYn == "Y") { + if (errYn == "Y" && !isBizErr) { $("#" + rows[i]).find("td").css("background-color", "#FFCC99"); } } - + $("#grid").tuiTableRowSpan("7"); //1000건이상 alert @@ -627,8 +682,9 @@ <%=localeMessage.getString("tracking.logtype")%> - + + diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogRepositoryImpl.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogRepositoryImpl.java index 78e103c..0fd1688 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogRepositoryImpl.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogRepositoryImpl.java @@ -194,7 +194,11 @@ public class EAILogRepositoryImpl implements EAILogRepository { // query.where(qeaiLog.eaierrcd.trim().isNotEmpty()); // } - if (StringUtils.equalsIgnoreCase(eaiLogSearch.getSearchErrorYn(), "Y")) { + // Y: 에러로그(시스템 에러, ERRCODE_BIZ 제외) / B: 오류로그(업무오류, ERRCODE_BIZ만) + boolean searchErrLog = StringUtils.equalsIgnoreCase(eaiLogSearch.getSearchErrorYn(), "Y"); + boolean searchBizErrLog = StringUtils.equalsIgnoreCase(eaiLogSearch.getSearchErrorYn(), "B"); + + if (searchErrLog || searchBizErrLog) { // 에러 로그가 있는 eaisevrinstncname을 찾는 서브쿼리 // entityPathBase를 사용하여 동적 테이블에 대한 서브쿼리 생성 JPAQuery errorInstancesSubQuery = new JPAQueryFactory(em) @@ -206,12 +210,17 @@ public class EAILogRepositoryImpl implements EAILogRepository { qeaiLog.eaierrcd.trim().isNotEmpty() ); - // ERRCODE_BIZ(업무 오류) 코드는 시스템 에러가 아니므로 "에러로그" 검색 대상에서 제외 List bizErrCodes = codeService.findByIdCodegroup(ERRCODE_BIZ_GROUP).stream() .map(code -> code.getId().getCode()) .collect(Collectors.toList()); - if (!bizErrCodes.isEmpty()) { + if (searchBizErrLog) { + // 오류로그: 업무오류(ERRCODE_BIZ) 코드만 + errorInstancesSubQuery.where(bizErrCodes.isEmpty() + ? qeaiLog.eaierrcd.isNull().and(qeaiLog.eaierrcd.isNotNull()) // 등록된 업무오류 코드가 없으면 결과 없음 + : qeaiLog.eaierrcd.in(bizErrCodes)); + } else if (!bizErrCodes.isEmpty()) { + // 에러로그: ERRCODE_BIZ(업무 오류) 코드는 시스템 에러가 아니므로 제외 errorInstancesSubQuery.where(qeaiLog.eaierrcd.notIn(bizErrCodes)); } diff --git a/src/main/java/com/eactive/eai/rms/onl/transaction/tracking/DbTrackingService.java b/src/main/java/com/eactive/eai/rms/onl/transaction/tracking/DbTrackingService.java index c5d5399..7d338cc 100644 --- a/src/main/java/com/eactive/eai/rms/onl/transaction/tracking/DbTrackingService.java +++ b/src/main/java/com/eactive/eai/rms/onl/transaction/tracking/DbTrackingService.java @@ -7,6 +7,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; @@ -399,8 +400,13 @@ public class DbTrackingService extends BaseService { public List> selectListToExcel( EAILogSearch eaiLogSearch) { Page page = this.selectList(Pageable.unpaged(), eaiLogSearch); + List uiList = page.getContent(); + List prcsResults = computePrcsResults(uiList); - return page.getContent().stream().map(ui -> { + List> result = new ArrayList<>(); + + for (int i = 0; i < uiList.size(); i++) { + EAILogUI ui = uiList.get(i); Map map = new HashMap<>(); map.put("EAISVCSERNO_TMP", ui.getEaisvcserno()); @@ -409,14 +415,71 @@ public class DbTrackingService extends BaseService { map.put("EAISVCNAME", ui.getEaisvcname()); map.put("EAISVCDESC", ui.getEaisvcdesc()); map.put("EAIBZWKDSTCD_TMP", ui.getEaibzwkdstcd()); + map.put("PRCS_RESULT_TMP", prcsResults.get(i)); map.put("EXTBIZCD", ui.getExtbizcd()); map.put("REFKEY", ui.getRefkey()); map.put("MSGDPSTYMS_TMP", ui.getMsgdpstyms()); map.put("MSGPRCSSYMS", ui.getMsgprcssyms()); - return map; - }).collect(Collectors.toList()); + result.add(map); + } + return result; + } + + /** + * 처리결과(그리드의 PRCS_RESULT_TMP 컬럼과 동일한 판정) - trackingMan.jsp의 + * computePrcsResult/applyPrcsResult 와 동일한 규칙을 서버에서 재현한다(엑셀 다운로드는 + * 그리드가 아니라 이 서비스가 새로 조회한 결과를 쓰므로 그리드의 계산 결과를 재사용할 수 없다). + * + *

EAIERRCD가 업무(BIZ) 오류코드(ERRCODE_BIZ)면 "오류", ERRYN='Y'(에러내용 있음)면 "실패", + * SEQ(LOGPRCSSSERNO) 100/200은 아직 처리 완료 전 단계라 위 두 경우가 아니면 빈 값, 나머지는 "성공". + * 단, 같은 거래(EAISVCSERNO)의 400(응답)이 실패/오류면 300(요청)의 "성공"은 표시하지 않는다.

+ */ + private List computePrcsResults(List uiList) { + Set bizErrCodes = comboService.getFromCode("ERRCODE_BIZ").stream() + .map(ComboVo::getCode) + .collect(Collectors.toSet()); + + Map has400ErrorBySvcSerno = new HashMap<>(); + for (EAILogUI ui : uiList) { + if ("400".equals(ui.getLogprcssserno()) && isErrorResult(computeSinglePrcsResult(ui, bizErrCodes))) { + has400ErrorBySvcSerno.put(ui.getEaisvcserno(), true); + } + } + + List results = new ArrayList<>(uiList.size()); + for (EAILogUI ui : uiList) { + String result = computeSinglePrcsResult(ui, bizErrCodes); + + if ("300".equals(ui.getLogprcssserno()) && "성공".equals(result) + && Boolean.TRUE.equals(has400ErrorBySvcSerno.get(ui.getEaisvcserno()))) { + result = ""; + } + + results.add(result); + } + return results; + } + + private boolean isErrorResult(String result) { + return "실패".equals(result) || "오류".equals(result); + } + + private String computeSinglePrcsResult(EAILogUI ui, Set bizErrCodes) { + String eaiErrCd = ui.getEaierrcd(); + boolean isBizErr = eaiErrCd != null && bizErrCodes.contains(eaiErrCd.trim()); + String logPrcssSerno = ui.getLogprcssserno(); + + if (isBizErr) { + return "오류"; + } else if (StringUtils.isNotBlank(ui.getEaierrctnt())) { + return "실패"; + } else if ("100".equals(logPrcssSerno) || "200".equals(logPrcssSerno)) { + return ""; + } else { + return "성공"; + } } public Map> selectCombo() { diff --git a/src/main/resources/message/LocaleMessage_en.properties b/src/main/resources/message/LocaleMessage_en.properties index 72e5e09..3a3702d 100644 --- a/src/main/resources/message/LocaleMessage_en.properties +++ b/src/main/resources/message/LocaleMessage_en.properties @@ -2110,6 +2110,7 @@ tracking.eaisvcname = IF Service Code tracking.eaisvcserno = EAI Service No tracking.eaisvcserno_tmp = Service Serial No. tracking.errLog = Error Log +tracking.bizErrLog = Biz Error Log tracking.erryn = Error Yn tracking.extBizCd = External Biz.Code tracking.extBizName = Ext.Biz.Name diff --git a/src/main/resources/message/LocaleMessage_ko.properties b/src/main/resources/message/LocaleMessage_ko.properties index 4f326ce..0ae0545 100644 --- a/src/main/resources/message/LocaleMessage_ko.properties +++ b/src/main/resources/message/LocaleMessage_ko.properties @@ -2208,7 +2208,8 @@ tracking.eaisvcname = API \uBA85 tracking.eaisvcserno = EAI\uC11C\uBE44\uC2A4 \uBC88\uD638 tracking.eaisvcserno_tmp = \uAC70\uB798\uACE0\uC720\uBC88\uD638 tracking.errLog = \uC5D0\uB7EC\uB85C\uADF8 -tracking.erryn = \uC5D0\uB7EC\uC5EC\uBD80 +tracking.bizErrLog = \uC624\uB958\uB85C\uADF8 +tracking.erryn = \uC5D0\uB7EC\uC5EC\uBD80 tracking.extBizCd = \uB300\uC678\uC5C5\uBB34\uAD6C\uBD84 tracking.extBizName = \uB300\uC678\uC5C5\uBB34\uBA85 tracking.ifDisKeyVal = \uC5C5\uBB34 \uC11C\uBE44\uC2A4\uD0A4