This commit is contained in:
@@ -273,6 +273,9 @@ public interface MonitoringContext {
|
||||
// 비밀번호 변경 시 재사용을 금지할 최근 이력 개수
|
||||
public static final String RMS_PASSWORD_HISTORY_COUNT = "rms.password.history.count";
|
||||
|
||||
// 비밀번호 변경 시 SMS 2차 인증 사용 여부 (djb.sms_auth.enabled 와 함께 true 여야 동작)
|
||||
public static final String RMS_PASSWORD_SMS_AUTH_ENABLED = "rms.password.sms_auth.enabled";
|
||||
|
||||
// API 상태변화 스윙챗 발송여부
|
||||
public static final String DJB_UMS_MESSENGER_APIMONITOR_ENABLED = "djb.ums.messenger.api-monitor.enabled";
|
||||
|
||||
|
||||
@@ -464,6 +464,11 @@ public class MainController implements InterceptorSkipController {
|
||||
MonitoringContext.RMS_PASSWORD_HISTORY_COUNT, DEFAULT_PASSWORD_HISTORY_COUNT);
|
||||
}
|
||||
|
||||
// 비밀번호 변경 시 SMS 2차 인증 사용 여부 (djb.sms_auth.enabled 와 rms.password.sms_auth.enabled 가 모두 true 여야 동작)
|
||||
private boolean isPasswordChangeSmsAuthEnabled() {
|
||||
return monitoringContext.getBooleanProperty(MonitoringContext.RMS_PASSWORD_SMS_AUTH_ENABLED, false);
|
||||
}
|
||||
|
||||
// 로그인 실패 횟수 증가, 임계치 도달 시 계정 잠금
|
||||
private int increaseLoginFailCount(UserInfo userInfo) {
|
||||
int failCount = (userInfo.getLoginfailcount() == null ? 0 : userInfo.getLoginfailcount()) + 1;
|
||||
@@ -909,8 +914,9 @@ public class MainController implements InterceptorSkipController {
|
||||
}
|
||||
|
||||
// 5. SMS 2차 인증 필요 여부 체크 (비상모드는 로그인과 동일하게 우회)
|
||||
// djb.sms_auth.enabled 와 rms.password.sms_auth.enabled 가 모두 true 일 때만 SMS 인증 수행
|
||||
Boolean emergencyMode = (Boolean) session.getAttribute("emergencyMode");
|
||||
if (!Boolean.TRUE.equals(emergencyMode) && smsAuthService.isEnabled()) {
|
||||
if (!Boolean.TRUE.equals(emergencyMode) && smsAuthService.isEnabled() && isPasswordChangeSmsAuthEnabled()) {
|
||||
if (!smsAuthService.hasValidPhoneNumber(userInfo)) {
|
||||
UserAccessLogger.log(request, LOG_CATEGORY_LOGIN, "F", "휴대폰번호 미등록으로 비밀번호 변경 불가");
|
||||
return ChangePasswordResponseDto.builder()
|
||||
|
||||
+6
@@ -31,6 +31,12 @@ public class LayoutSyncHistoryService extends AbstractDataService<LayoutSyncHist
|
||||
if (StringUtils.isNotBlank(search.getSearchLoutName())) {
|
||||
query.where(q.loutname.containsIgnoreCase(search.getSearchLoutName()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchServiceName())) {
|
||||
query.where(q.servicename.containsIgnoreCase(search.getSearchServiceName()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchCommand())) {
|
||||
query.where(q.command.containsIgnoreCase(search.getSearchCommand()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchStartDate())) {
|
||||
query.where(q.recvamndhms.goe(parseYYYYMMDD(search.getSearchStartDate()).atStartOfDay()));
|
||||
}
|
||||
|
||||
@@ -31,16 +31,16 @@ public class InflowTokenService {
|
||||
private UmsManager ums;
|
||||
|
||||
public void checkRecentFails(long rangeMinute) {
|
||||
List<InflowTokenInsufficient> rows = inflowTokenRepository.countTokenInsufficient(rangeMinute);
|
||||
|
||||
for (InflowTokenInsufficient info : rows) {
|
||||
log.debug("유량제어 토큰 획득 실패: {}-{} 최근 {}분 동안 {}건", info.getEaisvcname(), info.getEaisvcdesc(), rangeMinute, info.getCnt());
|
||||
String message = "유량제어 토큰 획득 실패가 발생하였습니다 \n" + info.getEaisvcname();
|
||||
|
||||
if (monitoringContext.getBooleanProperty(MonitoringContext.DJB_UMS_MESSENGER_APIMONITOR_ENABLED, true)) {
|
||||
if (monitoringContext.getBooleanProperty(MonitoringContext.DJB_UMS_MESSENGER_APIMONITOR_ENABLED, true)) {
|
||||
List<InflowTokenInsufficient> rows = inflowTokenRepository.countTokenInsufficient(rangeMinute);
|
||||
|
||||
for (InflowTokenInsufficient info : rows) {
|
||||
log.debug("유량제어 토큰 획득 실패: {}-{} 최근 {}분 동안 {}건", info.getEaisvcname(), info.getEaisvcdesc(), rangeMinute, info.getCnt());
|
||||
String message = "유량제어 토큰 획득 실패가 발생하였습니다 \n" + info.getEaisvcname();
|
||||
|
||||
HashMap<String,Object> params = new HashMap<String,Object>();
|
||||
params.put("message", message);
|
||||
ums.send("api-monitor", MessageCode.INFLOW_TOKEN_FAILED, params);
|
||||
ums.sendMessenger("api-monitor", MessageCode.INFLOW_TOKEN_FAILED, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,9 +126,9 @@ public class ApiStatsHourlyAggregationJob implements Job {
|
||||
" , API_NAME, GW_INSTANCE_ID, BIZ_DIV_CODE, NVL(A.CLIENT_ID, 'NONE')" +
|
||||
" , INBOUND_ADAPTER, OUTBOUND_ADAPTER" +
|
||||
" , COUNT(EAISVCSERNO)" +
|
||||
" , SUM(CASE WHEN (A.ERROR_CODE IS NULL OR C.CODE IS NOT NULL) AND E400 IS NOT NULL THEN 1 ELSE 0 END)" +
|
||||
" , SUM(CASE WHEN A.ERROR_CODE IS NULL OR C.CODE IS NOT NULL THEN 1 ELSE 0 END)" +
|
||||
" , SUM(CASE WHEN B.CODE IS NOT NULL THEN 1 ELSE 0 END)" +
|
||||
" , SUM(CASE WHEN (A.E400 IS NULL OR A.ERROR_CODE IS NOT NULL) AND B.CODE IS NULL AND C.CODE IS NULL THEN 1 ELSE 0 END)" +
|
||||
" , SUM(CASE WHEN A.ERROR_CODE IS NOT NULL AND B.CODE IS NULL AND C.CODE IS NULL THEN 1 ELSE 0 END)" +
|
||||
" , 0, 0, 0, 0" +
|
||||
" , TRUNC(AVG(RESP_TIME)), MIN(RESP_TIME), MAX(RESP_TIME), 0, 0" +
|
||||
" FROM (" +
|
||||
@@ -143,8 +143,7 @@ public class ApiStatsHourlyAggregationJob implements Job {
|
||||
" + TO_NUMBER(SUBSTR(MAX(MSGPRCSSYMS),15,3))" +
|
||||
" - TO_NUMBER(SUBSTR(MIN(MSGPRCSSYMS),15,3))" +
|
||||
" ) AS RESP_TIME" +
|
||||
" , MAX(CASE WHEN LOGPRCSSSERNO = '400' THEN LOGPRCSSSERNO ELSE '' END) AS E400" +
|
||||
" , MAX(EAIERRCD) AS ERROR_CODE" +
|
||||
" , MAX(CASE WHEN LOGPRCSSSERNO = '400' THEN EAIERRCD ELSE '' END) AS ERROR_CODE" +
|
||||
" FROM " + logTableName + " A " +
|
||||
" WHERE MSGDPSTYMS >= :rangeStart AND MSGDPSTYMS < :rangeEnd" +
|
||||
" GROUP BY EAISVCSERNO" +
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.eactive.eai.rms.ext.djb.job;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -13,7 +11,6 @@ import org.quartz.JobDataMap;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.Trigger;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -37,7 +34,7 @@ import com.eactive.eai.rms.onl.common.util.DateUtil;
|
||||
* <p>Job 파라미터 (JobDataMap):</p>
|
||||
* <ul>
|
||||
* <li>
|
||||
* NONE
|
||||
* <b>api.inflow.fail.range_minute</b>: 유량제어 토큰 획득 실패 조회 구간 (단위: 분, 기본값: 5)
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
@@ -48,6 +45,12 @@ public class InflowTokenMonitorJob implements Job {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(InflowTokenMonitorJob.class);
|
||||
|
||||
/** Job 파라미터 키: 유량제어 실패 조회 구간(분) */
|
||||
public static final String KEY_API_INFLOW_FAIL_RANGE_MINUTE = "api.inflow.fail.range_minute";
|
||||
|
||||
/** 유량제어 실패 조회 구간 기본값(분) */
|
||||
public static final String DEFAULT_RANGE_MINUTE = "5";
|
||||
|
||||
private transient MonitoringContext monitoringContext;
|
||||
|
||||
@Override
|
||||
@@ -69,18 +72,19 @@ public class InflowTokenMonitorJob implements Job {
|
||||
|
||||
log.info("*** START InflowTokenFailMonitorJob run({})", CommonUtil.getToday("yyyy-MM-dd HH:mm"));
|
||||
|
||||
long execMinute = 1; //default 배치 실행주기(분)
|
||||
|
||||
Trigger trigger = context.getTrigger();
|
||||
Date prevFireTime = trigger.getPreviousFireTime();
|
||||
Date nextFireTime = trigger.getNextFireTime();
|
||||
|
||||
//1회 이상 배치가 실행된 경우, 배치 간격을 구하여 유량제어조회 구간 파라미터로 전달한다
|
||||
if (prevFireTime != null && nextFireTime != null) {
|
||||
long diffMillis = nextFireTime.getTime() - prevFireTime.getTime();
|
||||
execMinute = TimeUnit.MILLISECONDS.toMinutes(diffMillis);
|
||||
log.info("실행 주기: {}분", execMinute);
|
||||
}
|
||||
// Job 프로퍼티에서 유량제어 실패 조회 구간(분)을 읽는다. 미지정 시 기본값 사용
|
||||
long execMinute;
|
||||
String rangeMinute = jobDataMap.getString(KEY_API_INFLOW_FAIL_RANGE_MINUTE);
|
||||
if (StringUtils.isEmpty(rangeMinute)) {
|
||||
rangeMinute = DEFAULT_RANGE_MINUTE;
|
||||
}
|
||||
try {
|
||||
execMinute = Long.parseLong(rangeMinute.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("잘못된 {} 값: {} - 기본값 {} 사용", KEY_API_INFLOW_FAIL_RANGE_MINUTE, rangeMinute, DEFAULT_RANGE_MINUTE);
|
||||
execMinute = Long.parseLong(DEFAULT_RANGE_MINUTE);
|
||||
}
|
||||
log.info("유량제어 실패 조회 구간: {}분", execMinute);
|
||||
|
||||
ApplicationContext appContext;
|
||||
try {
|
||||
|
||||
@@ -57,19 +57,19 @@ public class ApiUseStatsService
|
||||
|
||||
String dataSql = "";
|
||||
if ("ORG".equals(search.getSearchType())) {
|
||||
dataSql = "SELECT NVL(NVL(B.ORGNAME, D.ORG_NAME),'미분류') AS ORGNAME";
|
||||
dataSql = "SELECT NVL(NVL(B.ORGNAME, D.ORG_NAME),'미분류') AS ORGNAME, '' AS APIDESC";
|
||||
dataSql += getQueryBody(search);
|
||||
dataSql += " GROUP BY NVL(NVL(B.ORGNAME, D.ORG_NAME),'미분류')";
|
||||
dataSql += " ORDER BY ORGNAME";
|
||||
}
|
||||
else if ("API".equals(search.getSearchType())) {
|
||||
dataSql = "SELECT A.API_NAME ";
|
||||
dataSql = "SELECT A.API_NAME, A.EAISVCDESC ";
|
||||
dataSql += getQueryBody(search);
|
||||
dataSql += " GROUP BY A.API_NAME";
|
||||
dataSql += " GROUP BY A.API_NAME, A.EAISVCDESC ";
|
||||
dataSql += " ORDER BY API_NAME";
|
||||
}
|
||||
else if ("DATE".equals(search.getSearchType())) {
|
||||
dataSql = "SELECT TO_CHAR(STAT_TIME,'YYYY-MM-DD') AS STAT_TIME ";
|
||||
dataSql = "SELECT TO_CHAR(STAT_TIME,'YYYY-MM-DD') AS STAT_TIME, '' AS APIDESC ";
|
||||
dataSql += getQueryBody(search);
|
||||
dataSql += " GROUP BY TO_CHAR(STAT_TIME,'YYYY-MM-DD')";
|
||||
dataSql += " ORDER BY STAT_TIME";
|
||||
@@ -85,7 +85,7 @@ public class ApiUseStatsService
|
||||
StringBuilder where = buildNativeWhere(search);
|
||||
|
||||
String totalSql;
|
||||
totalSql = "SELECT '합계' AS ORGNAME ";
|
||||
totalSql = "SELECT '합계' AS ORGNAME, '' AS APIDESC ";
|
||||
totalSql += getQueryBody(search);
|
||||
|
||||
Query totalQuery = entityManager.createNativeQuery(totalSql);
|
||||
@@ -109,6 +109,7 @@ public class ApiUseStatsService
|
||||
+ " FROM ("
|
||||
+ " SELECT A.STAT_TIME "
|
||||
+ " , A.API_NAME"
|
||||
+ " , C.EAISVCDESC"
|
||||
+ " , A.CLIENT_ID "
|
||||
+ " , A.TOTAL_CNT"
|
||||
+ " , A.SUCCESS_CNT"
|
||||
@@ -118,13 +119,13 @@ public class ApiUseStatsService
|
||||
+ " , A.MIN_RESP_TIME"
|
||||
+ " , A.MAX_RESP_TIME"
|
||||
+ " , CASE WHEN API_NAME LIKE '%1' THEN SUBSTR(OUTBOUND_ADAPTER,2,3) ELSE SUBSTR(INBOUND_ADAPTER,2,3) END AS ORG_CODE"
|
||||
+ " FROM API_STATS_DAY A "
|
||||
+ " FROM API_STATS_DAY A LEFT OUTER JOIN TSEAIHE01 C ON A.API_NAME = C.EAISVCNAME "
|
||||
+ " WHERE A.STAT_TIME >= :searchStartDate "
|
||||
+ " AND A.STAT_TIME <= :searchEndDate ";
|
||||
|
||||
|
||||
if (StringUtils.isNotBlank(search.getSearchApiName())) {
|
||||
dataSql += " AND A.API_NAME LIKE :searchApiName ";
|
||||
dataSql += " AND UPPER(A.API_NAME) LIKE :searchApiName ";
|
||||
}
|
||||
|
||||
dataSql += " ) A"
|
||||
@@ -160,15 +161,16 @@ public class ApiUseStatsService
|
||||
private ApiStatsUI toVO(Object[] row) {
|
||||
ApiStatsUI vo = new ApiStatsUI();
|
||||
vo.setOrgName(StringUtils.toString(row[0]));
|
||||
vo.setTotalCnt(StringUtils.toLong(row[1]));
|
||||
vo.setSuccessCnt(StringUtils.toLong(row[2]));
|
||||
vo.setSuccessRate(StringUtils.toDecimal(row[3]).setScale(2, RoundingMode.HALF_UP));
|
||||
vo.setFailRate(StringUtils.toDecimal(row[4]).setScale(2, RoundingMode.HALF_UP));
|
||||
vo.setTimeoutCnt(StringUtils.toLong(row[5]));
|
||||
vo.setSystemErrCnt(StringUtils.toLong(row[6]));
|
||||
vo.setAvgRespTime(StringUtils.toDecimal(row[7]));
|
||||
vo.setMinRespTime(StringUtils.toDecimal(row[8]));
|
||||
vo.setMaxRespTime(StringUtils.toDecimal(row[9]));
|
||||
vo.setApiDesc(StringUtils.toString(row[1]));
|
||||
vo.setTotalCnt(StringUtils.toLong(row[2]));
|
||||
vo.setSuccessCnt(StringUtils.toLong(row[3]));
|
||||
vo.setSuccessRate(StringUtils.toDecimal(row[4]).setScale(2, RoundingMode.HALF_UP));
|
||||
vo.setFailRate(StringUtils.toDecimal(row[5]).setScale(2, RoundingMode.HALF_UP));
|
||||
vo.setTimeoutCnt(StringUtils.toLong(row[6]));
|
||||
vo.setSystemErrCnt(StringUtils.toLong(row[7]));
|
||||
vo.setAvgRespTime(StringUtils.toDecimal(row[8]));
|
||||
vo.setMinRespTime(StringUtils.toDecimal(row[9]));
|
||||
vo.setMaxRespTime(StringUtils.toDecimal(row[10]));
|
||||
return vo;
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ public class UmsService {
|
||||
|
||||
// 스윙챗 알림 데이터
|
||||
SwingDataVO swiDataVO = new SwingDataVO();
|
||||
swiDataVO.setNotiCode("CNO_FEP_APIM_0002"); //0001:긴급, 0002:중요
|
||||
swiDataVO.setNotiCode("CNO_FEP_API_0002"); //0001:긴급, 0002:중요
|
||||
swiDataVO.setNotiTitle("알림");
|
||||
swiDataVO.setNotiContent(messageRequest.getMessage());
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
@@ -146,8 +145,12 @@ public class WebhookService {
|
||||
|
||||
/**
|
||||
* 웹훅 발송 메인 메서드
|
||||
*
|
||||
* <p>{@code @Transactional}을 두지 않는다 - 재시도(최대 retryCount회, Thread.sleep 포함)가
|
||||
* 이 메서드 안에서 동기로 도는데, 메서드 전체를 하나의 트랜잭션으로 감싸면 재시도 도중의
|
||||
* 실패 로그 저장(sendWithRetry 내부)이 커밋되지 않고 메서드가 끝날 때까지 대기하게 되어
|
||||
* "실패 시 즉시 로그부터 남긴다"는 의도가 무의미해진다. save() 호출마다 개별 커밋되도록 둔다.</p>
|
||||
*/
|
||||
@Transactional
|
||||
public void send(WebhookSendRequest req) {
|
||||
|
||||
String targetUrl = req.getTargetUrl();
|
||||
@@ -235,29 +238,50 @@ public class WebhookService {
|
||||
* 재시도 포함 HTTP 발송
|
||||
* - 4xx: 클라이언트 오류이므로 즉시 throw (재시도 불필요)
|
||||
* - 5xx / 네트워크 오류: 최대 RETRY_COUNT회까지 선형 증가 backoff 재시도 (1s → 2s → 3s → 4s → 5s)
|
||||
* - 실패할 때마다 즉시 로그를 저장한다 (최초 실패는 INSERT, 이후 재시도 실패는 같은 row를 UPDATE) -
|
||||
* 재시도 도중 앱이 죽어도 마지막으로 저장된 실패 기록이 남도록 하기 위함
|
||||
*/
|
||||
private ResponseEntity<String> sendWithRetry(String proxyUrl, HttpEntity<String> request, WebhookSendLog sendLog, int retryCount, int retryTime) throws Exception {
|
||||
Exception lastException = null;
|
||||
for (int attempt = 0; attempt <= retryCount; attempt++) {
|
||||
try {
|
||||
if (attempt == 0) {
|
||||
// 배포 반영 확인용: HttpComponentsClientHttpRequestFactory 여야 SSL 우회 RestTemplate 사용 중.
|
||||
// SimpleClientHttpRequestFactory 로 찍히면 기본 new RestTemplate() 이 주입된 것 → PKIX 원인.
|
||||
log.info("[Webhook] POST 시도 - url: {}, requestFactory: {}", proxyUrl,
|
||||
restTemplate.getRequestFactory().getClass().getSimpleName());
|
||||
}
|
||||
if (attempt > 0) {
|
||||
long delayMs = (long) retryTime * attempt;
|
||||
log.info("[Webhook] 재시도 {}/{} - url: {}, delay: {}ms", attempt, retryCount, proxyUrl, delayMs);
|
||||
sendLog.setRetryCount(attempt);
|
||||
Thread.sleep(delayMs);
|
||||
}
|
||||
return restTemplate.postForEntity(proxyUrl, request, String.class);
|
||||
} catch (HttpClientErrorException e) {
|
||||
//throw e; // 4xx는 재시도 불필요
|
||||
lastException = e; //TODO: 재시도 테스트
|
||||
lastException = e; //TODO: 재시도 테스트
|
||||
recordAttemptFailure(sendLog, attempt, e.getStatusCode().value(), e.getResponseBodyAsString(), e.getMessage());
|
||||
} catch (Exception e) {
|
||||
lastException = e;
|
||||
log.warn("[Webhook] 발송 실패 (attempt {}/{}) - url: {}, error: {}", attempt, retryCount, proxyUrl, e.getMessage());
|
||||
recordAttemptFailure(sendLog, attempt, null, null, e.getMessage());
|
||||
}
|
||||
}
|
||||
throw lastException;
|
||||
}
|
||||
|
||||
// 실패한 시도 하나를 즉시 저장한다. sendLog에 id가 없으면(최초 실패) INSERT, 있으면(재시도 실패) 같은 row를 UPDATE한다.
|
||||
private void recordAttemptFailure(WebhookSendLog sendLog, int attempt, Integer statusCode, String responseBody, String errorMessage) {
|
||||
sendLog.setRetryCount(attempt);
|
||||
sendLog.setSuccess(false);
|
||||
sendLog.setErrorMessage(errorMessage);
|
||||
if (statusCode != null) {
|
||||
sendLog.setStatusCode(statusCode);
|
||||
sendLog.setResponseBody(responseBody);
|
||||
}
|
||||
sendLogRepository.save(sendLog);
|
||||
}
|
||||
|
||||
/**
|
||||
* HMAC-SHA256 서명 생성
|
||||
* Java 17 미만은 HexFormat 미지원이므로 직접 변환
|
||||
|
||||
@@ -1,38 +1,62 @@
|
||||
package com.eactive.eai.rms.ext.user.sync;
|
||||
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.conn.ssl.NoopHostnameVerifier;
|
||||
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.http.conn.ssl.TrustAllStrategy;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.ssl.SSLContextBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class RestTemplateConfiguration {
|
||||
|
||||
|
||||
@Bean
|
||||
public HttpClient httpClient() {
|
||||
|
||||
HttpClient httpClient =
|
||||
public HttpClient httpClient() throws Exception {
|
||||
|
||||
// 사내망 내부 CA(자체 발급) 인증서 체인을 JVM cacerts가 신뢰하지 못해 PKIX 오류가 나는 문제의
|
||||
// 임시 우회. 인증서 체인/호스트명 검증을 모두 끄므로 MITM에 취약해진다 - 내부망 대상으로만 쓰고,
|
||||
// 가능하면 해당 CA를 JVM 트러스트스토어에 등록하는 방식으로 대체할 것.
|
||||
SSLContext sslContext = SSLContextBuilder.create()
|
||||
.loadTrustMaterial(TrustAllStrategy.INSTANCE)
|
||||
.build();
|
||||
|
||||
SSLConnectionSocketFactory sslSocketFactory =
|
||||
new SSLConnectionSocketFactory(sslContext, NoopHostnameVerifier.INSTANCE);
|
||||
|
||||
HttpClient httpClient =
|
||||
HttpClientBuilder.create()
|
||||
.setSSLSocketFactory(sslSocketFactory)
|
||||
.setMaxConnTotal(50)
|
||||
.setMaxConnPerRoute(20)
|
||||
.build();
|
||||
|
||||
|
||||
// 배포 반영 확인용: 이 줄이 기동 로그에 없으면 수정 전 클래스가 떠 있는 것.
|
||||
log.info("[RestTemplateConfiguration] httpClient 생성: SSL 인증서 체인/호스트명 검증 비활성화(TrustAllStrategy+NoopHostnameVerifier) 적용");
|
||||
|
||||
return httpClient;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public HttpComponentsClientHttpRequestFactory factory(HttpClient httpClient) {
|
||||
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
|
||||
factory.setHttpClient(httpClient);
|
||||
return factory;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(HttpComponentsClientHttpRequestFactory factory) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.setRequestFactory(factory);
|
||||
log.info("[RestTemplateConfiguration] RestTemplate 빈 생성: requestFactory={}", factory.getClass().getSimpleName());
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package com.eactive.eai.rms.onl.loader.controller;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URLDecoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@@ -1451,77 +1451,92 @@ public class LoaderController implements InterceptorSkipController {
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@RequestMapping( params ={"cmd=interface","control=downloadfull"})
|
||||
public ModelAndView interfaceDownLoadFully(String serviceType, String interfaceId) throws Exception {
|
||||
public ModelAndView interfaceDownLoadFully(String serviceType, String interfaceId) {
|
||||
DataSourceType dt = DataSourceTypeManager.getDataSourceType(serviceType);
|
||||
DataSourceContextHolder.setDataSourceType(dt);
|
||||
|
||||
// 1. interface 데이터 다운로드
|
||||
InterfaceDeployPack interfaceDeployPack = new InterfaceDeployPack();
|
||||
String json = "";
|
||||
try {
|
||||
// 1. interface 데이터 다운로드
|
||||
InterfaceDeployPack interfaceDeployPack = new InterfaceDeployPack();
|
||||
|
||||
EAIMessageDeploy eaiMessageDeploy = interfaceDeployService.selectDeploy(interfaceId);
|
||||
eaiMessageDeploy.setEailastamndyms(null);
|
||||
EAIMessageDeploy eaiMessageDeploy = interfaceDeployService.selectDeploy(interfaceId);
|
||||
eaiMessageDeploy.setEailastamndyms(null);
|
||||
|
||||
interfaceDeployPack.setEaiMessageDeploy(eaiMessageDeploy);
|
||||
interfaceDeployPack.setEaiMessageDeploy(eaiMessageDeploy);
|
||||
|
||||
for(StandardMessageInfoDeploy standardMessageInfoDeploy : eaiMessageDeploy.getStandardMessageInfoDeploys()){
|
||||
standardMessageInfoDeploy.setEailastamndyms(null);
|
||||
}
|
||||
for(StandardMessageInfoDeploy standardMessageInfoDeploy : eaiMessageDeploy.getStandardMessageInfoDeploys()){
|
||||
standardMessageInfoDeploy.setEailastamndyms(null);
|
||||
}
|
||||
|
||||
for (ServiceMessageDeploy serviceMessageDeploy : eaiMessageDeploy.getServiceMessages()){
|
||||
String[] transformNames = {serviceMessageDeploy.getChngmsgidname(), serviceMessageDeploy.getBascrspnschngmsgidname()};
|
||||
// 2. Layout 데이터 생성
|
||||
for(String transformName: transformNames){
|
||||
if(StringUtils.isBlank(transformName)){
|
||||
continue;
|
||||
}
|
||||
|
||||
for(TransformSourceResultUI transformSourceResultUI : transform2Service.selectTransformSourceResult(transformName)){
|
||||
String loutName = transformSourceResultUI.getLoutName();
|
||||
if(StringUtils.isBlank(loutName)){
|
||||
for (ServiceMessageDeploy serviceMessageDeploy : eaiMessageDeploy.getServiceMessages()){
|
||||
String[] transformNames = {serviceMessageDeploy.getChngmsgidname(), serviceMessageDeploy.getBascrspnschngmsgidname()};
|
||||
// 2. Layout 데이터 생성
|
||||
for(String transformName: transformNames){
|
||||
if(StringUtils.isBlank(transformName)){
|
||||
continue;
|
||||
}
|
||||
LayoutDeploy layoutDeploy = layoutDeployService.selectDeploy(loutName);
|
||||
layoutDeploy.setLastamndhms(null);
|
||||
interfaceDeployPack.getLayoutDeployList().add(layoutDeploy);
|
||||
|
||||
for(TransformSourceResultUI transformSourceResultUI : transform2Service.selectTransformSourceResult(transformName)){
|
||||
String loutName = transformSourceResultUI.getLoutName();
|
||||
if(StringUtils.isBlank(loutName)){
|
||||
continue;
|
||||
}
|
||||
LayoutDeploy layoutDeploy = layoutDeployService.selectDeploy(loutName);
|
||||
layoutDeploy.setLastamndhms(null);
|
||||
interfaceDeployPack.getLayoutDeployList().add(layoutDeploy);
|
||||
}
|
||||
|
||||
// 3. Transform 데이터 생성
|
||||
TransformDeploy transformDeploy = transformDeployService.selectDeploy(transformName);
|
||||
transformDeploy.setLastamndhms(null);
|
||||
interfaceDeployPack.getTransformDeployList().add(transformDeploy);
|
||||
}
|
||||
|
||||
// 3. Transform 데이터 생성
|
||||
TransformDeploy transformDeploy = transformDeployService.selectDeploy(transformName);
|
||||
transformDeploy.setLastamndhms(null);
|
||||
interfaceDeployPack.getTransformDeployList().add(transformDeploy);
|
||||
}
|
||||
|
||||
// 4. API 스펙 정보(ptl_api_spec_info) 추가 (감사(audit) 컬럼은 제외)
|
||||
Optional<ApiSpecInfo> optSpecInfo = apiSpecInfoService.findById(interfaceId);
|
||||
if (optSpecInfo.isPresent()) {
|
||||
ApiSpecInfoUI specInfo = apiSpecUIMapper.mapToUI(optSpecInfo.get());
|
||||
specInfo.setCreatedBy(null);
|
||||
specInfo.setCreatedDate(null);
|
||||
specInfo.setLastModifiedBy(null);
|
||||
specInfo.setLastModifiedDate(null);
|
||||
interfaceDeployPack.setSpecInfo(specInfo);
|
||||
}
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter();
|
||||
String bizCode = eaiMessageDeploy.getEaibzwkdstcd();
|
||||
String ioMapPath = monitoringContext.getStringProperty(MonitoringContext.IOMAP_DOWNLOAD_PATH);
|
||||
String fileDir = FilenameUtils.concat(ioMapPath, bizCode);
|
||||
String fileFullPath = FilenameUtils.concat(fileDir, interfaceId+".json");
|
||||
|
||||
FileWriteUtil.makeDirWithGroupPermission(fileDir);
|
||||
File file = new File(fileFullPath);
|
||||
json = writer.writeValueAsString(interfaceDeployPack);
|
||||
FileUtils.writeStringToFile(file, json, StandardCharsets.UTF_8);
|
||||
|
||||
// TSEAITR10 배포 이력 저장 (SERVICENAME=eCams, COMMAND=downloadfull, LOUTNAME=interfaceId, RECVDATA=json)
|
||||
loaderService.insertDeploySyncLog(dt, "downloadfull", interfaceId, json);
|
||||
|
||||
Map<String,String> result = new HashMap<>();
|
||||
result.put("status", "success");
|
||||
result.put("message", fileFullPath+" write done.");
|
||||
|
||||
return new ModelAndView(resultView, "result", result);
|
||||
} catch (Exception e) {
|
||||
logger.error("interface downloadfull error - interfaceId=" + interfaceId, e);
|
||||
loaderService.insertDeployFailLog(dt, "downloadfull", interfaceId, json, e.toString());
|
||||
|
||||
Map<String,String> result = new HashMap<>();
|
||||
result.put("status", "fail");
|
||||
result.put("message", e.toString());
|
||||
|
||||
return new ModelAndView(resultView, "result", result);
|
||||
}
|
||||
|
||||
// 4. API 스펙 정보(ptl_api_spec_info) 추가 (감사(audit) 컬럼은 제외)
|
||||
Optional<ApiSpecInfo> optSpecInfo = apiSpecInfoService.findById(interfaceId);
|
||||
if (optSpecInfo.isPresent()) {
|
||||
ApiSpecInfoUI specInfo = apiSpecUIMapper.mapToUI(optSpecInfo.get());
|
||||
specInfo.setCreatedBy(null);
|
||||
specInfo.setCreatedDate(null);
|
||||
specInfo.setLastModifiedBy(null);
|
||||
specInfo.setLastModifiedDate(null);
|
||||
interfaceDeployPack.setSpecInfo(specInfo);
|
||||
}
|
||||
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
|
||||
ObjectWriter writer = objectMapper.writerWithDefaultPrettyPrinter();
|
||||
String bizCode = eaiMessageDeploy.getEaibzwkdstcd();
|
||||
String ioMapPath = monitoringContext.getStringProperty(MonitoringContext.IOMAP_DOWNLOAD_PATH);
|
||||
String fileDir = FilenameUtils.concat(ioMapPath, bizCode);
|
||||
String fileFullPath = FilenameUtils.concat(fileDir, interfaceId+".json");
|
||||
|
||||
FileWriteUtil.makeDirWithGroupPermission(fileDir);
|
||||
File file = new File(fileFullPath);
|
||||
writer.writeValue(file, interfaceDeployPack);
|
||||
|
||||
Map<String,String> result = new HashMap<>();
|
||||
String status = "success";
|
||||
result.put("status", status);
|
||||
result.put("message", fileFullPath+" write done.");
|
||||
|
||||
return new ModelAndView(resultView, "result", result);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1533,57 +1548,73 @@ public class LoaderController implements InterceptorSkipController {
|
||||
* @throws Exception
|
||||
*/
|
||||
@RequestMapping( params ={"cmd=interface","control=uploadfull"})
|
||||
public ModelAndView interfaceLoadFully(String serviceType, String filePath) throws Exception {
|
||||
public ModelAndView interfaceLoadFully(String serviceType, String filePath) {
|
||||
DataSourceType dt = DataSourceTypeManager.getDataSourceType(serviceType);
|
||||
DataSourceContextHolder.setDataSourceType(dt);
|
||||
|
||||
String ioMapPath = monitoringContext.getStringProperty(MonitoringContext.IOMAP_UPLOAD_PATH);
|
||||
String fileFullPath ;
|
||||
if(StringUtils.isBlank(ioMapPath)) {
|
||||
fileFullPath = filePath;
|
||||
} else {
|
||||
fileFullPath = FilenameUtils.concat(ioMapPath, filePath);
|
||||
}
|
||||
|
||||
File file = new File(fileFullPath);
|
||||
InputStream inputStream = new FileInputStream(file);
|
||||
// ObjectMapper 생성 및 설정
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
InterfaceDeployPack interfaceDeployPack = objectMapper.readValue(inputStream, InterfaceDeployPack.class);
|
||||
|
||||
EAIMessageDeploy eaiMessageDeploy = interfaceDeployPack.getEaiMessageDeploy();
|
||||
|
||||
interfaceDeployService.saveDeploy(eaiMessageDeploy);
|
||||
agentUtilService.broadcast(new CommonCommand("com.ext.eai.agent.stdmessage.ReloadSTDMessageCommand", "ALL"));
|
||||
agentUtilService.broadcast(new CommonCommand("com.eactive.eai.agent.eaimessage.ReloadEAIMessageCommand", eaiMessageDeploy.getEaisvcname()));
|
||||
|
||||
for(LayoutDeploy layoutDeploy: interfaceDeployPack.getLayoutDeployList()){
|
||||
layoutDeployService.saveDeploy(layoutDeploy);
|
||||
agentUtilService.broadcast(new CommonCommand( "com.eactive.eai.agent.transformer.ReloadLayoutCommand", layoutDeploy.getLoutname()));
|
||||
}
|
||||
|
||||
for(TransformDeploy transformDeploy : interfaceDeployPack.getTransformDeployList()){
|
||||
transformDeployService.saveDeploy(transformDeploy);
|
||||
agentUtilService.broadcast(new CommonCommand( "com.eactive.eai.agent.transformer.ReloadTransformCommand", transformDeploy.getCnvsnname()));
|
||||
}
|
||||
|
||||
ApiSpecInfoUI specInfoUI = interfaceDeployPack.getSpecInfo();
|
||||
if (specInfoUI != null && StringUtils.isNotBlank(specInfoUI.getApiId())) {
|
||||
ApiSpecInfo specInfo = apiSpecUIMapper.mapToEntity(specInfoUI);
|
||||
if (apiSpecInfoService.findById(specInfo.getApiId()).isPresent()) {
|
||||
apiSpecInfoService.updateById(specInfo.getApiId(), specInfo);
|
||||
String json = "";
|
||||
String loutName = filePath;
|
||||
try {
|
||||
String ioMapPath = monitoringContext.getStringProperty(MonitoringContext.IOMAP_UPLOAD_PATH);
|
||||
String fileFullPath ;
|
||||
if(StringUtils.isBlank(ioMapPath)) {
|
||||
fileFullPath = filePath;
|
||||
} else {
|
||||
apiSpecInfoService.create(specInfo);
|
||||
fileFullPath = FilenameUtils.concat(ioMapPath, filePath);
|
||||
}
|
||||
|
||||
File file = new File(fileFullPath);
|
||||
json = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
|
||||
// ObjectMapper 생성 및 설정
|
||||
ObjectMapper objectMapper = new ObjectMapper();
|
||||
objectMapper.registerModule(new JavaTimeModule());
|
||||
InterfaceDeployPack interfaceDeployPack = objectMapper.readValue(json, InterfaceDeployPack.class);
|
||||
|
||||
EAIMessageDeploy eaiMessageDeploy = interfaceDeployPack.getEaiMessageDeploy();
|
||||
loutName = eaiMessageDeploy.getEaisvcname();
|
||||
|
||||
interfaceDeployService.saveDeploy(eaiMessageDeploy);
|
||||
agentUtilService.broadcast(new CommonCommand("com.ext.eai.agent.stdmessage.ReloadSTDMessageCommand", "ALL"));
|
||||
agentUtilService.broadcast(new CommonCommand("com.eactive.eai.agent.eaimessage.ReloadEAIMessageCommand", eaiMessageDeploy.getEaisvcname()));
|
||||
|
||||
for(LayoutDeploy layoutDeploy: interfaceDeployPack.getLayoutDeployList()){
|
||||
layoutDeployService.saveDeploy(layoutDeploy);
|
||||
agentUtilService.broadcast(new CommonCommand( "com.eactive.eai.agent.transformer.ReloadLayoutCommand", layoutDeploy.getLoutname()));
|
||||
}
|
||||
|
||||
for(TransformDeploy transformDeploy : interfaceDeployPack.getTransformDeployList()){
|
||||
transformDeployService.saveDeploy(transformDeploy);
|
||||
agentUtilService.broadcast(new CommonCommand( "com.eactive.eai.agent.transformer.ReloadTransformCommand", transformDeploy.getCnvsnname()));
|
||||
}
|
||||
|
||||
ApiSpecInfoUI specInfoUI = interfaceDeployPack.getSpecInfo();
|
||||
if (specInfoUI != null && StringUtils.isNotBlank(specInfoUI.getApiId())) {
|
||||
ApiSpecInfo specInfo = apiSpecUIMapper.mapToEntity(specInfoUI);
|
||||
if (apiSpecInfoService.findById(specInfo.getApiId()).isPresent()) {
|
||||
apiSpecInfoService.updateById(specInfo.getApiId(), specInfo);
|
||||
} else {
|
||||
apiSpecInfoService.create(specInfo);
|
||||
}
|
||||
}
|
||||
|
||||
// TSEAITR10 배포 이력 저장 (SERVICENAME=eCams, COMMAND=uploadfull, LOUTNAME=eaisvcname, RECVDATA=json)
|
||||
loaderService.insertDeploySyncLog(dt, "uploadfull", loutName, json);
|
||||
|
||||
Map<String,String> result = new HashMap<String,String>();
|
||||
result.put("status", "success");
|
||||
result.put("message", fileFullPath+" deploy done.");
|
||||
|
||||
return new ModelAndView(resultView, "result", result);
|
||||
} catch (Exception e) {
|
||||
logger.error("interface uploadfull error - filePath=" + filePath, e);
|
||||
loaderService.insertDeployFailLog(dt, "uploadfull", loutName, json, e.toString());
|
||||
|
||||
Map<String,String> result = new HashMap<String,String>();
|
||||
result.put("status", "fail");
|
||||
result.put("message", e.toString());
|
||||
|
||||
return new ModelAndView(resultView, "result", result);
|
||||
}
|
||||
|
||||
Map<String,String> result = new HashMap<String,String>();
|
||||
String status = "success";
|
||||
result.put("status", status);
|
||||
result.put("message", fileFullPath+" deploy done.");
|
||||
|
||||
return new ModelAndView(resultView, "result", result);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,4 +41,9 @@ public interface LoaderDao {
|
||||
public List<LinkedHashMap> selectTableDataForListValue( DataSourceType dataSourceType, String tableName, String key1, List<String> param1 ) ;
|
||||
|
||||
public List<LinkedHashMap> selectSnaAdpApList( DataSourceType dataSourceType, String param1 ) ;
|
||||
|
||||
/**
|
||||
* TSEAITR10(배포/동기화 이력)에 로그 1건을 저장한다.
|
||||
*/
|
||||
public int insertSyncLog( DataSourceType dt, HashMap<String, String> param ) ;
|
||||
}
|
||||
|
||||
@@ -189,10 +189,15 @@ public class LoaderDaoImpl extends SqlMapClientTemplateDao implements LoaderDao
|
||||
// }
|
||||
// }.execute();
|
||||
}
|
||||
public int insertSyncLog( DataSourceType dt, HashMap<String, String> param ) {
|
||||
param.put("schemaId", dt.getSchema());
|
||||
return this.template.update("Layout.insertLayoutSyncLog", param);
|
||||
}
|
||||
|
||||
public List<LinkedHashMap> selectSnaAdpApList( DataSourceType dataSourceType, String param1 ) {
|
||||
final HashMap param = new HashMap();
|
||||
param.put("param1", param1);
|
||||
|
||||
param.put("param1", param1);
|
||||
|
||||
return template.queryForList("Loader.selectSnaAdpApList", param);
|
||||
|
||||
// return new SpecifiedDataSourceExecutor<List<LinkedHashMap>>(
|
||||
|
||||
@@ -157,5 +157,15 @@ public interface TransactionLoaderService{
|
||||
|
||||
public HashMap syncResult(Command command ,String fileName ) throws Exception;
|
||||
|
||||
public void appendToListfile(String bizCode, String interfaceId) throws Exception ;
|
||||
public void appendToListfile(String bizCode, String interfaceId) throws Exception ;
|
||||
|
||||
/**
|
||||
* downloadfull / uploadfull 성공 시 TSEAITR10 에 배포 이력을 저장한다. (PRCSSRSLT=S)
|
||||
*/
|
||||
public void insertDeploySyncLog(DataSourceType dt, String command, String interfaceId, String recvData) ;
|
||||
|
||||
/**
|
||||
* downloadfull / uploadfull 실패 시 TSEAITR10 에 실패 이력을 저장한다. (PRCSSRSLT=F, PRCSSRSLTCMNT=errMsg)
|
||||
*/
|
||||
public void insertDeployFailLog(DataSourceType dt, String command, String interfaceId, String recvData, String errMsg) ;
|
||||
}
|
||||
+30
@@ -2,6 +2,7 @@ package com.eactive.eai.rms.onl.loader.service;
|
||||
|
||||
import com.eactive.eai.agent.command.Command;
|
||||
import com.eactive.eai.agent.command.CommonCommand;
|
||||
import com.eactive.eai.common.util.UUIDGenerator;
|
||||
import com.eactive.eai.rms.common.base.BaseService;
|
||||
import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
import com.eactive.eai.rms.common.converter.ElinkObjectMapper;
|
||||
@@ -1483,4 +1484,33 @@ public class TransactionLoaderServiceImpl extends BaseService implements Transac
|
||||
String targetLine = bizCode+"|"+interfaceId+System.lineSeparator();
|
||||
org.apache.commons.io.FileUtils.writeStringToFile(listFile, targetLine, Charset.defaultCharset(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertDeploySyncLog(DataSourceType dt, String command, String interfaceId, String recvData) {
|
||||
insertDeployLog(dt, command, interfaceId, recvData, "S", "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void insertDeployFailLog(DataSourceType dt, String command, String interfaceId, String recvData, String errMsg) {
|
||||
insertDeployLog(dt, command, interfaceId, recvData, "F", errMsg);
|
||||
}
|
||||
|
||||
private void insertDeployLog(DataSourceType dt, String command, String interfaceId, String recvData,
|
||||
String prcssRslt, String prcssRsltCmnt) {
|
||||
try {
|
||||
HashMap<String, String> param = new HashMap<String, String>();
|
||||
param.put("logPrcssSeqno", UUIDGenerator.getUUID());
|
||||
param.put("serviceName", "InterfaceDeploy");
|
||||
param.put("command", command);
|
||||
param.put("loutName", interfaceId);
|
||||
param.put("recvData", recvData == null ? "" : recvData);
|
||||
param.put("recvAmndHMS", DateUtil.getDateTime("yyyyMMddHHmmssSS").substring(0, 16));
|
||||
param.put("prcssRslt", prcssRslt);
|
||||
param.put("prcssRsltCmnt", StringUtils.left(prcssRsltCmnt, 4000)); // PRCSSRSLTCMNT 길이 보호
|
||||
dao.insertSyncLog(dt, param);
|
||||
} catch (Exception e) {
|
||||
// 이력 저장 실패가 download/upload 본기능을 중단시키지 않도록 한다.
|
||||
logger.error("insertDeployLog error (command=" + command + ", interfaceId=" + interfaceId + ")", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -7,6 +7,12 @@ public class LayoutSyncHistoryUISearch {
|
||||
|
||||
private String searchLoutName;
|
||||
|
||||
/* 서비스명 (부분일치) */
|
||||
private String searchServiceName;
|
||||
|
||||
/* 커맨드 (부분일치) */
|
||||
private String searchCommand;
|
||||
|
||||
/* 연동시간 기간 검색 (yyyyMMdd, 8자리) */
|
||||
private String searchStartDate;
|
||||
private String searchEndDate;
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.io.IOException;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -18,7 +20,10 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.vo.GridResponse;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricJpaDAO;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsDay;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsDayService;
|
||||
import com.eactive.ext.kjb.statistics.mapping.ApiStatsUIMapper;
|
||||
@@ -38,6 +43,7 @@ public class ApiStatsDayController {
|
||||
private final ApiStatsDayService service;
|
||||
private final ApiStatsUIMapper mapper;
|
||||
private final ApiStatsExcelExportService excelExportService;
|
||||
private final ObpGwMetricJpaDAO apiNameDao;
|
||||
|
||||
@GetMapping(value = "/onl/kjb/statistics/apiStatsDayMan.view")
|
||||
public String view() {
|
||||
@@ -66,9 +72,38 @@ public class ApiStatsDayController {
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsDayMan.json", params = "cmd=LIST_SUMMARY")
|
||||
public ResponseEntity<GridResponse<ApiStatsUI>> selectSummaryList(ApiStatsSearch search, Pageable pageable) {
|
||||
Page<ApiStatsUI> page = service.selectSummaryList(search, pageable);
|
||||
fillApiDesc(page.getContent());
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 요약 통계 행의 apiName(=API ID)으로 TSEAIHE01 을 조회하여 API 명(EAISVCDESC)을 채운다.
|
||||
* 매칭되는 항목이 없으면 공란으로 둔다.
|
||||
*/
|
||||
private void fillApiDesc(List<ApiStatsUI> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> apiIds = rows.stream()
|
||||
.map(ApiStatsUI::getApiName)
|
||||
.filter(id -> id != null && !id.isEmpty())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (apiIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// API_STATS_DAY 와 동일한 APIGW 스키마에서 조회
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||
|
||||
Map<String, String> nameMap = apiNameDao.selectApiNames(apiIds);
|
||||
for (ApiStatsUI row : rows) {
|
||||
row.setApiDesc(nameMap.get(row.getApiName()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsDayMan.json", params = "cmd=EXCEL_EXPORT")
|
||||
public void exportToExcel(ApiStatsSearch search, HttpServletResponse response) throws IOException {
|
||||
log.info("Excel export started - search: {}", search);
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -18,7 +20,10 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.vo.GridResponse;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricJpaDAO;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsHour;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsHourService;
|
||||
import com.eactive.ext.kjb.statistics.mapping.ApiStatsUIMapper;
|
||||
@@ -38,6 +43,7 @@ public class ApiStatsHourController {
|
||||
private final ApiStatsHourService service;
|
||||
private final ApiStatsUIMapper mapper;
|
||||
private final ApiStatsExcelExportService excelExportService;
|
||||
private final ObpGwMetricJpaDAO apiNameDao;
|
||||
|
||||
@GetMapping(value = "/onl/kjb/statistics/apiStatsHourMan.view")
|
||||
public String view() {
|
||||
@@ -66,9 +72,38 @@ public class ApiStatsHourController {
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsHourMan.json", params = "cmd=LIST_SUMMARY")
|
||||
public ResponseEntity<GridResponse<ApiStatsUI>> selectSummaryList(ApiStatsSearch search, Pageable pageable) {
|
||||
Page<ApiStatsUI> page = service.selectSummaryList(search, pageable);
|
||||
fillApiDesc(page.getContent());
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 요약 통계 행의 apiName(=API ID)으로 TSEAIHE01 을 조회하여 API 명(EAISVCDESC)을 채운다.
|
||||
* 매칭되는 항목이 없으면 공란으로 둔다.
|
||||
*/
|
||||
private void fillApiDesc(List<ApiStatsUI> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> apiIds = rows.stream()
|
||||
.map(ApiStatsUI::getApiName)
|
||||
.filter(id -> id != null && !id.isEmpty())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (apiIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// API_STATS_HOUR 와 동일한 APIGW 스키마에서 조회
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||
|
||||
Map<String, String> nameMap = apiNameDao.selectApiNames(apiIds);
|
||||
for (ApiStatsUI row : rows) {
|
||||
row.setApiDesc(nameMap.get(row.getApiName()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsHourMan.json", params = "cmd=EXCEL_EXPORT")
|
||||
public void exportToExcel(ApiStatsSearch search, HttpServletResponse response) throws IOException {
|
||||
log.info("Excel export started - search: {}", search);
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.io.IOException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -18,7 +20,10 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.vo.GridResponse;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricJpaDAO;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsMinute;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsMinuteService;
|
||||
import com.eactive.ext.kjb.statistics.mapping.ApiStatsUIMapper;
|
||||
@@ -38,6 +43,7 @@ public class ApiStatsMinuteController {
|
||||
private final ApiStatsMinuteService service;
|
||||
private final ApiStatsUIMapper mapper;
|
||||
private final ApiStatsExcelExportService excelExportService;
|
||||
private final ObpGwMetricJpaDAO apiNameDao;
|
||||
|
||||
@GetMapping(value = "/onl/kjb/statistics/apiStatsMinuteMan.view")
|
||||
public String view() {
|
||||
@@ -66,9 +72,38 @@ public class ApiStatsMinuteController {
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsMinuteMan.json", params = "cmd=LIST_SUMMARY")
|
||||
public ResponseEntity<GridResponse<ApiStatsUI>> selectSummaryList(ApiStatsSearch search, Pageable pageable) {
|
||||
Page<ApiStatsUI> page = service.selectSummaryList(search, pageable);
|
||||
fillApiDesc(page.getContent());
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 요약 통계 행의 apiName(=API ID)으로 TSEAIHE01 을 조회하여 API 명(EAISVCDESC)을 채운다.
|
||||
* 매칭되는 항목이 없으면 공란으로 둔다.
|
||||
*/
|
||||
private void fillApiDesc(List<ApiStatsUI> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> apiIds = rows.stream()
|
||||
.map(ApiStatsUI::getApiName)
|
||||
.filter(id -> id != null && !id.isEmpty())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (apiIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// API_STATS_MINUTE 와 동일한 APIGW 스키마에서 조회
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||
|
||||
Map<String, String> nameMap = apiNameDao.selectApiNames(apiIds);
|
||||
for (ApiStatsUI row : rows) {
|
||||
row.setApiDesc(nameMap.get(row.getApiName()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsMinuteMan.json", params = "cmd=EXCEL_EXPORT")
|
||||
public void exportToExcel(ApiStatsSearch search, HttpServletResponse response) throws IOException {
|
||||
log.info("Excel export started - search: {}", search);
|
||||
|
||||
@@ -4,6 +4,8 @@ import java.io.IOException;
|
||||
import java.time.YearMonth;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -18,7 +20,10 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.vo.GridResponse;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricJpaDAO;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsMonth;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsMonthService;
|
||||
import com.eactive.ext.kjb.statistics.mapping.ApiStatsUIMapper;
|
||||
@@ -38,6 +43,7 @@ public class ApiStatsMonthController {
|
||||
private final ApiStatsMonthService service;
|
||||
private final ApiStatsUIMapper mapper;
|
||||
private final ApiStatsExcelExportService excelExportService;
|
||||
private final ObpGwMetricJpaDAO apiNameDao;
|
||||
|
||||
@GetMapping(value = "/onl/kjb/statistics/apiStatsMonthMan.view")
|
||||
public String view() {
|
||||
@@ -66,9 +72,38 @@ public class ApiStatsMonthController {
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsMonthMan.json", params = "cmd=LIST_SUMMARY")
|
||||
public ResponseEntity<GridResponse<ApiStatsUI>> selectSummaryList(ApiStatsSearch search, Pageable pageable) {
|
||||
Page<ApiStatsUI> page = service.selectSummaryList(search, pageable);
|
||||
fillApiDesc(page.getContent());
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 요약 통계 행의 apiName(=API ID)으로 TSEAIHE01 을 조회하여 API 명(EAISVCDESC)을 채운다.
|
||||
* 매칭되는 항목이 없으면 공란으로 둔다.
|
||||
*/
|
||||
private void fillApiDesc(List<ApiStatsUI> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> apiIds = rows.stream()
|
||||
.map(ApiStatsUI::getApiName)
|
||||
.filter(id -> id != null && !id.isEmpty())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (apiIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// API_STATS_MONTH 와 동일한 APIGW 스키마에서 조회
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||
|
||||
Map<String, String> nameMap = apiNameDao.selectApiNames(apiIds);
|
||||
for (ApiStatsUI row : rows) {
|
||||
row.setApiDesc(nameMap.get(row.getApiName()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsMonthMan.json", params = "cmd=EXCEL_EXPORT")
|
||||
public void exportToExcel(ApiStatsSearch search, HttpServletResponse response) throws IOException {
|
||||
log.info("Excel export started - search: {}", search);
|
||||
|
||||
@@ -3,6 +3,8 @@ package com.eactive.ext.kjb.statistics;
|
||||
import java.io.IOException;
|
||||
import java.time.Year;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -17,7 +19,10 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
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.vo.GridResponse;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricJpaDAO;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsYear;
|
||||
import com.eactive.eai.rms.data.entity.onl.kjb.statistics.ApiStatsYearService;
|
||||
import com.eactive.ext.kjb.statistics.mapping.ApiStatsUIMapper;
|
||||
@@ -37,6 +42,7 @@ public class ApiStatsYearController {
|
||||
private final ApiStatsYearService service;
|
||||
private final ApiStatsUIMapper mapper;
|
||||
private final ApiStatsExcelExportService excelExportService;
|
||||
private final ObpGwMetricJpaDAO apiNameDao;
|
||||
|
||||
@GetMapping(value = "/onl/kjb/statistics/apiStatsYearMan.view")
|
||||
public String view() {
|
||||
@@ -65,9 +71,38 @@ public class ApiStatsYearController {
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsYearMan.json", params = "cmd=LIST_SUMMARY")
|
||||
public ResponseEntity<GridResponse<ApiStatsUI>> selectSummaryList(ApiStatsSearch search, Pageable pageable) {
|
||||
Page<ApiStatsUI> page = service.selectSummaryList(search, pageable);
|
||||
fillApiDesc(page.getContent());
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
/**
|
||||
* 요약 통계 행의 apiName(=API ID)으로 TSEAIHE01 을 조회하여 API 명(EAISVCDESC)을 채운다.
|
||||
* 매칭되는 항목이 없으면 공란으로 둔다.
|
||||
*/
|
||||
private void fillApiDesc(List<ApiStatsUI> rows) {
|
||||
if (rows == null || rows.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Set<String> apiIds = rows.stream()
|
||||
.map(ApiStatsUI::getApiName)
|
||||
.filter(id -> id != null && !id.isEmpty())
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
if (apiIds.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// API_STATS_YEAR 와 동일한 APIGW 스키마에서 조회
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||
|
||||
Map<String, String> nameMap = apiNameDao.selectApiNames(apiIds);
|
||||
for (ApiStatsUI row : rows) {
|
||||
row.setApiDesc(nameMap.get(row.getApiName()));
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/kjb/statistics/apiStatsYearMan.json", params = "cmd=EXCEL_EXPORT")
|
||||
public void exportToExcel(ApiStatsSearch search, HttpServletResponse response) throws IOException {
|
||||
log.info("Excel export started - search: {}", search);
|
||||
|
||||
@@ -11,6 +11,7 @@ import lombok.Data;
|
||||
public class ApiStatsUI {
|
||||
private String statTime;
|
||||
private String apiName;
|
||||
private String apiDesc;
|
||||
private String gwInstanceId;
|
||||
private String bizDivCode;
|
||||
private String clientId;
|
||||
|
||||
Reference in New Issue
Block a user