Merge remote-tracking branch 'origin/jenkins_with_weblogic' of C:/KJB_DEV/eapim-bundle/bundles/251216/eapim-admin_incremental_2025-12-01.bundle into jenkins_with_weblogic
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
package com.eactive.eai.rms.common.util;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 서버 시작 시 등록된 HTTP 엔드포인트 목록을 로그로 출력
|
||||
*/
|
||||
@Component
|
||||
public class EndpointLogger implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(EndpointLogger.class);
|
||||
|
||||
private boolean logged = false;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
// 중복 출력 방지 (parent/child context)
|
||||
if (logged) {
|
||||
return;
|
||||
}
|
||||
|
||||
ApplicationContext ctx = event.getApplicationContext();
|
||||
|
||||
try {
|
||||
RequestMappingHandlerMapping mapping = ctx.getBean(RequestMappingHandlerMapping.class);
|
||||
Map<RequestMappingInfo, HandlerMethod> methods = mapping.getHandlerMethods();
|
||||
|
||||
log.debug("========== Registered HTTP Endpoints ({}) ==========", methods.size());
|
||||
|
||||
methods.entrySet().stream()
|
||||
.sorted((e1, e2) -> e1.getKey().toString().compareTo(e2.getKey().toString()))
|
||||
.forEach(entry -> {
|
||||
RequestMappingInfo info = entry.getKey();
|
||||
HandlerMethod method = entry.getValue();
|
||||
log.debug("{} -> {}.{}",
|
||||
info.getPatternsCondition(),
|
||||
method.getBeanType().getSimpleName(),
|
||||
method.getMethod().getName());
|
||||
});
|
||||
|
||||
log.debug("========== End of Endpoints ==========");
|
||||
logged = true;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to log endpoints: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.apim.obp;
|
||||
|
||||
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* ObpGwMetric Repository (eapim-admin 위치)
|
||||
* API Gateway 시간별 거래량 지표 조회/저장을 위한 Spring Data JPA Repository
|
||||
*/
|
||||
@EMSDataSource
|
||||
public interface ObpGwMetricRepository extends BaseRepository<ObpGwMetric, String> {
|
||||
|
||||
/**
|
||||
* UPSERT 판단을 위한 기존 데이터 조회
|
||||
* 동일한 timeslice + apiId + clientId + hostname + orgId 조합이 존재하는지 확인
|
||||
*/
|
||||
Optional<ObpGwMetric> findByTimesliceAndApiIdAndClientIdAndHostnameAndOrgId(
|
||||
LocalDateTime timeslice,
|
||||
String apiId,
|
||||
String clientId,
|
||||
String hostname,
|
||||
String orgId
|
||||
);
|
||||
|
||||
/**
|
||||
* 특정 시간대의 모든 GwMetric 데이터 조회
|
||||
*/
|
||||
List<ObpGwMetric> findByTimeslice(LocalDateTime timeslice);
|
||||
|
||||
/**
|
||||
* 특정 시간 범위의 GwMetric 데이터 조회
|
||||
*/
|
||||
List<ObpGwMetric> findByTimesliceBetween(LocalDateTime startTime, LocalDateTime endTime);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.apim.obp;
|
||||
|
||||
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
|
||||
import com.eactive.apim.portal.obp.repository.ObpGwMetricRepository;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -43,6 +44,13 @@ public class ObpGwMetricService {
|
||||
return repository.findByTimesliceBetween(startTime, endTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 시간대 이후의 모든 GwMetric 데이터 조회
|
||||
*/
|
||||
public List<ObpGwMetric> findByTimesliceGreaterThanEqual(LocalDateTime timeslice) {
|
||||
return repository.findByTimesliceGreaterThanEqual(timeslice);
|
||||
}
|
||||
|
||||
/**
|
||||
* 엔티티 저장 (INSERT 또는 UPDATE)
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.eactive.eai.rms.onl.apim.obp;
|
||||
|
||||
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
|
||||
import com.google.gson.annotations.SerializedName;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* ObpGwMetric JSON 응답 DTO (after-timeslice 엔드포인트용)
|
||||
*
|
||||
* <p>예시 출력 형식에 맞춤:</p>
|
||||
* <pre>
|
||||
* {
|
||||
* "apiId": "1ba56b82-a9c9-41e2-b3ab-ff9377667d56",
|
||||
* "apiName": "[해외송금] 가상계좌 입금실패 정보조회",
|
||||
* "apiRoutingUri": "/api/obs/remittance/remittancefail*",
|
||||
* "orgId": "ORG001",
|
||||
* "partnerCode": "000008-01",
|
||||
* "appId": "APP001",
|
||||
* "appKey": "l7xx2fd7efc523794be5a1b126873a5de613",
|
||||
* "requestUri": "-1",
|
||||
* "timeslice": "2025-12-02T03:00:00.000+0000",
|
||||
* "attemptedCount": 3,
|
||||
* "completedCount": 3
|
||||
* }
|
||||
* </pre>
|
||||
*/
|
||||
@Data
|
||||
public class ObpGwMetricAfterDTO {
|
||||
|
||||
private static final DateTimeFormatter ISO8601_MILLIS_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'+0000'");
|
||||
|
||||
@SerializedName("apiId")
|
||||
private String apiId;
|
||||
|
||||
@SerializedName("apiName")
|
||||
private String apiName;
|
||||
|
||||
@SerializedName("apiRoutingUri")
|
||||
private String apiRoutingUri;
|
||||
|
||||
@SerializedName("orgId")
|
||||
private String orgId;
|
||||
|
||||
@SerializedName("partnerCode")
|
||||
private String partnerCode;
|
||||
|
||||
@SerializedName("appId")
|
||||
private String appId;
|
||||
|
||||
@SerializedName("appKey")
|
||||
private String appKey;
|
||||
|
||||
@SerializedName("requestUri")
|
||||
private String requestUri;
|
||||
|
||||
@SerializedName("timeslice")
|
||||
private String timeslice;
|
||||
|
||||
@SerializedName("attemptedCount")
|
||||
private Long attemptedCount;
|
||||
|
||||
@SerializedName("completedCount")
|
||||
private Long completedCount;
|
||||
|
||||
/**
|
||||
* Entity → DTO 변환
|
||||
*/
|
||||
public static ObpGwMetricAfterDTO from(ObpGwMetric entity) {
|
||||
ObpGwMetricAfterDTO dto = new ObpGwMetricAfterDTO();
|
||||
dto.setApiId(entity.getApiId());
|
||||
dto.setApiName(entity.getApiName());
|
||||
dto.setApiRoutingUri(entity.getUri());
|
||||
dto.setOrgId(entity.getOrgId());
|
||||
dto.setPartnerCode(entity.getPartnerCode());
|
||||
dto.setAppId(entity.getAppId());
|
||||
dto.setAppKey(entity.getClientId());
|
||||
dto.setRequestUri(entity.getRequestUri());
|
||||
dto.setTimeslice(formatTimeslice(entity.getTimeslice()));
|
||||
dto.setAttemptedCount(entity.getAttemptedCount());
|
||||
dto.setCompletedCount(entity.getCompletedCount());
|
||||
return dto;
|
||||
}
|
||||
|
||||
/**
|
||||
* timeslice를 ISO8601 형식 (밀리초 포함) + UTC 시간대로 변환
|
||||
* 예: 2025-12-02T03:00:00.000+0000
|
||||
*/
|
||||
private static String formatTimeslice(LocalDateTime timeslice) {
|
||||
if (timeslice == null) return null;
|
||||
return timeslice.format(ISO8601_MILLIS_FORMATTER);
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
@@ -27,7 +28,7 @@ public class ObpGwMetricController implements InterceptorSkipController {
|
||||
private static final Logger log = LoggerFactory.getLogger(ObpGwMetricController.class);
|
||||
|
||||
private static final DateTimeFormatter PATH_FORMATTER =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd_HH:mm:ss");
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd_HH:mm:ss");
|
||||
|
||||
private final ObpGwMetricManService obpGwMetricManService;
|
||||
|
||||
@@ -39,15 +40,18 @@ public class ObpGwMetricController implements InterceptorSkipController {
|
||||
* 특정 시간대의 GwMetric 데이터 조회
|
||||
*
|
||||
* @param datetime 조회 시간대 (형식: yyyy-MM-dd_HH:mm:ss)
|
||||
* @param pretty true면 JSON 들여쓰기 적용
|
||||
* @return JSON Array
|
||||
*/
|
||||
@RequestMapping(
|
||||
value = "/kjb/gw-metrics/{datetime}",
|
||||
value = "/kjb/gw-metrics/{datetime}.json",
|
||||
produces = "application/json;charset=utf-8"
|
||||
)
|
||||
@ResponseBody
|
||||
public String getGwMetrics(@PathVariable("datetime") String datetime) {
|
||||
log.debug("GwMetric 조회 요청: datetime={}", datetime);
|
||||
public String getGwMetrics(
|
||||
@PathVariable("datetime") String datetime,
|
||||
@RequestParam(value = "pretty", required = false) Boolean pretty) {
|
||||
log.debug("GwMetric 조회 요청: datetime={}, pretty={}", datetime, pretty);
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
@@ -59,11 +63,7 @@ public class ObpGwMetricController implements InterceptorSkipController {
|
||||
List<ObpGwMetricDTO> metrics = obpGwMetricManService.findByTimeslice(timeslice);
|
||||
|
||||
// JSON 변환 (GSON)
|
||||
Gson gson = new GsonBuilder()
|
||||
.serializeNulls()
|
||||
.create();
|
||||
|
||||
String json = gson.toJson(metrics);
|
||||
String json = toJson(metrics, pretty);
|
||||
|
||||
// 응답 크기 계산 (UTF-8 기준)
|
||||
int jsonBytes = json.getBytes(StandardCharsets.UTF_8).length;
|
||||
@@ -81,6 +81,66 @@ public class ObpGwMetricController implements InterceptorSkipController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 시간대 이후의 GwMetric 데이터 조회
|
||||
*
|
||||
* @param datetime 조회 시작 시간대 (형식: yyyy-MM-dd_HH:mm:ss)
|
||||
* @param pretty true면 JSON 들여쓰기 적용
|
||||
* @return JSON Array (해당 시간대 이후의 모든 지표)
|
||||
*/
|
||||
@RequestMapping(
|
||||
value = "/kjb/gw-metrics/after-timeslice/{datetime}.json",
|
||||
produces = "application/json;charset=utf-8"
|
||||
)
|
||||
@ResponseBody
|
||||
public String getGwMetricsAfterTimeslice(
|
||||
@PathVariable("datetime") String datetime,
|
||||
@RequestParam(value = "pretty", required = false) Boolean pretty) {
|
||||
log.debug("GwMetric after-timeslice 조회 요청: datetime={}, pretty={}", datetime, pretty);
|
||||
long startTime = System.currentTimeMillis();
|
||||
|
||||
try {
|
||||
// Path 파라미터 파싱
|
||||
LocalDateTime targetTime = LocalDateTime.parse(datetime, PATH_FORMATTER);
|
||||
LocalDateTime timeslice = targetTime.withMinute(0).withSecond(0).withNano(0);
|
||||
|
||||
// 조회
|
||||
List<ObpGwMetricAfterDTO> metrics = obpGwMetricManService.findByTimesliceAfter(timeslice);
|
||||
|
||||
// JSON 변환 (GSON)
|
||||
String json = toJson(metrics, pretty);
|
||||
|
||||
// 응답 크기 계산 (UTF-8 기준)
|
||||
int jsonBytes = json.getBytes(StandardCharsets.UTF_8).length;
|
||||
String jsonSize = formatByteSize(jsonBytes);
|
||||
|
||||
long elapsed = System.currentTimeMillis() - startTime;
|
||||
log.info("GwMetric after-timeslice 조회 완료: datetime={}, count={}, size={}, elapsed={}ms",
|
||||
datetime, metrics.size(), jsonSize, elapsed);
|
||||
|
||||
return json;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("GwMetric after-timeslice 조회 실패: datetime={}", datetime, 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"
|
||||
|
||||
@@ -279,4 +279,18 @@ public class ObpGwMetricManService extends BaseService {
|
||||
.map(ObpGwMetricDTO::from)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* 특정 시간대 이후의 GwMetric 데이터 조회 (REST API용)
|
||||
* after-timeslice 엔드포인트에서 사용
|
||||
*/
|
||||
public List<ObpGwMetricAfterDTO> findByTimesliceAfter(LocalDateTime timeslice) {
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.MONITORING));
|
||||
|
||||
List<ObpGwMetric> entities = obpGwMetricService.findByTimesliceGreaterThanEqual(timeslice);
|
||||
return entities.stream()
|
||||
.map(ObpGwMetricAfterDTO::from)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user