Merge remote-tracking branch 'origin/jenkins_with_weblogic' of C:/KJB_DEV/eapim-bundle/bundles/251217/eapim-admin_incremental_2025-12-01.bundle into jenkins_with_weblogic

This commit is contained in:
Rinjae
2025-12-17 17:38:59 +09:00
9 changed files with 172 additions and 63 deletions
+1
View File
@@ -2,5 +2,6 @@
GET {{emsUrl}}/kjb/gw-metrics/after-timeslice/2025-12-02_01:00:00.json GET {{emsUrl}}/kjb/gw-metrics/after-timeslice/2025-12-02_01:00:00.json
### Pretty Print ### Pretty Print
GET {{emsUrl}}/kjb/gw-metrics/after-timeslice/2025-12-02_01:00:00.json?pretty=true GET {{emsUrl}}/kjb/gw-metrics/after-timeslice/2025-12-02_01:00:00.json?pretty=true
+4
View File
@@ -33,6 +33,10 @@
# Spring Bean 설정 및 리소스 실시간 반영 (경로 주의) # Spring Bean 설정 및 리소스 실시간 반영 (경로 주의)
-javaagent:C:\path\to\hotswap-agent.jar -javaagent:C:\path\to\hotswap-agent.jar
-XX:HotswapAgent=fatjar
-Dhotswap.agent.disablePlugin=org.hotswap.agent.plugin.ibatis.IBatisPlugin,org.hotswap.agent.plugin.mybatis.MyBatisPlugin
``` ```
----- -----
@@ -61,18 +61,39 @@ public class ObpGwMetricDAO extends SqlMapClientTemplateDao {
} }
/** /**
* URI 조회 (HTTP_ADAPTER_EXTRA_LOG) * URI 및 HTTP Method 조회 결과
*/
public static class UriMethodResult {
private final Map<String, String> uriMap;
private final Map<String, String> methodMap;
public UriMethodResult(Map<String, String> uriMap, Map<String, String> methodMap) {
this.uriMap = uriMap;
this.methodMap = methodMap;
}
public Map<String, String> getUriMap() {
return uriMap;
}
public Map<String, String> getMethodMap() {
return methodMap;
}
}
/**
* URI 및 HTTP Method 조회 (HTTP_ADAPTER_EXTRA_LOG)
* - GUID = TSEAILG1X.EAISVCSERNO와 매핑 * - GUID = TSEAILG1X.EAISVCSERNO와 매핑
* - SERVICE_PROCESS_NUMBER = 100 (인바운드 요청) * - SERVICE_PROCESS_NUMBER = 100 (인바운드 요청)
* *
* @param schemaId DB 스키마 ID * @param schemaId DB 스키마 ID
* @param eaiSvcSernos EAI 서비스 일련번호 목록 (GUID) * @param eaiSvcSernos EAI 서비스 일련번호 목록 (GUID)
* @return eaiSvcSerno → URI 맵 (예: "POST /api/v1/transfer") * @return UriMethodResult (eaiSvcSerno → URI 맵, eaiSvcSerno → METHOD 맵)
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public Map<String, String> selectUris(String schemaId, Set<String> eaiSvcSernos) { public UriMethodResult selectUrisAndMethods(String schemaId, Set<String> eaiSvcSernos) {
if (eaiSvcSernos == null || eaiSvcSernos.isEmpty()) { if (eaiSvcSernos == null || eaiSvcSernos.isEmpty()) {
return new HashMap<>(); return new UriMethodResult(new HashMap<>(), new HashMap<>());
} }
HashMap<String, Object> paramMap = new HashMap<>(); HashMap<String, Object> paramMap = new HashMap<>();
@@ -81,15 +102,22 @@ public class ObpGwMetricDAO extends SqlMapClientTemplateDao {
List<Map<String, String>> resultList = this.template.queryForList("ObpGwMetric.selectUris", paramMap); List<Map<String, String>> resultList = this.template.queryForList("ObpGwMetric.selectUris", paramMap);
Map<String, String> result = new HashMap<>(); Map<String, String> uriMap = new HashMap<>();
Map<String, String> methodMap = new HashMap<>();
for (Map<String, String> m : resultList) { for (Map<String, String> m : resultList) {
String eaiSvcSerno = m.get("EAI_SVC_SERNO"); String eaiSvcSerno = m.get("EAI_SVC_SERNO");
String uri = m.get("URI"); String uri = m.get("URI");
if (eaiSvcSerno != null && uri != null) { String method = m.get("METHOD");
result.put(eaiSvcSerno, uri); if (eaiSvcSerno != null) {
if (uri != null) {
uriMap.put(eaiSvcSerno, uri);
}
if (method != null) {
methodMap.put(eaiSvcSerno, method);
}
} }
} }
return result; return new UriMethodResult(uriMap, methodMap);
} }
/** /**
@@ -0,0 +1,101 @@
package com.eactive.eai.rms.onl.apim.common;
import com.eactive.eai.rms.common.interceptor.InterceptorSkipController;
import com.google.gson.GsonBuilder;
import java.nio.charset.StandardCharsets;
/**
* REST API Controller 기본 클래스
*
* <p>기능:</p>
* <ul>
* <li>세션 체크 우회 (InterceptorSkipController)</li>
* <li>JSON 변환 유틸리티 (pretty print 지원)</li>
* <li>응답 크기 포맷팅</li>
* </ul>
*
* <p>사용 예:</p>
* <pre>
* {@code
* @Controller
* public class MyApiController extends BaseRestController {
* @RequestMapping(value = "/api/something.json", produces = JSON_CONTENT_TYPE)
* @ResponseBody
* public String getSomething(@RequestParam(value = "pretty", required = false) Boolean pretty) {
* List<MyDTO> data = service.getData();
* return toJson(data, pretty);
* }
* }
* }
* </pre>
*/
public abstract class BaseRestController implements InterceptorSkipController {
/**
* JSON 응답 Content-Type
*/
protected static final String JSON_CONTENT_TYPE = "application/json;charset=utf-8";
/**
* 객체를 JSON 문자열로 변환
*
* @param object 변환할 객체
* @param pretty true면 들여쓰기 적용 (null이면 false로 처리)
* @return JSON 문자열
*/
protected String toJson(Object object, Boolean pretty) {
GsonBuilder builder = new GsonBuilder().serializeNulls();
if (Boolean.TRUE.equals(pretty)) {
builder.setPrettyPrinting();
}
return builder.create().toJson(object);
}
/**
* 객체를 JSON 문자열로 변환 (기본: 한 줄 출력)
*
* @param object 변환할 객체
* @return JSON 문자열
*/
protected String toJson(Object object) {
return toJson(object, false);
}
/**
* 바이트 크기를 읽기 쉬운 형식으로 변환
* 예: 1024 -> "1.0 KB", 1048576 -> "1.0 MB"
*
* @param bytes 바이트 수
* @return 포맷된 문자열
*/
protected String formatByteSize(long bytes) {
if (bytes < 1024) {
return bytes + " B";
} else if (bytes < 1024 * 1024) {
return String.format("%.1f KB", bytes / 1024.0);
} else {
return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
}
}
/**
* JSON 문자열의 바이트 크기 계산 (UTF-8 기준)
*
* @param json JSON 문자열
* @return 바이트 수
*/
protected int getJsonByteSize(String json) {
return json.getBytes(StandardCharsets.UTF_8).length;
}
/**
* JSON 문자열의 포맷된 바이트 크기 반환
*
* @param json JSON 문자열
* @return 포맷된 크기 문자열
*/
protected String getFormattedJsonSize(String json) {
return formatByteSize(getJsonByteSize(json));
}
}
@@ -16,6 +16,7 @@ import java.time.format.DateTimeFormatter;
* "apiId": "1ba56b82-a9c9-41e2-b3ab-ff9377667d56", * "apiId": "1ba56b82-a9c9-41e2-b3ab-ff9377667d56",
* "apiName": "[해외송금] 가상계좌 입금실패 정보조회", * "apiName": "[해외송금] 가상계좌 입금실패 정보조회",
* "apiRoutingUri": "/api/obs/remittance/remittancefail*", * "apiRoutingUri": "/api/obs/remittance/remittancefail*",
* "httpMethod": "POST",
* "orgId": "ORG001", * "orgId": "ORG001",
* "partnerCode": "000008-01", * "partnerCode": "000008-01",
* "appId": "APP001", * "appId": "APP001",
@@ -42,6 +43,9 @@ public class ObpGwMetricAfterDTO {
@SerializedName("apiRoutingUri") @SerializedName("apiRoutingUri")
private String apiRoutingUri; private String apiRoutingUri;
@SerializedName("httpMethod")
private String httpMethod;
@SerializedName("orgId") @SerializedName("orgId")
private String orgId; private String orgId;
@@ -74,6 +78,7 @@ public class ObpGwMetricAfterDTO {
dto.setApiId(entity.getApiId()); dto.setApiId(entity.getApiId());
dto.setApiName(entity.getApiName()); dto.setApiName(entity.getApiName());
dto.setApiRoutingUri(entity.getUri()); dto.setApiRoutingUri(entity.getUri());
dto.setHttpMethod(entity.getMethod());
dto.setOrgId(entity.getOrgId()); dto.setOrgId(entity.getOrgId());
dto.setPartnerCode(entity.getPartnerCode()); dto.setPartnerCode(entity.getPartnerCode());
dto.setAppId(entity.getAppId()); dto.setAppId(entity.getAppId());
@@ -1,8 +1,6 @@
package com.eactive.eai.rms.onl.apim.obp; package com.eactive.eai.rms.onl.apim.obp;
import com.eactive.eai.rms.common.interceptor.InterceptorSkipController; import com.eactive.eai.rms.onl.apim.common.BaseRestController;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller; import org.springframework.stereotype.Controller;
@@ -11,7 +9,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseBody;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatter;
import java.util.List; import java.util.List;
@@ -20,10 +17,10 @@ import java.util.List;
* ObpGwMetric REST Controller * ObpGwMetric REST Controller
* API Gateway 시간별 거래량 지표 조회 API * API Gateway 시간별 거래량 지표 조회 API
* *
* <p>세션 체크를 우회하기 위해 InterceptorSkipController 인터페이스 구현</p> * @see BaseRestController 세션 체크 우회 및 JSON 유틸리티 제공
*/ */
@Controller @Controller
public class ObpGwMetricController implements InterceptorSkipController { public class ObpGwMetricController extends BaseRestController {
private static final Logger log = LoggerFactory.getLogger(ObpGwMetricController.class); private static final Logger log = LoggerFactory.getLogger(ObpGwMetricController.class);
@@ -45,7 +42,7 @@ public class ObpGwMetricController implements InterceptorSkipController {
*/ */
@RequestMapping( @RequestMapping(
value = "/kjb/gw-metrics/{datetime}.json", value = "/kjb/gw-metrics/{datetime}.json",
produces = "application/json;charset=utf-8" produces = JSON_CONTENT_TYPE
) )
@ResponseBody @ResponseBody
public String getGwMetrics( public String getGwMetrics(
@@ -65,13 +62,9 @@ public class ObpGwMetricController implements InterceptorSkipController {
// JSON 변환 (GSON) // JSON 변환 (GSON)
String json = toJson(metrics, pretty); String json = toJson(metrics, pretty);
// 응답 크기 계산 (UTF-8 기준)
int jsonBytes = json.getBytes(StandardCharsets.UTF_8).length;
String jsonSize = formatByteSize(jsonBytes);
long elapsed = System.currentTimeMillis() - startTime; long elapsed = System.currentTimeMillis() - startTime;
log.info("GwMetric 조회 완료: datetime={}, count={}, size={}, elapsed={}ms", log.info("GwMetric 조회 완료: datetime={}, count={}, size={}, elapsed={}ms",
datetime, metrics.size(), jsonSize, elapsed); datetime, metrics.size(), getFormattedJsonSize(json), elapsed);
return json; return json;
@@ -90,7 +83,7 @@ public class ObpGwMetricController implements InterceptorSkipController {
*/ */
@RequestMapping( @RequestMapping(
value = "/kjb/gw-metrics/after-timeslice/{datetime}.json", value = "/kjb/gw-metrics/after-timeslice/{datetime}.json",
produces = "application/json;charset=utf-8" produces = JSON_CONTENT_TYPE
) )
@ResponseBody @ResponseBody
public String getGwMetricsAfterTimeslice( public String getGwMetricsAfterTimeslice(
@@ -110,13 +103,9 @@ public class ObpGwMetricController implements InterceptorSkipController {
// JSON 변환 (GSON) // JSON 변환 (GSON)
String json = toJson(metrics, pretty); String json = toJson(metrics, pretty);
// 응답 크기 계산 (UTF-8 기준)
int jsonBytes = json.getBytes(StandardCharsets.UTF_8).length;
String jsonSize = formatByteSize(jsonBytes);
long elapsed = System.currentTimeMillis() - startTime; long elapsed = System.currentTimeMillis() - startTime;
log.info("GwMetric after-timeslice 조회 완료: datetime={}, count={}, size={}, elapsed={}ms", log.info("GwMetric after-timeslice 조회 완료: datetime={}, count={}, size={}, elapsed={}ms",
datetime, metrics.size(), jsonSize, elapsed); datetime, metrics.size(), getFormattedJsonSize(json), elapsed);
return json; return json;
@@ -125,33 +114,4 @@ public class ObpGwMetricController implements InterceptorSkipController {
throw e; throw e;
} }
} }
/**
* 객체를 JSON 문자열로 변환
*
* @param object 변환할 객체
* @param pretty true면 들여쓰기 적용
* @return JSON 문자열
*/
private String toJson(Object object, Boolean pretty) {
GsonBuilder builder = new GsonBuilder().serializeNulls();
if (Boolean.TRUE.equals(pretty)) {
builder.setPrettyPrinting();
}
return builder.create().toJson(object);
}
/**
* 바이트 크기를 읽기 쉬운 형식으로 변환
* 예: 1024 -> "1.0 KB", 1048576 -> "1.0 MB"
*/
private String formatByteSize(long bytes) {
if (bytes < 1024) {
return bytes + " B";
} else if (bytes < 1024 * 1024) {
return String.format("%.1f KB", bytes / 1024.0);
} else {
return String.format("%.1f MB", bytes / (1024.0 * 1024.0));
}
}
} }
@@ -32,6 +32,9 @@ public class ObpGwMetricDTO {
@SerializedName("apiRoutingUri") @SerializedName("apiRoutingUri")
private String uri; private String uri;
@SerializedName("httpMethod")
private String method;
@SerializedName("attemptedCount") @SerializedName("attemptedCount")
private Long attemptedCount; private Long attemptedCount;
@@ -74,6 +77,7 @@ public class ObpGwMetricDTO {
dto.setTimeslice(formatTimeslice(entity.getTimeslice())); dto.setTimeslice(formatTimeslice(entity.getTimeslice()));
dto.setApiName(entity.getApiName()); dto.setApiName(entity.getApiName());
dto.setUri(entity.getUri()); dto.setUri(entity.getUri());
dto.setMethod(entity.getMethod());
dto.setAttemptedCount(entity.getAttemptedCount()); dto.setAttemptedCount(entity.getAttemptedCount());
dto.setCompletedCount(entity.getCompletedCount()); dto.setCompletedCount(entity.getCompletedCount());
dto.setApiId(entity.getApiId()); dto.setApiId(entity.getApiId());
@@ -165,7 +165,9 @@ public class ObpGwMetricManService extends BaseService {
.collect(Collectors.toSet()); .collect(Collectors.toSet());
Map<String, String> apiNameMap = obpGwMetricDAO.selectApiNames(apigwDataSourceType.getSchema(), apiIds); Map<String, String> apiNameMap = obpGwMetricDAO.selectApiNames(apigwDataSourceType.getSchema(), apiIds);
Map<String, String> uriMap = obpGwMetricDAO.selectUris(apigwDataSourceType.getSchema(), eaiSvcSernos); ObpGwMetricDAO.UriMethodResult uriMethodResult = obpGwMetricDAO.selectUrisAndMethods(apigwDataSourceType.getSchema(), eaiSvcSernos);
Map<String, String> uriMap = uriMethodResult.getUriMap();
Map<String, String> methodMap = uriMethodResult.getMethodMap();
log.info("[3단계] 부가정보 조회 완료: apiCount={}, eaiSvcSernoCount={}, elapsed={}ms", log.info("[3단계] 부가정보 조회 완료: apiCount={}, eaiSvcSernoCount={}, elapsed={}ms",
apiIds.size(), eaiSvcSernos.size(), System.currentTimeMillis() - step3Start); apiIds.size(), eaiSvcSernos.size(), System.currentTimeMillis() - step3Start);
@@ -202,7 +204,8 @@ public class ObpGwMetricManService extends BaseService {
entity.setAttemptedCount(vo.getAttemptedCount()); entity.setAttemptedCount(vo.getAttemptedCount());
entity.setCompletedCount(vo.getCompletedCount()); entity.setCompletedCount(vo.getCompletedCount());
entity.setApiName(apiNameMap.get(vo.getApiId())); entity.setApiName(apiNameMap.get(vo.getApiId()));
entity.setUri(uriMap.get(vo.getEaiSvcSerno())); // eaiSvcSerno로 URI 조회 entity.setUri(uriMap.get(vo.getEaiSvcSerno())); // eaiSvcSerno로 URI 조회
entity.setMethod(methodMap.get(vo.getEaiSvcSerno())); // eaiSvcSerno로 HTTP Method 조회
entity.setAppId(appIdMap.get(vo.getOrgId())); entity.setAppId(appIdMap.get(vo.getOrgId()));
entity.setUpdateCount(entity.getUpdateCount() + 1); // 보정 횟수 증가 entity.setUpdateCount(entity.getUpdateCount() + 1); // 보정 횟수 증가
entity.setUpdatedAt(LocalDateTime.now()); entity.setUpdatedAt(LocalDateTime.now());
@@ -211,7 +214,7 @@ public class ObpGwMetricManService extends BaseService {
updateCount++; updateCount++;
} else { } else {
// INSERT: 신규 데이터 생성 // INSERT: 신규 데이터 생성
ObpGwMetric entity = convertToEntity(vo, apiNameMap, uriMap, appIdMap); ObpGwMetric entity = convertToEntity(vo, apiNameMap, uriMap, methodMap, appIdMap);
obpGwMetricService.save(entity); obpGwMetricService.save(entity);
insertCount++; insertCount++;
} }
@@ -249,7 +252,8 @@ public class ObpGwMetricManService extends BaseService {
* VO → Entity 변환 * VO → Entity 변환
*/ */
private ObpGwMetric convertToEntity(ObpGwMetricVO vo, Map<String, String> apiNameMap, private ObpGwMetric convertToEntity(ObpGwMetricVO vo, Map<String, String> apiNameMap,
Map<String, String> uriMap, Map<String, String> appIdMap) { Map<String, String> uriMap, Map<String, String> methodMap,
Map<String, String> appIdMap) {
ObpGwMetric entity = new ObpGwMetric(); ObpGwMetric entity = new ObpGwMetric();
entity.setClientId(vo.getClientId()); entity.setClientId(vo.getClientId());
entity.setHostname(vo.getHostname()); entity.setHostname(vo.getHostname());
@@ -259,7 +263,8 @@ public class ObpGwMetricManService extends BaseService {
entity.setAttemptedCount(vo.getAttemptedCount()); entity.setAttemptedCount(vo.getAttemptedCount());
entity.setCompletedCount(vo.getCompletedCount()); entity.setCompletedCount(vo.getCompletedCount());
entity.setApiName(apiNameMap.get(vo.getApiId())); entity.setApiName(apiNameMap.get(vo.getApiId()));
entity.setUri(uriMap.get(vo.getEaiSvcSerno())); // eaiSvcSerno로 URI 조회 entity.setUri(uriMap.get(vo.getEaiSvcSerno())); // eaiSvcSerno로 URI 조회
entity.setMethod(methodMap.get(vo.getEaiSvcSerno())); // eaiSvcSerno로 HTTP Method 조회
entity.setAppId(appIdMap.get(vo.getOrgId())); entity.setAppId(appIdMap.get(vo.getOrgId()));
entity.setUpdateCount(0); entity.setUpdateCount(0);
entity.setCreatedAt(LocalDateTime.now()); entity.setCreatedAt(LocalDateTime.now());
@@ -66,15 +66,16 @@
</statement> </statement>
<!-- <!--
URI 조회 (HTTP_ADAPTER_EXTRA_LOG) URI 및 HTTP Method 조회 (HTTP_ADAPTER_EXTRA_LOG)
- GUID = TSEAILG1X.EAISVCSERNO - GUID = TSEAILG1X.EAISVCSERNO
- SERVICE_PROCESS_NUMBER = 100 (인바운드 요청) - SERVICE_PROCESS_NUMBER = 100 (인바운드 요청)
- 결과: HTTP_METHOD + ' ' + URL (예: POST /mapi/kjbank/obp/kakaobank/v3/loan/query) - 결과: HTTP_METHOD (예: POST), URL (예: /mapi/kjbank/obp/kakaobank/v3/loan/query)
--> -->
<statement id="selectUris" parameterClass="java.util.HashMap" resultClass="java.util.HashMap"> <statement id="selectUris" parameterClass="java.util.HashMap" resultClass="java.util.HashMap">
SELECT SELECT
GUID AS EAI_SVC_SERNO, GUID AS EAI_SVC_SERNO,
HTTP_METHOD || ' ' || URL AS URI URL AS URI,
HTTP_METHOD AS METHOD
FROM $schemaId$.HTTP_ADAPTER_EXTRA_LOG FROM $schemaId$.HTTP_ADAPTER_EXTRA_LOG
WHERE SERVICE_PROCESS_NUMBER = 100 WHERE SERVICE_PROCESS_NUMBER = 100
AND GUID IN AND GUID IN