From d8184c5fe2615c8f7151a23610c9907bea59a4d6 Mon Sep 17 00:00:00 2001 From: daekuk Date: Tue, 23 Dec 2025 16:35:03 +0900 Subject: [PATCH 01/32] =?UTF-8?q?=EC=8A=A4=EC=BD=94=ED=94=84=EC=97=90=20?= =?UTF-8?q?=EB=A7=A4=ED=95=91=EB=90=9C=20API=EA=B0=80=20eq=EA=B0=80=20?= =?UTF-8?q?=EC=95=84=EB=8B=8C=20like=20=EB=A1=9C=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=ED=95=B4=20=EB=8B=A4=EB=A5=B8=20id=EC=9D=98=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EB=A5=BC=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B3=A0=20?= =?UTF-8?q?=EC=9E=88=EC=96=B4=EC=84=9C=20=ED=8C=A8=EC=B9=98=ED=95=A8.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eai/rms/data/entity/onl/eaimsg/EAIMessageService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/eaimsg/EAIMessageService.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/eaimsg/EAIMessageService.java index 4bf2428..0cdc9c3 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/eaimsg/EAIMessageService.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/eaimsg/EAIMessageService.java @@ -320,7 +320,7 @@ public class EAIMessageService extends AbstractDataService Date: Wed, 24 Dec 2025 14:59:09 +0900 Subject: [PATCH 02/32] =?UTF-8?q?-=20EmptyJsonResponse=20=EA=B1=B0?= =?UTF-8?q?=EC=B3=90=20=EC=A0=95=EC=83=81=EC=B2=98=EB=A6=AC=20=EB=90=A0=20?= =?UTF-8?q?=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95.?= =?UTF-8?q?=20-=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20import=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InflowGroupControlManController.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/inflow/group/InflowGroupControlManController.java b/src/main/java/com/eactive/eai/rms/onl/manage/inflow/group/InflowGroupControlManController.java index ab4fe96..c3e31bf 100644 --- a/src/main/java/com/eactive/eai/rms/onl/manage/inflow/group/InflowGroupControlManController.java +++ b/src/main/java/com/eactive/eai/rms/onl/manage/inflow/group/InflowGroupControlManController.java @@ -7,6 +7,14 @@ import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import com.eactive.eai.agent.command.CommonCommand; +import com.eactive.eai.rms.common.base.OnlBaseAnnotationController; +import com.eactive.eai.rms.common.combo.ComboService; +import com.eactive.eai.rms.common.combo.ComboVo; +import com.eactive.eai.rms.common.vo.GridResponse; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -16,14 +24,6 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.servlet.ModelAndView; -import com.eactive.eai.agent.command.CommonCommand; -import com.eactive.eai.rms.common.base.OnlBaseAnnotationController; -import com.eactive.eai.rms.common.combo.ComboService; -import com.eactive.eai.rms.common.combo.ComboVo; -import com.eactive.eai.rms.common.vo.GridResponse; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; - @Controller public class InflowGroupControlManController extends OnlBaseAnnotationController { @@ -78,7 +78,7 @@ public class InflowGroupControlManController extends OnlBaseAnnotationController * 그룹 저장 (INSERT) */ @RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=INSERT") - public String insert(HttpServletRequest request, HttpServletResponse response, InflowGroupControlManUI ui, + public ResponseEntity insert(HttpServletRequest request, HttpServletResponse response, InflowGroupControlManUI ui, @RequestParam(value = "interfaceListJson", required = false) String interfaceListJson) throws Exception { parseInterfaceList(ui, interfaceListJson); String modifiedBy = getSessionUserId(request); @@ -88,14 +88,14 @@ public class InflowGroupControlManController extends OnlBaseAnnotationController CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.ReloadInflowGroupControlCommand", ui.getGroupId()); agentUtilService.broadcast(command); - return null; + return ResponseEntity.ok().build(); } /** * 그룹 저장 (UPDATE) */ @RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=UPDATE") - public String update(HttpServletRequest request, HttpServletResponse response, InflowGroupControlManUI ui, + public ResponseEntity update(HttpServletRequest request, HttpServletResponse response, InflowGroupControlManUI ui, @RequestParam(value = "interfaceListJson", required = false) String interfaceListJson) throws Exception { parseInterfaceList(ui, interfaceListJson); String modifiedBy = getSessionUserId(request); @@ -105,21 +105,21 @@ public class InflowGroupControlManController extends OnlBaseAnnotationController CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.ReloadInflowGroupControlCommand", ui.getGroupId()); agentUtilService.broadcast(command); - return null; + return ResponseEntity.ok().build(); } /** * 그룹 삭제 */ @RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=DELETE") - public String delete(HttpServletRequest request, HttpServletResponse response, String groupId) throws Exception { + public ResponseEntity delete(HttpServletRequest request, HttpServletResponse response, String groupId) throws Exception { service.deleteGroup(groupId); // Agent Command 전송 CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.RemoveInflowGroupControlCommand", groupId); agentUtilService.broadcast(command); - return null; + return ResponseEntity.ok().build(); } /** From 69c189cb53eee9bc391a3f0e1f8b83284e8a0216 Mon Sep 17 00:00:00 2001 From: daekuk Date: Wed, 24 Dec 2025 15:52:00 +0900 Subject: [PATCH 03/32] =?UTF-8?q?INSERT=EC=9D=BC=20=EB=95=8C=20scopeId=20?= =?UTF-8?q?=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=ED=95=B4=EC=84=9C=20API=20?= =?UTF-8?q?=EB=A7=A4=ED=95=91=EC=A0=95=EB=B3=B4=EB=8F=84=20=EB=93=A4?= =?UTF-8?q?=EC=96=B4=EA=B0=88=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp b/WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp index 8a78458..2e5f6be 100644 --- a/WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp +++ b/WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp @@ -187,7 +187,11 @@ $(document).ready(function() { success:function(args){ alert("SCOPE 정보가 저장 되었습니다. 이어서 API 리스트를 저장합니다."); + if(!isDetail) { // INSERT 일 경우 ScopeId를 업데이트 + key = $('input[name=scopeId]').val(); + } saveApiGridData(key, returnUrl); // API LIST 저장. + }, error:function(e){ From 65279fe7d413caed671fbd352874e77770d38205 Mon Sep 17 00:00:00 2001 From: daekuk Date: Fri, 26 Dec 2025 13:22:03 +0900 Subject: [PATCH 04/32] =?UTF-8?q?=EC=84=B8=EC=85=98=20=ED=83=80=EC=9E=84?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=8B=9C=20=EC=84=B8=EC=85=98=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A0=9C=EA=B1=B0=ED=95=98=EB=8A=94=20=ED=81=B4?= =?UTF-8?q?=EB=9E=98=EC=8A=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../login/SessionDestructionListener.java | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 src/main/java/com/eactive/eai/rms/common/login/SessionDestructionListener.java diff --git a/src/main/java/com/eactive/eai/rms/common/login/SessionDestructionListener.java b/src/main/java/com/eactive/eai/rms/common/login/SessionDestructionListener.java new file mode 100644 index 0000000..1fb4d46 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/common/login/SessionDestructionListener.java @@ -0,0 +1,46 @@ +package com.eactive.eai.rms.common.login; + +import javax.servlet.annotation.WebListener; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; + +import org.apache.log4j.Logger; + +@WebListener +public class SessionDestructionListener implements HttpSessionListener { + + private static final Logger logger = Logger.getLogger(SessionDestructionListener.class); + + @Override + public void sessionCreated(HttpSessionEvent se) { + + } + + /** + * 세션 타임아웃 등으로 소멸 시 세션정보 삭제 + */ + @Override + public void sessionDestroyed(HttpSessionEvent se) { + + try { + HttpSession session = se.getSession(); + + String userId = (String) session.getAttribute("userId"); + + // 로그인 한 사용자의 세션정보 정리 + if (userId != null) { + if (logger.isDebugEnabled()) { + logger.debug("[SessionListener] 세션만료 감지. 사용자 제거: " + userId); + } + + SessionManager.removeUserSession(userId); + } + + } catch (Exception e) { + + + logger.error("[SessionListener] 세션 정리 중 오류 발생", e); + } + } +} From b0b9553e66c4a29ec92363c9d9206c47a584f8c7 Mon Sep 17 00:00:00 2001 From: daekuk Date: Fri, 26 Dec 2025 16:23:30 +0900 Subject: [PATCH 05/32] =?UTF-8?q?-=20API=20=EC=B6=94=EA=B0=80=20=ED=8C=9D?= =?UTF-8?q?=EC=97=85=EC=97=90=EC=84=9C=20path=20=EB=A1=9C=20=EA=B2=80?= =?UTF-8?q?=EC=83=89=20=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebContent/jsp/onl/apim/apigroup/apiGroupManPopup.jsp | 6 ++++++ .../eai/rms/onl/apim/apigroup/ui/ApiGroupUISearch.java | 1 + 2 files changed, 7 insertions(+) diff --git a/WebContent/jsp/onl/apim/apigroup/apiGroupManPopup.jsp b/WebContent/jsp/onl/apim/apigroup/apiGroupManPopup.jsp index 0654ec0..f5f6d14 100644 --- a/WebContent/jsp/onl/apim/apigroup/apiGroupManPopup.jsp +++ b/WebContent/jsp/onl/apim/apigroup/apiGroupManPopup.jsp @@ -236,10 +236,16 @@ + + API 명 + API FULL PATH + + + diff --git a/src/main/java/com/eactive/eai/rms/onl/apim/apigroup/ui/ApiGroupUISearch.java b/src/main/java/com/eactive/eai/rms/onl/apim/apigroup/ui/ApiGroupUISearch.java index c2c4716..47bf7e5 100644 --- a/src/main/java/com/eactive/eai/rms/onl/apim/apigroup/ui/ApiGroupUISearch.java +++ b/src/main/java/com/eactive/eai/rms/onl/apim/apigroup/ui/ApiGroupUISearch.java @@ -7,4 +7,5 @@ public class ApiGroupUISearch { private String searchGroupName; private String searchGroupDesc; private String searchDisplayYn; + private String searchApiFullPath; } From b08e722e6825dad0ca933d56dba1df789958b120 Mon Sep 17 00:00:00 2001 From: daekuk Date: Fri, 26 Dec 2025 16:25:23 +0900 Subject: [PATCH 06/32] =?UTF-8?q?-=20=EB=82=B4=EB=B6=80=ED=91=9C=EC=A4=80?= =?UTF-8?q?=20=EB=A9=94=EC=8B=9C=EC=A7=80=20N=EA=B1=B4=EB=A7=8C=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EB=90=98=EB=8A=94=20=ED=98=84=EC=83=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95,=20page=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../stdmessage/StdMessageManController.java | 3 ++- .../serviceinfo/stdmessage/StdMessageManService.java | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/serviceinfo/stdmessage/StdMessageManController.java b/src/main/java/com/eactive/eai/rms/onl/manage/serviceinfo/stdmessage/StdMessageManController.java index ec5f5ce..6482828 100644 --- a/src/main/java/com/eactive/eai/rms/onl/manage/serviceinfo/stdmessage/StdMessageManController.java +++ b/src/main/java/com/eactive/eai/rms/onl/manage/serviceinfo/stdmessage/StdMessageManController.java @@ -9,6 +9,7 @@ import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; @@ -52,7 +53,7 @@ public class StdMessageManController extends BaseController { @PostMapping(value = "/onl/admin/service/stdMessageMan.json", params = "cmd=LIST") public ResponseEntity> selectList(Pageable pageable, String searchBzwkSvcKeyName, String searchEaiSvcCode, String searchEaiSendRecv, String searchEaiDirection) { - List map = service + Page map = service .selectList(pageable, searchBzwkSvcKeyName, searchEaiSvcCode, searchEaiSendRecv, searchEaiDirection); return ResponseEntity.ok(new GridResponse<>(map)); diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/serviceinfo/stdmessage/StdMessageManService.java b/src/main/java/com/eactive/eai/rms/onl/manage/serviceinfo/stdmessage/StdMessageManService.java index 15d84a6..6ecbf58 100644 --- a/src/main/java/com/eactive/eai/rms/onl/manage/serviceinfo/stdmessage/StdMessageManService.java +++ b/src/main/java/com/eactive/eai/rms/onl/manage/serviceinfo/stdmessage/StdMessageManService.java @@ -16,6 +16,7 @@ import org.apache.commons.lang3.StringUtils; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -59,14 +60,13 @@ public class StdMessageManService { @Autowired private ExtendedColumnDefinitionUIMapper extendedColumnDefinitionUIMapper; - public List selectList(Pageable pageable, String searchBzwkSvcKeyName, String searchEaiSvcCode, + public Page selectList(Pageable pageable, String searchBzwkSvcKeyName, String searchEaiSvcCode, String searchEaiSendRecv, String searchEaiDirection) { - return standardMessageInfoService - .findAll(pageable, searchBzwkSvcKeyName, searchEaiSvcCode, searchEaiSendRecv, searchEaiDirection) - .stream() - .map(stdMessageUIMapper::toVo) - .collect(Collectors.toList()); + Page pageResult = standardMessageInfoService + .findAll(pageable, searchBzwkSvcKeyName, searchEaiSvcCode, searchEaiSendRecv, searchEaiDirection); + + return pageResult.map(stdMessageUIMapper::toVo); } From 08f1f1bb92e27e8ae867074803a4f1757ab75034 Mon Sep 17 00:00:00 2001 From: daekuk Date: Fri, 26 Dec 2025 16:26:16 +0900 Subject: [PATCH 07/32] =?UTF-8?q?-=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83?= =?UTF-8?q?=20=EB=B3=80=ED=99=98=EB=A7=A4=ED=95=91=EC=9D=98=20=EB=B3=80?= =?UTF-8?q?=ED=99=98=ED=95=A8=EC=88=98=20=ED=95=AD=EB=AA=A9=20setSearchabl?= =?UTF-8?q?e=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jsp/onl/admin/rule/transform2/transform2ManDetail.jsp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/WebContent/jsp/onl/admin/rule/transform2/transform2ManDetail.jsp b/WebContent/jsp/onl/admin/rule/transform2/transform2ManDetail.jsp index aa0d607..8ee79f9 100644 --- a/WebContent/jsp/onl/admin/rule/transform2/transform2ManDetail.jsp +++ b/WebContent/jsp/onl/admin/rule/transform2/transform2ManDetail.jsp @@ -717,6 +717,8 @@ reloadSourceTargetGrid('${param.cnvsnName}'); reloadCnvsnDesc(); + + setSearchable("functionCombo"); }, error:function(e){ alert(e.responseText); From de67e321abd4a03f1c1b66c9e40814dc9f5e983b Mon Sep 17 00:00:00 2001 From: daekuk Date: Mon, 29 Dec 2025 17:18:27 +0900 Subject: [PATCH 08/32] =?UTF-8?q?=ED=95=84=EC=9A=94=EC=97=86=EB=8A=94=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebContent/jsp/onl/transaction/apim/apiInterfaceManDetail.jsp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/WebContent/jsp/onl/transaction/apim/apiInterfaceManDetail.jsp b/WebContent/jsp/onl/transaction/apim/apiInterfaceManDetail.jsp index df04283..6b53621 100644 --- a/WebContent/jsp/onl/transaction/apim/apiInterfaceManDetail.jsp +++ b/WebContent/jsp/onl/transaction/apim/apiInterfaceManDetail.jsp @@ -2084,7 +2084,7 @@ -loneInterfaceButton">복제 + From f06adb5ff1fc659448cf9f6a1ce06c066a51b1f2 Mon Sep 17 00:00:00 2001 From: daekuk Date: Mon, 29 Dec 2025 17:20:31 +0900 Subject: [PATCH 09/32] =?UTF-8?q?=EB=B3=80=ED=99=98=EB=A7=A4=ED=95=91=20?= =?UTF-8?q?=ED=95=9C=EA=B8=80=EB=8C=80=EC=9D=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rms/onl/manage/rule/transform2/Transform2Service.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/rule/transform2/Transform2Service.java b/src/main/java/com/eactive/eai/rms/onl/manage/rule/transform2/Transform2Service.java index a667814..badc081 100644 --- a/src/main/java/com/eactive/eai/rms/onl/manage/rule/transform2/Transform2Service.java +++ b/src/main/java/com/eactive/eai/rms/onl/manage/rule/transform2/Transform2Service.java @@ -171,7 +171,13 @@ public class Transform2Service extends BaseService { private String genConversionSourceItems(String srcLayoutName, String cnvsncmdname) { - Pattern pattern = Pattern.compile(srcLayoutName + "(\\w|\\[|\\]|\\*|\\.|-|:)*"); + // \w : 영문, 숫자, _ + // \. \- : 점, 하이픈 + // \[ \] \* : 대괄호, 별표 + // : : 콜론 + // \uAC00-\uD7A3 : 한글 전체 ('가' ~ '힣') + + Pattern pattern = Pattern.compile(srcLayoutName + "[\\w\\.\\[\\]\\*\\-:\\uAC00-\\uD7A3]*"); Matcher matcher = pattern.matcher(cnvsncmdname); StringBuilder result = new StringBuilder(); From 08c6bb44d56bf94f3c1a65197f037c226c883b42 Mon Sep 17 00:00:00 2001 From: daekuk Date: Tue, 30 Dec 2025 10:31:39 +0900 Subject: [PATCH 10/32] =?UTF-8?q?=EC=A3=BC=EC=84=9D=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rms/onl/manage/rule/transform2/Transform2Service.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/rule/transform2/Transform2Service.java b/src/main/java/com/eactive/eai/rms/onl/manage/rule/transform2/Transform2Service.java index badc081..cc2e444 100644 --- a/src/main/java/com/eactive/eai/rms/onl/manage/rule/transform2/Transform2Service.java +++ b/src/main/java/com/eactive/eai/rms/onl/manage/rule/transform2/Transform2Service.java @@ -171,12 +171,7 @@ public class Transform2Service extends BaseService { private String genConversionSourceItems(String srcLayoutName, String cnvsncmdname) { - // \w : 영문, 숫자, _ - // \. \- : 점, 하이픈 - // \[ \] \* : 대괄호, 별표 - // : : 콜론 // \uAC00-\uD7A3 : 한글 전체 ('가' ~ '힣') - Pattern pattern = Pattern.compile(srcLayoutName + "[\\w\\.\\[\\]\\*\\-:\\uAC00-\\uD7A3]*"); Matcher matcher = pattern.matcher(cnvsncmdname); From ba6dff6f9ebc4ff45e07cd9db1a7541426457ca1 Mon Sep 17 00:00:00 2001 From: daekuk Date: Tue, 30 Dec 2025 10:36:27 +0900 Subject: [PATCH 11/32] =?UTF-8?q?-=20=EA=B0=99=EC=9D=80=20ID=20=EB=A1=9C?= =?UTF-8?q?=20DEL=20->=20INSERT=20=EC=8B=9C=20=EC=B6=A9=EB=8F=8C=EB=8C=80?= =?UTF-8?q?=EC=9D=91=20-=20API=2020=EA=B1=B4=20=EC=A1=B0=ED=9A=8C=20->=20?= =?UTF-8?q?=EC=A0=84=EC=B2=B4=EC=A1=B0=ED=9A=8C=20-=20API=20LIST=20?= =?UTF-8?q?=EC=A0=80=EC=9E=A5=EC=8B=9C=20=EC=9A=94=EC=B2=AD/=EC=99=84?= =?UTF-8?q?=EB=A3=8C=20=EC=95=8C=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D?= =?UTF-8?q?=20=EB=B2=84=ED=8A=BC=20=EC=A0=9C=EC=96=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jsp/onl/admin/authserver/scopeManDetail.jsp | 10 +++++++++- .../onl/authserver/ScopeEntityService.java | 16 +++++++++++++--- .../entity/onl/eaimsg/EAIMessageService.java | 2 -- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp b/WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp index 2e5f6be..505483e 100644 --- a/WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp +++ b/WebContent/jsp/onl/admin/authserver/scopeManDetail.jsp @@ -151,6 +151,10 @@ function saveApiGridData(scopeId, returnUrl) { type : "POST", url:mapping_url, data: postData, + beforeSend: function() { + $("[id^='btn_']").prop("disabled", true); + $("#btn_modify").text("처리중 . . . . ."); + }, success:function(args){ alert("저장 되었습니다."); @@ -158,7 +162,11 @@ function saveApiGridData(scopeId, returnUrl) { }, error:function(e){ alert(e.responseText); - } + }, + complete: function() { + $("[id^='btn_']").prop("disabled", false); + $("#btn_modify").text("수정"); + } }); } diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/authserver/ScopeEntityService.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/authserver/ScopeEntityService.java index 2f42d64..89b2a1e 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/authserver/ScopeEntityService.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/authserver/ScopeEntityService.java @@ -1,21 +1,31 @@ package com.eactive.eai.rms.data.entity.onl.authserver; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; import com.eactive.eai.data.entity.onl.authserver.QScopeEntity; import com.eactive.eai.data.entity.onl.authserver.ScopeEntity; import com.eactive.eai.data.entity.onl.authserver.ScopeEntityId; import com.eactive.eai.data.jpa.AbstractDataService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + @Service @Transactional public class ScopeEntityService extends AbstractDataService { - + + @PersistenceContext + private EntityManager entityManager; // AbstractDataService 의 entityManager가 private이라 접근 불가하여 별도 주입 + public void deleteByIdScopeId(String scopeId) { getJPAQueryFactory().delete(QScopeEntity.scopeEntity) .where(QScopeEntity.scopeEntity.id.scopeid.eq(scopeId)) .execute(); + + // 동일 트랜잭션 내에서 같은 ID로 재저장 시 충돌(EntityExistsException)을 방지 + entityManager.flush(); + entityManager.clear(); } } diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/eaimsg/EAIMessageService.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/eaimsg/EAIMessageService.java index 0cdc9c3..2aeb0e3 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/eaimsg/EAIMessageService.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/eaimsg/EAIMessageService.java @@ -310,8 +310,6 @@ public class EAIMessageService extends AbstractDataService(result, pageable, result.size()); From a7e68bcb27faa9733ff935a789cb6c0bab898bac Mon Sep 17 00:00:00 2001 From: daekuk Date: Tue, 30 Dec 2025 13:58:34 +0900 Subject: [PATCH 12/32] =?UTF-8?q?api=20transaction=20log=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=84=9C=EB=B9=84=EC=8A=A4=20=EA=B0=9C=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebContent/WEB-INF/springapp-servlet.xml | 1 + kjb-docs/apilog/log.md | 64 ++++++++ .../rms/data/entity/onl/logger/ApiLogDTO.java | 17 +++ .../entity/onl/logger/ApiMessageLogDTO.java | 36 +++++ .../entity/onl/logger/EAILogRepository.java | 3 + .../onl/logger/EAILogRepositoryImpl.java | 36 +++-- .../data/entity/onl/logger/EAILogService.java | 2 + .../entity/onl/logger/EAILogServiceImpl.java | 143 +++++++++++++----- .../logger/HttpAdapterExtraLogService.java | 12 ++ .../com/eactive/ext/kjb/web/ApiLogUI.java | 17 +++ .../eactive/ext/kjb/web/ApiMessageLogUI.java | 35 +++++ .../kjb/web/ApiTransactionLogController.java | 142 +++++++++++++++++ .../com/eactive/ext/kjb/web/package-info.java | 1 + 13 files changed, 463 insertions(+), 46 deletions(-) create mode 100644 kjb-docs/apilog/log.md create mode 100644 src/main/java/com/eactive/eai/rms/data/entity/onl/logger/ApiLogDTO.java create mode 100644 src/main/java/com/eactive/eai/rms/data/entity/onl/logger/ApiMessageLogDTO.java create mode 100644 src/main/java/com/eactive/ext/kjb/web/ApiLogUI.java create mode 100644 src/main/java/com/eactive/ext/kjb/web/ApiMessageLogUI.java create mode 100644 src/main/java/com/eactive/ext/kjb/web/ApiTransactionLogController.java create mode 100644 src/main/java/com/eactive/ext/kjb/web/package-info.java diff --git a/WebContent/WEB-INF/springapp-servlet.xml b/WebContent/WEB-INF/springapp-servlet.xml index bdcc5db..f3a55c6 100644 --- a/WebContent/WEB-INF/springapp-servlet.xml +++ b/WebContent/WEB-INF/springapp-servlet.xml @@ -140,4 +140,5 @@ + diff --git a/kjb-docs/apilog/log.md b/kjb-docs/apilog/log.md new file mode 100644 index 0000000..ad82c85 --- /dev/null +++ b/kjb-docs/apilog/log.md @@ -0,0 +1,64 @@ +- url +- 요청 clientId +- 거래정보 + +- 기존 샘플 +``` +{ + "clientId": "8cd49ec6bdf82502e053030011ac7064", + "header": { + "x-request-id": "22617829,22617831,22617833,22617835", + "traceId": "8d41a04141794275abc3691b525cf2a9", + "content-length": "75194", + "x-forwarded-for": "117.52.3.143", + "x-user-no": "29024601", + "accept": "application/json, application/cbor, application/*+json", + "x-partner-id": "KWANGJU_BANK", + "via": "1.1 localhost:20443", + "authorization": "Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJkODBiMDJmZDVmYmM0MjNhOWYyZTk5YzY1MzgwODY5YyIsInNpbXBsZXEiOiJkYjJmODVmNTQ4ZmY3Njk3MmMwZTA2YjBiMWUwNDBmYWIyNjczNTI2ODI0ZjE1M2RiODAzNDQ4MzRhMDIzNzk3IiwidHJhY2VfaWQiOiJiMGU3MjNkOTY2NTM0N2QxYmFiZmYzZTIwYzZiMjIxYSIsImdyYW50X3R5cGUiOiJjbGllbnRfY3JlZGVudGlhbHMiLCJyZXNvdXJjZSI6IjhjZDViYTczMzgzOTJkNTdlMDUzMDMwMDExYWM4YmUxIiwic2NvcGUiOiJvb2IiLCJzaW1wbGUiOiIxZjNmODYwY2U4ODkxNTVkNDAxYWZjNmE5YTIxZjQ3OTYwNTczNzVhZjI3NzdkY2Y2YTMyZjQ3ZTAxOTc0ZGFiYWY5MTM0ODEzOGFkMTBjMDg3N2FkYTRmZDhhZmVhMmZkMDIzMjVkYTIzYTBkZThlNjMyODRjYzBhMjNjY2VlZjU0NDAyZjdhYzU2NmE5NmM0MmFjZDg4YjI0ZmE2NWQ2NWRiMzcwZDEyMTg2ZjY5ZDkzNmNhYjM0MTcyZDk1NzdkMzNlNDk2MTYxMzczMTY0YjJmMTdjMTk0YWRkZjYyMWIwZmJjNDViNWMzNjUyNzU5MTY2NWQ2NDg1NGE0OWUyYWNmNzM4NDdmZDVkYWZkNDY1Zjg3ZDU5ZTU1N2ZiNWNlN2Y3Njk1NGU2YTg4YjE1ZWFhN2JlNDhmODk5NmVmN2QxYmRjMDg1MjMwOGM5NDc1MzdmMDc1Y2JhZTBmYTM5OTBhZmYzMTY0ZGZlOGVmYTg3YmFlZDgyYjQyYjcyMDA3ZTg4YTM3NmU5MjUyMzZiMGIwZjE5MzM2MDNlN2ExMzNkMzI4YzBkM2JhNWY0OTExNjMyYWFlZmRkZjI5OTk4N2FmMjY3MjIyZTM2ZWI5ZmNlMzg0OWIyODNmN2Q3Yzc4NTQ0MjRlZWE2YTBmYzQ0ZWFmOTNiNzY1ZGQ2YWE5ZWQzNGFlOWEyNTU5OWFmZDM1NTkwOWQ3YjViNDUxYjM4NTc4OTdiMTM2ZjQyNmQ4ODkwZTljZWFiZTQ3NWRjYTEiLCJleHAiOjE3NjU5NjEwMDksInRva2VuX3R5cGUiOiJCZWFyZXIiLCJleHBpcmVzX2luIjozNjAwfQ.G-KC8DPeBBM40NoD7yQs6Y552PAExlz-V_DhehmqMuc", + "x-loan-token": "HOkND9Wb2PGjcV/h1pdpeMyVia8", + "x-forwarded-server": "localhost", + "x-forwarded-host": "apit.kjbank.com:20443", + "key-event-id": "BSST5OEP7G", + "host": "192.168.246.16:28184", + "content-type": "application/json;charset=UTF-8", + "connection": "Keep-Alive", + "accept-encoding": "gzip,deflate", + "user-agent": "Apache-HttpClient/4.5.13 (Java/17.0.12)" + }, + "queryString": "", + "body": { + "data": { + "agreeIdentifyInfo": true, + "joinDate": "20191217", + "corporateNumber": "1248100998", + "agreePersonalCreditInfo": true, + "ci": "CI85100722580288510072258028851007225802885100722580288510072258028851007225802885100722", + "name": "박주희", + "salary": 33000000, + "jobType": "01", + "rrn": "8510072037827" + }, + "requestProducts": [ + { + "loanReqNo": "T000022617829", + "loanProductId": "01535" + }, + { + "loanReqNo": "T000022617831", + "loanProductId": "0531" + }, + { + "loanReqNo": "T000022617833", + "loanProductId": "0607" + }, + { + "loanReqNo": "T000022617835", + "loanProductId": "0608" + } + ] + }, + "exdata": "", + "txDate": "20251217" +} +``` \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/ApiLogDTO.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/ApiLogDTO.java new file mode 100644 index 0000000..618a124 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/ApiLogDTO.java @@ -0,0 +1,17 @@ +package com.eactive.eai.rms.data.entity.onl.logger; + +import java.util.List; + +import lombok.Data; + +@Data +public class ApiLogDTO { + + private String apiServiceNumber; + + private String txDate; + + private List logs; + + private Long totalProcessingTime; +} diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/ApiMessageLogDTO.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/ApiMessageLogDTO.java new file mode 100644 index 0000000..793da46 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/ApiMessageLogDTO.java @@ -0,0 +1,36 @@ +package com.eactive.eai.rms.data.entity.onl.logger; + +import java.util.List; +import java.util.Map; + +import lombok.Data; + +@Data +public class ApiMessageLogDTO { + + private String apiServiceNumber; + + private int processNumber; + + private String txDate; + + private String url; + + private String queryString; + + private String clientId; + + private String method; + + private Integer HttpStatus; + + private String header; + + private String body; + + private String exdata; + + private Long processingTime; + + private String keymgtmsgctnt; +} diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogRepository.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogRepository.java index 2b10fb0..b89448c 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogRepository.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogRepository.java @@ -6,6 +6,7 @@ import org.springframework.data.domain.Pageable; import com.eactive.eai.data.entity.onl.logger.EAILog; import com.eactive.eai.data.entity.onl.logger.EAILogId; +import java.util.List; import java.util.Map; public interface EAILogRepository { @@ -16,4 +17,6 @@ public interface EAILogRepository { Map countDetailedTransactions(Class clazz, EAILogSearch eaiLogSearch); + List getApiLog(Class class1, String apiServiceNumber); + } 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 fc78b9c..aad5b34 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 @@ -1,5 +1,19 @@ package com.eactive.eai.rms.data.entity.onl.logger; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Repository; + import com.eactive.eai.data.entity.onl.logger.EAILog; import com.eactive.eai.data.entity.onl.logger.EAILogId; import com.eactive.eai.data.entity.onl.logger.QEAILog; @@ -11,18 +25,6 @@ import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.core.types.dsl.EntityPathBase; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; -import org.apache.commons.lang3.StringUtils; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageImpl; -import org.springframework.data.domain.Pageable; -import org.springframework.stereotype.Repository; - -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; @Repository public class EAILogRepositoryImpl implements EAILogRepository { @@ -217,4 +219,14 @@ public class EAILogRepositoryImpl implements EAILogRepository { .fetchOne(); } + @Override + public List getApiLog(Class clazz, String apiServiceNumber) { + QEAILog qeaiLog = QEAILog.eAILog; + EntityPathBase entityPathBase = new EntityPathBase<>(clazz, qeaiLog.getMetadata().getName()); + + return new JPAQueryFactory(em).select(qeaiLog).from(entityPathBase) + .where(qeaiLog.id.eaisvcserno.trim().eq(apiServiceNumber)).orderBy(qeaiLog.id.logprcssserno.asc()) + .fetch(); + } + } diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogService.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogService.java index 5742260..215687b 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogService.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogService.java @@ -19,4 +19,6 @@ public interface EAILogService { List selectLogList(HashMap paramMap); Map getTransactionCounts(EAILogSearch eaiLogSearch); + + ApiLogDTO getApiLog(String txDate, String apiServiceNumber); } diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogServiceImpl.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogServiceImpl.java index 30a8d95..2782e65 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogServiceImpl.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogServiceImpl.java @@ -1,55 +1,130 @@ package com.eactive.eai.rms.data.entity.onl.logger; -import com.eactive.eai.data.RollingTable; -import com.eactive.eai.data.entity.onl.logger.EAILog; -import com.eactive.eai.data.entity.onl.logger.EAILogId; -import com.eactive.eai.rms.common.util.CommonUtil; -import com.eactive.eai.rms.data.entity.onl.apim.portalstatistics.PortalStatisticsVO; -import lombok.RequiredArgsConstructor; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationContext; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import com.eactive.eai.data.RollingTable; +import com.eactive.eai.data.entity.onl.logger.EAILog; +import com.eactive.eai.data.entity.onl.logger.EAILogId; +import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraLog; +import com.eactive.eai.rms.common.util.CommonUtil; +import com.eactive.eai.rms.data.entity.onl.apim.portalstatistics.PortalStatisticsVO; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j @Service @Transactional @RequiredArgsConstructor public class EAILogServiceImpl implements EAILogService { - private final EAILogRepository eaiLogRepository; - private final ApplicationContext applicationContext; - private final EAILogDAOForEMS eaiLogDAOForEMS; + private final EAILogRepository eaiLogRepository; + private final ApplicationContext applicationContext; + private final EAILogDAOForEMS eaiLogDAOForEMS; + private final HttpAdapterExtraLogService httpAdapterExtraLogService; - @Override - public Page findAll(Pageable pageable, EAILogSearch eaiLogSearch) { - long time = CommonUtil.getCalendar(eaiLogSearch.getSearchStartTime()).getTimeInMillis(); - EAILog eaiLog = (EAILog) applicationContext.getBean(RollingTable.class, EAILog.class, time); - Page eaiLogDtos = eaiLogRepository.findAll(eaiLog.getClass(), pageable, eaiLogSearch); - return eaiLogDtos; - } + @Override + public Page findAll(Pageable pageable, EAILogSearch eaiLogSearch) { + long time = CommonUtil.getCalendar(eaiLogSearch.getSearchStartTime()).getTimeInMillis(); + EAILog eaiLog = (EAILog) applicationContext.getBean(RollingTable.class, EAILog.class, time); + Page eaiLogDtos = eaiLogRepository.findAll(eaiLog.getClass(), pageable, eaiLogSearch); + return eaiLogDtos; + } - public Map getTransactionCounts(EAILogSearch eaiLogSearch){ - long time = CommonUtil.getCalendar(eaiLogSearch.getSearchStartTime()).getTimeInMillis(); - EAILog eaiLog = (EAILog) applicationContext.getBean(RollingTable.class, EAILog.class, time); - Map detailedCounts = eaiLogRepository.countDetailedTransactions(eaiLog.getClass(), eaiLogSearch); - return detailedCounts; - } + public Map getTransactionCounts(EAILogSearch eaiLogSearch) { + long time = CommonUtil.getCalendar(eaiLogSearch.getSearchStartTime()).getTimeInMillis(); + EAILog eaiLog = (EAILog) applicationContext.getBean(RollingTable.class, EAILog.class, time); + Map detailedCounts = eaiLogRepository.countDetailedTransactions(eaiLog.getClass(), eaiLogSearch); + return detailedCounts; + } - @Override - public EAILogDto getById(EAILogId eaiLogId) { - long time = CommonUtil.getCalendar(eaiLogId.getMsgdpstyms()).getTimeInMillis(); - EAILog eaiLog = (EAILog) applicationContext.getBean(RollingTable.class, EAILog.class, time); - return eaiLogRepository.getById(eaiLog.getClass(), eaiLogId); - } + @Override + public EAILogDto getById(EAILogId eaiLogId) { + long time = CommonUtil.getCalendar(eaiLogId.getMsgdpstyms()).getTimeInMillis(); + EAILog eaiLog = (EAILog) applicationContext.getBean(RollingTable.class, EAILog.class, time); + return eaiLogRepository.getById(eaiLog.getClass(), eaiLogId); + } + public List selectLogList(HashMap paramMap) { + return eaiLogDAOForEMS.selectLogList(paramMap); + } - public List selectLogList(HashMap paramMap) { - return eaiLogDAOForEMS.selectLogList(paramMap); - } + @Override + public ApiLogDTO getApiLog(String txDate, String apiServiceNumber) { + + long time = CommonUtil.getCalendar(txDate).getTimeInMillis(); + EAILog eaiLogTargetObject = (EAILog) applicationContext.getBean(RollingTable.class, EAILog.class, time); + List eaiLogs = eaiLogRepository.getApiLog(eaiLogTargetObject.getClass(), apiServiceNumber); + eaiLogs.sort((l1, l2) -> l1.getId().getEaisvcserno().compareTo(l2.getId().getEaisvcserno())); + + ApiLogDTO apiLogDTO = new ApiLogDTO(); + apiLogDTO.setApiServiceNumber(apiServiceNumber); + eaiLogs.stream().findFirst().ifPresent(log -> apiLogDTO.setTxDate(log.getId().getMsgdpstyms())); + + List apiMessageLogDTOs = new LinkedList<>(); + + for (EAILog eaiLog : eaiLogs) { + ApiMessageLogDTO apiMessageLogDTO = new ApiMessageLogDTO(); + + apiMessageLogDTO.setApiServiceNumber(apiServiceNumber); + apiMessageLogDTO.setTxDate(eaiLog.getMsgprcssyms()); + apiMessageLogDTO.setProcessNumber(Integer.parseInt(eaiLog.getId().getLogprcssserno())); + apiMessageLogDTO.setQueryString(""); + apiMessageLogDTO.setClientId(eaiLog.getClientid()); + apiMessageLogDTO.setKeymgtmsgctnt(eaiLog.getKeymgtmsgctnt()); + + String body = StringUtils.substringAfter(eaiLog.getBzwkdatactnt(), '|'); + body = StringUtils.substringBeforeLast(body, "|"); + + apiMessageLogDTO.setBody(body); + apiMessageLogDTOs.add(apiMessageLogDTO); + } + + Map extraLogs = httpAdapterExtraLogService.findByGuid(apiServiceNumber); + for (ApiMessageLogDTO apiMessageLogDTO : apiMessageLogDTOs) { + HttpAdapterExtraLog httpAdapterExtraLog = extraLogs.get(apiMessageLogDTO.getProcessNumber()); + + apiMessageLogDTO.setHeader(httpAdapterExtraLog.getHeaderContent()); + apiMessageLogDTO.setMethod(httpAdapterExtraLog.getHttpMethod()); + apiMessageLogDTO.setHttpStatus(httpAdapterExtraLog.getHttpStatus()); + apiMessageLogDTO.setUrl(httpAdapterExtraLog.getUrl()); + } + + // 처리 시간 계산 + for (int i = 0; i < apiMessageLogDTOs.size(); i++) { + ApiMessageLogDTO dto = apiMessageLogDTOs.get(i); + EAILog eaiLog = eaiLogs.get(i); + + // msgprcssyms - msgdpstyms + long receivedTime = CommonUtil.getCalendar(eaiLog.getId().getMsgdpstyms()).getTimeInMillis(); + long processedTime = CommonUtil.getCalendar(eaiLog.getMsgprcssyms()).getTimeInMillis(); + long processingTime = processedTime - receivedTime; + dto.setProcessingTime(processingTime); + } + + // 전체 처리 시간 계산 (첫 수신 시각 ~ 마지막 처리 시각) + if (!eaiLogs.isEmpty()) { + long firstReceivedTime = CommonUtil.getCalendar(eaiLogs.get(0).getId().getMsgdpstyms()).getTimeInMillis(); + long lastProcessedTime = CommonUtil.getCalendar(eaiLogs.get(eaiLogs.size() - 1).getMsgprcssyms()).getTimeInMillis(); + long totalProcessingTime = lastProcessedTime - firstReceivedTime; + apiLogDTO.setTotalProcessingTime(totalProcessingTime); + } + + apiLogDTO.setLogs(apiMessageLogDTOs); + return apiLogDTO; + } } diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/HttpAdapterExtraLogService.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/HttpAdapterExtraLogService.java index 2fa2c86..6441b7c 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/HttpAdapterExtraLogService.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/HttpAdapterExtraLogService.java @@ -1,16 +1,28 @@ package com.eactive.eai.rms.data.entity.onl.logger; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; + import javax.transaction.Transactional; import org.springframework.stereotype.Service; import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraLog; import com.eactive.eai.data.entity.onl.logger.HttpAdapterExtraLogId; +import com.eactive.eai.data.entity.onl.logger.QHttpAdapterExtraLog; import com.eactive.eai.data.jpa.AbstractDataService; +import com.querydsl.core.types.dsl.BooleanExpression; @Service @Transactional public class HttpAdapterExtraLogService extends AbstractDataService { + public Map findByGuid(String guid) { + BooleanExpression predicate = QHttpAdapterExtraLog.httpAdapterExtraLog.id.guid.eq(guid); + return StreamSupport.stream(repository.findAll(predicate).spliterator(), false) + .collect(Collectors.toMap(log -> log.getId().getServiceProcessNumber(), log -> log)); + } + } diff --git a/src/main/java/com/eactive/ext/kjb/web/ApiLogUI.java b/src/main/java/com/eactive/ext/kjb/web/ApiLogUI.java new file mode 100644 index 0000000..7572680 --- /dev/null +++ b/src/main/java/com/eactive/ext/kjb/web/ApiLogUI.java @@ -0,0 +1,17 @@ +package com.eactive.ext.kjb.web; + +import java.util.List; + +import lombok.Data; + +@Data +public class ApiLogUI { + + private String apiServiceNumber; + + private String txDate; + + private List logs; + + private Long totalProcessingTime; +} diff --git a/src/main/java/com/eactive/ext/kjb/web/ApiMessageLogUI.java b/src/main/java/com/eactive/ext/kjb/web/ApiMessageLogUI.java new file mode 100644 index 0000000..7e2989a --- /dev/null +++ b/src/main/java/com/eactive/ext/kjb/web/ApiMessageLogUI.java @@ -0,0 +1,35 @@ +package com.eactive.ext.kjb.web; + +import java.util.Map; + +import lombok.Data; + +@Data +public class ApiMessageLogUI { + + private String apiServiceNumber; + + private int processNumber; + + private String txDate; + + private String url; + + private String queryString; + + private String clientId; + + private String method; + + private Integer HttpStatus; + + private Map header; + + private Object body; + + private String exdata; + + private Long processingTime; + + private String guid; +} diff --git a/src/main/java/com/eactive/ext/kjb/web/ApiTransactionLogController.java b/src/main/java/com/eactive/ext/kjb/web/ApiTransactionLogController.java new file mode 100644 index 0000000..c18c317 --- /dev/null +++ b/src/main/java/com/eactive/ext/kjb/web/ApiTransactionLogController.java @@ -0,0 +1,142 @@ +package com.eactive.ext.kjb.web; + +import java.time.LocalDate; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; + +import com.eactive.eai.rms.common.datasource.DataSourceContextHolder; +import com.eactive.eai.rms.common.datasource.DataSourceTypeManager; +import com.eactive.eai.rms.common.interceptor.InterceptorSkipController; +import com.eactive.eai.rms.data.entity.onl.logger.ApiLogDTO; +import com.eactive.eai.rms.data.entity.onl.logger.ApiMessageLogDTO; +import com.eactive.eai.rms.data.entity.onl.logger.EAILogService; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Controller +@RequiredArgsConstructor +public class ApiTransactionLogController implements InterceptorSkipController { + + private final EAILogService eaiLogService; + private final ObjectMapper objectMapper = new ObjectMapper(); + + @GetMapping("/api/transaction/log.do") + @PostMapping("/api/transaction/log.do") + public ResponseEntity getApiLog(String txDate, String apiServiceNumber) { + DataSourceContextHolder.setDataSourceType(DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW)); + + // txDate가 없으면 오늘 날짜 설정 + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd"); + LocalDate searchDate; + if (StringUtils.hasText(txDate)) { + searchDate = LocalDate.parse(txDate, formatter); + } else { + searchDate = LocalDate.now(); + } + + // 최대 10일 전까지 조회 시도 + ApiLogDTO dto = null; + for (int i = 0; i < 10; i++) { + String searchDateStr = searchDate.format(formatter); + dto = eaiLogService.getApiLog(searchDateStr, apiServiceNumber); + + // 결과가 있으면 종료 + if (dto != null && dto.getLogs() != null && !dto.getLogs().isEmpty()) { + break; + } + + // 하루 전으로 이동 + searchDate = searchDate.minusDays(1); + } + + return ResponseEntity.ok(convertToUI(dto)); + } + + private ApiLogUI convertToUI(ApiLogDTO dto) { + ApiLogUI ui = new ApiLogUI(); + ui.setApiServiceNumber(dto.getApiServiceNumber()); + ui.setTxDate(dto.getTxDate()); + ui.setTotalProcessingTime(dto.getTotalProcessingTime()); + + if (dto.getLogs() != null) { + List uiLogs = dto.getLogs().stream().map(this::convertMessageToUI) + .collect(Collectors.toList()); + ui.setLogs(uiLogs); + } + + return ui; + } + + private ApiMessageLogUI convertMessageToUI(ApiMessageLogDTO dto) { + ApiMessageLogUI ui = new ApiMessageLogUI(); + ui.setApiServiceNumber(dto.getApiServiceNumber()); + ui.setProcessNumber(dto.getProcessNumber()); + ui.setTxDate(dto.getTxDate()); + ui.setUrl(dto.getUrl()); + ui.setQueryString(dto.getQueryString()); + ui.setClientId(dto.getClientId()); + ui.setMethod(dto.getMethod()); + ui.setHttpStatus(dto.getHttpStatus()); + ui.setExdata(dto.getExdata()); + ui.setProcessingTime(dto.getProcessingTime()); + ui.setGuid(dto.getKeymgtmsgctnt()); + + // header: JSON 문자열 → Map + if (dto.getHeader() != null) { + try { + List> headerList = objectMapper.readValue(dto.getHeader(), + new TypeReference>>() { + }); + + Map headerMap = new HashMap<>(); + for (Map headerItem : headerList) { + String name = headerItem.get("name"); + String value = headerItem.get("value"); + if (name != null) { + headerMap.put(name, value); + } + } + + // header에서 client*id 패턴 추출 (정규식, ignoreCase) + for (Map.Entry entry : headerMap.entrySet()) { + if (entry.getKey() != null && entry.getKey().matches("(?i)client.*id")) { + ui.setClientId(entry.getValue()); + break; + } + } + + ui.setHeader(headerMap); + } catch (Exception e) { + log.error("Failed to parse header JSON: {}", dto.getHeader(), e); + } + } + + // body: JSON 문자열 → Object + if (dto.getBody() != null) { + try { + Object bodyObject = objectMapper.readValue(dto.getBody(), Object.class); + ui.setBody(bodyObject); + } catch (Exception e) { + // JSON 파싱 실패 시 원본 문자열 사용 + ui.setBody(dto.getBody()); + } + } + + return ui; + } + +} diff --git a/src/main/java/com/eactive/ext/kjb/web/package-info.java b/src/main/java/com/eactive/ext/kjb/web/package-info.java new file mode 100644 index 0000000..03ec7ba --- /dev/null +++ b/src/main/java/com/eactive/ext/kjb/web/package-info.java @@ -0,0 +1 @@ +package com.eactive.ext.kjb.web; \ No newline at end of file From 27dacfefb6974406b84a12af5f640ea4a34d689e Mon Sep 17 00:00:00 2001 From: daekuk Date: Tue, 30 Dec 2025 14:54:59 +0900 Subject: [PATCH 13/32] =?UTF-8?q?header=20=EC=97=86=EC=9D=84=20=EA=B2=BD?= =?UTF-8?q?=EC=9A=B0=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rms/data/entity/onl/logger/EAILogServiceImpl.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogServiceImpl.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogServiceImpl.java index 2782e65..1c86c8d 100644 --- a/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogServiceImpl.java +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/logger/EAILogServiceImpl.java @@ -97,10 +97,12 @@ public class EAILogServiceImpl implements EAILogService { for (ApiMessageLogDTO apiMessageLogDTO : apiMessageLogDTOs) { HttpAdapterExtraLog httpAdapterExtraLog = extraLogs.get(apiMessageLogDTO.getProcessNumber()); - apiMessageLogDTO.setHeader(httpAdapterExtraLog.getHeaderContent()); - apiMessageLogDTO.setMethod(httpAdapterExtraLog.getHttpMethod()); - apiMessageLogDTO.setHttpStatus(httpAdapterExtraLog.getHttpStatus()); - apiMessageLogDTO.setUrl(httpAdapterExtraLog.getUrl()); + if (httpAdapterExtraLog != null) { + apiMessageLogDTO.setHeader(httpAdapterExtraLog.getHeaderContent()); + apiMessageLogDTO.setMethod(httpAdapterExtraLog.getHttpMethod()); + apiMessageLogDTO.setHttpStatus(httpAdapterExtraLog.getHttpStatus()); + apiMessageLogDTO.setUrl(httpAdapterExtraLog.getUrl()); + } } // 처리 시간 계산 From fc94d01e75e55026d2f360bec820ba6e3431eacd Mon Sep 17 00:00:00 2001 From: daekuk Date: Tue, 30 Dec 2025 15:24:26 +0900 Subject: [PATCH 14/32] =?UTF-8?q?=EA=B0=80=EC=83=81=20=EC=9D=B8=EB=8D=B1?= =?UTF-8?q?=EC=8A=A4=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jsp/onl/admin/authserver/clientManDetail.jsp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/WebContent/jsp/onl/admin/authserver/clientManDetail.jsp b/WebContent/jsp/onl/admin/authserver/clientManDetail.jsp index 18e652f..33dd4d8 100644 --- a/WebContent/jsp/onl/admin/authserver/clientManDetail.jsp +++ b/WebContent/jsp/onl/admin/authserver/clientManDetail.jsp @@ -133,14 +133,17 @@ var selectedApiGrid = $("#selectedApiGrid"); selectedApiGrid.jqGrid({ datatype: "local", + gridview: true, // 성능 향상 + rownumbers: true, // 가상 인덱스 + rownumWidth: 40, colNames: ['API ID', 'API 이름'], colModel: [ {name: 'apiId', index: 'apiId', width: 100, align: 'center'}, {name: 'apiDesc', index: 'apiDesc', width: 100, align: 'center'} ], - rowNum: 10, - rowList: [10, 20, 30], - pager: '#selectedApiGridPager', + rowNum: -1, +// rowList: [10, 20, 30], +// pager: '#selectedApiGridPager', sortname: 'apiId', viewrecords: true, sortorder: "asc", @@ -152,6 +155,9 @@ // selectedApiGrid.jqGrid('delRowData', rowid); } }); + + selectedApiGrid.jqGrid('setLabel', 'rn', 'No'); // 가상 인덱스 ColNames + $.ajax({ type: "POST", url: url, From 9a1e73ec4f0004be736872c39a78480566ddf437 Mon Sep 17 00:00:00 2001 From: Rinjae Date: Tue, 30 Dec 2025 15:32:23 +0900 Subject: [PATCH 15/32] =?UTF-8?q?=EA=B0=9C=EB=B0=9C=EC=9E=90=ED=8F=AC?= =?UTF-8?q?=ED=83=88=20=EA=B4=80=EB=A0=A8=20summernote=20=EC=98=81?= =?UTF-8?q?=EC=97=AD=20=EC=97=90=EB=94=94=ED=84=B0=20=EC=8A=A4=ED=83=80?= =?UTF-8?q?=EC=9D=BC=20=EC=A0=95=EA=B7=9C=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebContent/css/editor-content.css | 334 ++++++++++++++++++ .../onl/apim/portalfaq/portalFaqManDetail.jsp | 2 + .../portalnotice/portalNoticeManDetail.jsp | 2 + .../apim/portalterms/portalTermsManDetail.jsp | 2 + 4 files changed, 340 insertions(+) create mode 100644 WebContent/css/editor-content.css diff --git a/WebContent/css/editor-content.css b/WebContent/css/editor-content.css new file mode 100644 index 0000000..c144110 --- /dev/null +++ b/WebContent/css/editor-content.css @@ -0,0 +1,334 @@ +/** + * Editor Content Styles (editor-content.css) + * + * Summernote 에디터로 작성된 HTML 콘텐츠의 공통 스타일 + * 관리자포탈/개발자포탈 양쪽에서 동일하게 사용 + * + * 사용법: + * - 관리자포탈: Summernote .note-editable에 .editor-content 클래스 추가 + * - 개발자포탈: 콘텐츠 wrapper에 .editor-content 클래스 추가 + * + * @version 1.0.0 + * @date 2025-12-30 + */ + +/* ========================================================================== + CSS Reset + 기본 설정 + ========================================================================== */ + +.editor-content { + all: revert; + font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important; + font-size: 16px !important; + font-weight: 400 !important; + line-height: 1.8 !important; + color: #1A1A2E !important; + word-wrap: break-word; + text-align: left !important; +} + +/* ========================================================================== + 헤딩 (Headings) + ========================================================================== */ + +.editor-content h1 { + font-size: 20px !important; + font-weight: 700 !important; + margin: 32px 0 16px !important; + line-height: 1.4 !important; + color: #1A1A2E !important; +} + +.editor-content h1:first-child { + margin-top: 0 !important; +} + +.editor-content h2 { + font-size: 18px !important; + font-weight: 700 !important; + margin: 24px 0 8px !important; + line-height: 1.4 !important; + color: #1A1A2E !important; +} + +.editor-content h3 { + font-size: 16px !important; + font-weight: 600 !important; + margin: 16px 0 8px !important; + line-height: 1.4 !important; + color: #1A1A2E !important; +} + +.editor-content h4, +.editor-content h5, +.editor-content h6 { + font-size: 16px !important; + font-weight: 600 !important; + margin: 16px 0 8px !important; + line-height: 1.4 !important; + color: #1A1A2E !important; +} + +/* ========================================================================== + 단락 (Paragraphs) + ========================================================================== */ + +.editor-content p { + margin-bottom: 16px !important; + line-height: 1.8 !important; + font-size: 16px !important; +} + +.editor-content p:last-child { + margin-bottom: 0 !important; +} + +/* ========================================================================== + 리스트 (Lists) - 글로벌 reset 대응 + ========================================================================== */ + +.editor-content ul { + list-style-type: disc !important; + padding-left: 32px !important; + margin: 16px 0 !important; +} + +.editor-content ol { + list-style-type: decimal !important; + padding-left: 32px !important; + margin: 16px 0 !important; +} + +.editor-content li { + margin-bottom: 8px !important; + line-height: 1.8 !important; + font-size: 16px !important; +} + +.editor-content li:last-child { + margin-bottom: 0 !important; +} + +/* 중첩 리스트 */ +.editor-content ul ul { + list-style-type: circle !important; + margin: 8px 0 !important; +} + +.editor-content ul ul ul { + list-style-type: square !important; +} + +.editor-content ol ol { + list-style-type: lower-alpha !important; + margin: 8px 0 !important; +} + +.editor-content ol ol ol { + list-style-type: lower-roman !important; +} + +/* ========================================================================== + 테이블 (Tables) + ========================================================================== */ + +.editor-content table { + width: 100% !important; + border-collapse: collapse !important; + margin: 24px 0 !important; + border: 1px solid #E2E8F0 !important; + border-radius: 8px !important; + overflow: hidden !important; + font-size: 14px !important; +} + +.editor-content th, +.editor-content td { + border: 1px solid #E2E8F0 !important; + padding: 8px 16px !important; + text-align: left !important; + vertical-align: top !important; +} + +.editor-content th { + background: #EFF6FF !important; + font-weight: 600 !important; + color: #1A1A2E !important; +} + +.editor-content tr:hover { + background: #F8FAFC !important; +} + +/* ========================================================================== + 링크 (Links) + ========================================================================== */ + +.editor-content a { + color: #0049b4 !important; + text-decoration: underline !important; + transition: color 0.3s ease !important; +} + +.editor-content a:hover { + color: #003080 !important; +} + +/* ========================================================================== + 인용문 (Blockquote) + ========================================================================== */ + +.editor-content blockquote { + border-left: 4px solid #0049b4 !important; + padding: 16px 24px !important; + margin: 24px 0 !important; + background: #F8FAFC !important; + font-style: italic !important; + color: #64748B !important; + border-radius: 0 8px 8px 0 !important; +} + +.editor-content blockquote p { + margin-bottom: 0 !important; +} + +/* ========================================================================== + 이미지 (Images) + ========================================================================== */ + +.editor-content img { + max-width: 100% !important; + height: auto !important; + border-radius: 8px !important; + margin: 16px 0 !important; + display: block !important; +} + +/* ========================================================================== + 코드 (Code) + ========================================================================== */ + +.editor-content code { + background: #F8FAFC !important; + padding: 2px 6px !important; + border-radius: 4px !important; + font-family: 'Fira Code', 'Courier New', monospace !important; + font-size: 0.9em !important; + color: #0049b4 !important; +} + +.editor-content pre { + background: #F8FAFC !important; + border: 1px solid #E2E8F0 !important; + border-radius: 8px !important; + padding: 16px !important; + overflow-x: auto !important; + margin: 16px 0 !important; +} + +.editor-content pre code { + background: transparent !important; + padding: 0 !important; + color: #1A1A2E !important; +} + +/* ========================================================================== + 구분선 (Horizontal Rule) + ========================================================================== */ + +.editor-content hr { + border: none !important; + border-top: 1px solid #E2E8F0 !important; + margin: 32px 0 !important; +} + +/* ========================================================================== + 텍스트 강조 (Text Emphasis) + ========================================================================== */ + +.editor-content strong, +.editor-content b { + font-weight: 700 !important; +} + +.editor-content em, +.editor-content i { + font-style: italic !important; +} + +.editor-content u { + text-decoration: underline !important; +} + +.editor-content s, +.editor-content strike, +.editor-content del { + text-decoration: line-through !important; +} + +.editor-content mark { + background-color: #FEF3C7 !important; + padding: 0 2px !important; +} + +.editor-content sub { + vertical-align: sub !important; + font-size: 0.8em !important; +} + +.editor-content sup { + vertical-align: super !important; + font-size: 0.8em !important; +} + +/* ========================================================================== + 반응형 (Responsive) + ========================================================================== */ + +@media (max-width: 768px) { + .editor-content { + font-size: 14px !important; + } + + .editor-content h1 { + font-size: 18px !important; + } + + .editor-content h2 { + font-size: 16px !important; + } + + .editor-content h3, + .editor-content h4, + .editor-content h5, + .editor-content h6 { + font-size: 14px !important; + } + + .editor-content p, + .editor-content li { + font-size: 14px !important; + } + + .editor-content table { + font-size: 12px !important; + } + + .editor-content th, + .editor-content td { + padding: 4px 8px !important; + } + + .editor-content ul, + .editor-content ol { + padding-left: 24px !important; + } + + .editor-content blockquote { + padding: 8px 16px !important; + } + + .editor-content pre { + padding: 8px !important; + } +} diff --git a/WebContent/jsp/onl/apim/portalfaq/portalFaqManDetail.jsp b/WebContent/jsp/onl/apim/portalfaq/portalFaqManDetail.jsp index 5bc469a..d82566d 100644 --- a/WebContent/jsp/onl/apim/portalfaq/portalFaqManDetail.jsp +++ b/WebContent/jsp/onl/apim/portalfaq/portalFaqManDetail.jsp @@ -13,6 +13,7 @@ FAQ 상세 + "/> ", Pattern.CASE_INSENSITIVE), - Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", - Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), - Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", - Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), Pattern.compile("", Pattern.CASE_INSENSITIVE), Pattern.compile("", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL), @@ -46,6 +43,16 @@ class RequestWrapper extends HttpServletRequestWrapper { Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL) }; + // src 속성 화이트리스트 패턴 - data:image/만 허용 + private static final Pattern SRC_ATTR_PATTERN = Pattern.compile( + "(src\\s*=\\s*)([\"'])([^\"']*?)\\2", + Pattern.CASE_INSENSITIVE); + + // 허용되는 src 값 패턴 (화이트리스트) - data:image/만 허용 + private static final Pattern ALLOWED_SRC_PATTERN = Pattern.compile( + "^data:image/.*", + Pattern.CASE_INSENSITIVE); + public RequestWrapper(HttpServletRequest servletRequest) { super(servletRequest); @@ -123,6 +130,10 @@ class RequestWrapper extends HttpServletRequestWrapper { // script 문자열을 완전히 제거 value = value.replaceAll("(?i)\\bscript\\b", ""); + + // src 속성 화이트리스트 필터링 - 허용된 프로토콜만 통과 + value = filterSrcAttribute(value); + StringBuilder sb = new StringBuilder(); value = convertChars(value, sb); @@ -133,6 +144,37 @@ class RequestWrapper extends HttpServletRequestWrapper { return value; } + /** + * src 속성을 화이트리스트 방식으로 필터링 + * 허용: data:image/ (Base64 이미지) + * 비허용: 그 외 모든 프로토콜 + */ + private String filterSrcAttribute(String value) { + if (value == null || !value.toLowerCase().contains("src")) { + return value; + } + + Matcher matcher = SRC_ATTR_PATTERN.matcher(value); + StringBuffer result = new StringBuffer(); + + while (matcher.find()) { + String srcPrefix = matcher.group(1); // src= + String quote = matcher.group(2); // " 또는 ' + String srcValue = matcher.group(3); // src 값 + + // 빈 값이거나 화이트리스트에 매칭되면 유지 + if (srcValue.isEmpty() || ALLOWED_SRC_PATTERN.matcher(srcValue).matches()) { + matcher.appendReplacement(result, Matcher.quoteReplacement(srcPrefix + quote + srcValue + quote)); + } else { + // 허용되지 않는 프로토콜은 src="" 로 대체 + matcher.appendReplacement(result, Matcher.quoteReplacement(srcPrefix + quote + quote)); + } + } + matcher.appendTail(result); + + return result.toString(); + } + // '(', ')', '"' 문자는 getMethod()가 "get"일 때만 변환됨. // 이는 gridData에서 사용되는 큰따옴표(")와 변환 함수에서 사용하는 괄호('(', ')')의 처리를 위함. private String convertChars(String value, StringBuilder sb) { From 6c1db7176951c8f7e41d2954958cd668afb3ef29 Mon Sep 17 00:00:00 2001 From: "Yunsam.Eo" Date: Fri, 2 Jan 2026 11:35:10 +0900 Subject: [PATCH 17/32] =?UTF-8?q?variableUrlRequest=20=EC=8B=9D=EB=B3=84?= =?UTF-8?q?=20=EC=A0=95=EA=B7=9C=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../eai/rms/onl/transaction/apim/ApiInterfaceService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/eactive/eai/rms/onl/transaction/apim/ApiInterfaceService.java b/src/main/java/com/eactive/eai/rms/onl/transaction/apim/ApiInterfaceService.java index f46f749..c3c521a 100644 --- a/src/main/java/com/eactive/eai/rms/onl/transaction/apim/ApiInterfaceService.java +++ b/src/main/java/com/eactive/eai/rms/onl/transaction/apim/ApiInterfaceService.java @@ -553,7 +553,7 @@ public class ApiInterfaceService extends OnlBaseService { restOption.setMethod(outboundHttpMethod); restOption.setExtraPath(outboundRestPath); - String pathType = outboundRestPath.matches(".*\\{[a-zA-Z]+\\}.*") ? "variableUrlRequest" : "simpleRequest"; + String pathType = outboundRestPath.matches(".*\\{[_a-zA-Z]+\\}.*") ? "variableUrlRequest" : "simpleRequest"; restOption.setType(pathType); if (StringUtils.isNotBlank(contentType)) { From fa993157e9c9d90c9570a34a01c2a0defcd2bc53 Mon Sep 17 00:00:00 2001 From: Rinjae Date: Fri, 2 Jan 2026 13:12:24 +0900 Subject: [PATCH 18/32] =?UTF-8?q?=EC=84=B8=EC=85=98=20=EB=A7=8C=EB=A3=8C?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99=20context=20path=20=EA=B4=80=EB=A0=A8=20?= =?UTF-8?q?=EC=9D=B4=EC=8A=88=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebContent/emergency.jsp | 7 ++++--- .../rms/common/interceptor/SessionCheckInterceptor.java | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/WebContent/emergency.jsp b/WebContent/emergency.jsp index 04bba57..667d56a 100644 --- a/WebContent/emergency.jsp +++ b/WebContent/emergency.jsp @@ -6,16 +6,17 @@ diff --git a/src/main/java/com/eactive/eai/rms/common/interceptor/SessionCheckInterceptor.java b/src/main/java/com/eactive/eai/rms/common/interceptor/SessionCheckInterceptor.java index a339126..1d9d9d2 100644 --- a/src/main/java/com/eactive/eai/rms/common/interceptor/SessionCheckInterceptor.java +++ b/src/main/java/com/eactive/eai/rms/common/interceptor/SessionCheckInterceptor.java @@ -67,9 +67,9 @@ public class SessionCheckInterceptor extends HandlerInterceptorAdapter { } else { //request.getRequestDispatcher("/monitoring/loginForm.do").forward(request, response); //request.getSession().setAttribute("redirectInProgress", true); - response.sendRedirect("/monitoring/rms/logout.do"); + response.sendRedirect(request.getContextPath() + "/rms/logout.do"); //response.sendRedirect("/monitoring/loginForm.do"); - + } } From b477c84a63592a4d3d1d85db11401e3466858851 Mon Sep 17 00:00:00 2001 From: daekuk Date: Fri, 2 Jan 2026 13:44:21 +0900 Subject: [PATCH 19/32] =?UTF-8?q?merge=20=EC=B6=A9=EB=8F=8C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebContent/WEB-INF/web.xml | 45 +++++++++++--------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/WebContent/WEB-INF/web.xml b/WebContent/WEB-INF/web.xml index dc7a0ea..a73128b 100644 --- a/WebContent/WEB-INF/web.xml +++ b/WebContent/WEB-INF/web.xml @@ -9,16 +9,7 @@ contextConfigLocation /WEB-INF/applicationContext.xml - - - CrossScriptingFilter - com.eactive.eai.rms.common.filter.CrossScriptingFilter - - - CrossScriptingFilter - /* - - + encodingFilter org.springframework.web.filter.CharacterEncodingFilter @@ -31,30 +22,20 @@ true + + + encodingFilter + /* + + + - encodingFilterEUCKR - org.springframework.web.filter.CharacterEncodingFilter - - encoding - utf-8 - - - forceEncoding - true - + CrossScriptingFilter + com.eactive.eai.rms.common.filter.CrossScriptingFilter - encodingFilterEUCKR - *.excel - - - encodingFilter - *.file - - - - encodingFilter - *.json + CrossScriptingFilter + /* + + + CrossScriptingFilter + com.eactive.eai.rms.common.filter.CrossScriptingFilter + + + CrossScriptingFilter + /* + + encodingFilter org.springframework.web.filter.CharacterEncodingFilter @@ -22,20 +31,30 @@ true - - - encodingFilter - /* - - - - CrossScriptingFilter - com.eactive.eai.rms.common.filter.CrossScriptingFilter + encodingFilterEUCKR + org.springframework.web.filter.CharacterEncodingFilter + + encoding + utf-8 + + + forceEncoding + true + - CrossScriptingFilter - /* + encodingFilterEUCKR + *.excel + + + encodingFilter + *.file + + + + encodingFilter + *.json - - - + +"/>