Merge remote-tracking branch 'origin/master'
# Conflicts: # src/main/java/com/eactive/eai/rms/onl/apim/approval/PortalApprovalManController.java
This commit is contained in:
@@ -254,6 +254,13 @@ public interface MonitoringContext {
|
||||
|
||||
// 이중 로그인 허용여부
|
||||
public static final String RMS_DUAL_LOGIN_ENABLED = "rms.DUAL_LOGIN_ENABLED";
|
||||
|
||||
// 자동 로그아웃 타임아웃 (단위: 분, 기본값: 10)
|
||||
public static final String RMS_AUTO_LOGOUT_TIMEOUT = "rms.auto.logout.timeout";
|
||||
|
||||
// 웹훅 재전송 설정
|
||||
public static final String API_WEBHOOK_RETRY_COUNT = "api.webhook.retry_count";
|
||||
public static final String API_WEBHOOK_RETRY_TIME = "api.webhook.retry_time";
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -617,6 +617,8 @@ public class MainController implements InterceptorSkipController {
|
||||
menuId = menuId == null ? "" : menuId;
|
||||
model.addAttribute("mainPage", mainPage);
|
||||
model.addAttribute("menuId", menuId);
|
||||
model.addAttribute("autoLogoutTimeout",
|
||||
monitoringContext.getIntProperty(MonitoringContext.RMS_AUTO_LOGOUT_TIMEOUT, 10));
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("CURRENT SERVICE TYPE : " + service);
|
||||
|
||||
@@ -107,6 +107,17 @@ public class UserInfoService extends
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<UserInfo> findAllByRoleId(String roleId) {
|
||||
QUserInfo qUserInfo = QUserInfo.userInfo;
|
||||
QUserRole qUserRole = QUserRole.userRole;
|
||||
|
||||
return getJPAQueryFactory()
|
||||
.selectFrom(qUserInfo)
|
||||
.join(qUserRole).on(qUserInfo.userid.eq(qUserRole.id.userId))
|
||||
.where(qUserRole.id.roleId.eq(roleId))
|
||||
.fetch();
|
||||
}
|
||||
|
||||
public Page<UserInfo> findByUsername(Pageable pageable, String username) {
|
||||
QUserInfo qUserInfo = QUserInfo.userInfo;
|
||||
BooleanExpression predicate = qUserInfo.isNotNull();
|
||||
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.apim.portalinquiry;
|
||||
|
||||
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||
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;
|
||||
|
||||
@EMSDataSource
|
||||
public interface PortalInquiryCommentRepository extends BaseRepository<InquiryComment, String> {
|
||||
|
||||
long countByInquiry_Id(String inquiryId);
|
||||
|
||||
long countByInquiry_IdAndDelYn(String inquiryId, String delYn);
|
||||
|
||||
List<InquiryComment> findByInquiry_IdAndDelYnOrderByCreatedDateAsc(String inquiryId, String delYn);
|
||||
|
||||
Optional<InquiryComment> findTopByInquiry_IdAndDelYnOrderByCreatedDateDesc(
|
||||
String inquiryId, String delYn);
|
||||
|
||||
Optional<InquiryComment> findTopByInquiry_IdAndAdminYnAndDelYnOrderByCreatedDateDesc(
|
||||
String inquiryId, String adminYn, String delYn);
|
||||
|
||||
boolean existsByInquiry_IdAndAdminYnAndDelYnAndCreatedDateAfter(
|
||||
String inquiryId, String adminYn, String delYn, LocalDateTime after);
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.apim.portalinquiry;
|
||||
|
||||
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||
import com.eactive.eai.rms.data.jpa.AbstractEMSDataSerivce;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
public class PortalInquiryCommentService extends AbstractEMSDataSerivce<InquiryComment, String, PortalInquiryCommentRepository> {
|
||||
|
||||
// AbstractEMSDataSerivce의 repository 필드가 BaseRepository<T,I>로 고정되어
|
||||
// 커스텀 메서드를 호출할 수 없으므로 별도 필드로 직접 주입
|
||||
@Autowired
|
||||
private PortalInquiryCommentRepository inquiryCommentRepository;
|
||||
|
||||
public long countByInquiryId(String inquiryId) {
|
||||
return inquiryCommentRepository.countByInquiry_Id(inquiryId);
|
||||
}
|
||||
|
||||
public long countActiveByInquiryId(String inquiryId) {
|
||||
return inquiryCommentRepository.countByInquiry_IdAndDelYn(inquiryId, "N");
|
||||
}
|
||||
|
||||
public List<InquiryComment> findByInquiryId(String inquiryId) {
|
||||
return inquiryCommentRepository.findByInquiry_IdAndDelYnOrderByCreatedDateAsc(inquiryId, "N");
|
||||
}
|
||||
}
|
||||
+3
@@ -4,7 +4,10 @@ import com.eactive.apim.portal.qna.entity.Inquiry;
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@EMSDataSource
|
||||
public interface PortalInquiryRepository extends BaseRepository<Inquiry, String> {
|
||||
|
||||
List<Inquiry> findByInquiryStatus(String inquiryStatus);
|
||||
}
|
||||
|
||||
+18
-6
@@ -1,20 +1,28 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.apim.portalinquiry;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.apim.portal.qna.entity.Inquiry;
|
||||
import com.eactive.apim.portal.qna.entity.QInquiry;
|
||||
import com.eactive.eai.rms.data.jpa.AbstractEMSDataSerivce;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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.List;
|
||||
|
||||
@Service
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
public class PortalInquiryService extends AbstractEMSDataSerivce<Inquiry, String, PortalInquiryRepository> {
|
||||
|
||||
// AbstractEMSDataSerivce의 repository 필드가 BaseRepository<T,I>로 고정되어
|
||||
// 커스텀 메서드를 호출할 수 없으므로 별도 필드로 직접 주입
|
||||
@Autowired
|
||||
private PortalInquiryRepository portalInquiryRepository;
|
||||
|
||||
public Page<Inquiry> findAll(Pageable pageable, PortalInquirySearch portalInquirySearch) {
|
||||
QInquiry qInquiry = QInquiry.inquiry;
|
||||
|
||||
@@ -58,4 +66,8 @@ public class PortalInquiryService extends AbstractEMSDataSerivce<Inquiry, String
|
||||
repository.deleteAll(inquiries);
|
||||
}
|
||||
}
|
||||
|
||||
public List<Inquiry> findByInquiryStatus(String inquiryStatus) {
|
||||
return portalInquiryRepository.findByInquiryStatus(inquiryStatus);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.apistatus;
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.apistatus;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
+2
-1
@@ -1,7 +1,8 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.apistatus;
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.apistatus;
|
||||
|
||||
public interface ApiStatusEvent {
|
||||
String getEaisvcname();
|
||||
String getEaisvcdesc();
|
||||
String getPrevStatusCode();
|
||||
String getEvent();
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.inflow;
|
||||
|
||||
public interface InflowTokenInsufficient {
|
||||
String getEaisvcname();
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.inflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.inflow;
|
||||
|
||||
import java.io.Serializable;
|
||||
import javax.persistence.Column;
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.webhook;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.Comment;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PTL_WEBHOOK_REQ")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class WebhookReq {
|
||||
|
||||
@Id
|
||||
@Column(name = "ID", length = 36, nullable = false)
|
||||
private String id;
|
||||
|
||||
@Column(name = "ORG_ID", length = 100)
|
||||
@Comment("법인 ID")
|
||||
private String orgId;
|
||||
|
||||
@Column(name = "TARGET_URL", length = 500, nullable = false)
|
||||
@Comment("웹훅 수신 URL")
|
||||
private String targetUrl;
|
||||
|
||||
@Column(name = "SECRET", length = 200)
|
||||
@Comment("HMAC 서명용 Secret Key")
|
||||
private String secret;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.webhook;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PTL_WEBHOOK_REQ_API")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class WebhookReqApi implements Serializable {
|
||||
|
||||
@EmbeddedId
|
||||
private WebhookReqApiId id;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.webhook;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.Comment;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Embeddable
|
||||
public class WebhookReqApiId implements Serializable {
|
||||
|
||||
@Column(name = "WEBHOOK_REQ_ID", nullable = false, length = 36)
|
||||
@Comment("웹훅 요청 ID")
|
||||
private String webhookReqId;
|
||||
|
||||
@Column(name = "API_ID", nullable = false, length = 100)
|
||||
@Comment("API ID")
|
||||
private String apiId;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.webhook;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import javax.persistence.EmbeddedId;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "PTL_WEBHOOK_REQ_EVENT")
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
public class WebhookReqEvent implements Serializable {
|
||||
|
||||
@EmbeddedId
|
||||
private WebhookReqEventId id;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.webhook;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.hibernate.annotations.Comment;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embeddable;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Embeddable
|
||||
public class WebhookReqEventId implements Serializable {
|
||||
|
||||
@Column(name = "WEBHOOK_REQ_ID", nullable = false, length = 36)
|
||||
@Comment("웹훅 요청 ID")
|
||||
private String webhookReqId;
|
||||
|
||||
@Column(name = "EVENT_TYPE", nullable = false, length = 50)
|
||||
@Comment("이벤트 유형 (CONTROL_START, ERROR_START 등)")
|
||||
private String eventType;
|
||||
}
|
||||
+4
-1
@@ -1,4 +1,4 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.webhook;
|
||||
package com.eactive.eai.rms.data.entity.onl.djb.webhook;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
@@ -42,6 +42,9 @@ public class WebhookSendLog {
|
||||
@Column(name = "STATUS_CODE")
|
||||
private Integer statusCode;
|
||||
|
||||
@Column(name = "ORG_ID")
|
||||
private String orgId;
|
||||
|
||||
@Lob
|
||||
@Column(name = "RESPONSE_BODY")
|
||||
private String responseBody;
|
||||
@@ -1,69 +0,0 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.apistatus;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.eai.rms.ext.djb.event.ApiStatusChangedEvent;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class ApiStatusService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiStatusService.class);
|
||||
|
||||
@Autowired
|
||||
private ApiStatusRepository apiStatusRepository;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
|
||||
|
||||
|
||||
public void updateApiStatus(HashMap<String, String> param) {
|
||||
|
||||
List<ApiStatusEvent> list = apiStatusRepository.findApiStatusEvents(
|
||||
Integer.parseInt(param.get("errorRate")),
|
||||
Integer.parseInt(param.get("errorRangeMinute")),
|
||||
Integer.parseInt(param.get("delayRangeMinute")),
|
||||
Integer.parseInt(param.get("delayAvgRespTime"))
|
||||
);
|
||||
|
||||
for (ApiStatusEvent event : list) {
|
||||
String newStatusCode = resolveStatusCode(event.getEvent());
|
||||
if (newStatusCode == null) continue;
|
||||
|
||||
ApiStatus apiStatus = apiStatusRepository.findById(event.getEaisvcname()).orElse(new ApiStatus());
|
||||
|
||||
apiStatus.setEaisvcname(event.getEaisvcname());
|
||||
apiStatus.setStatusCode(newStatusCode);
|
||||
|
||||
apiStatusRepository.save(apiStatus); // PK 있으면 UPDATE, 없으면 INSERT
|
||||
log.debug("API 상태 변경: {}-{} {} → {}", event.getEaisvcname(), event.getEaisvcdesc(), event.getEvent(), newStatusCode);
|
||||
|
||||
eventPublisher.publishEvent(ApiStatusChangedEvent.from(event)); // 트랜잭션 커밋 후 리스너 실행
|
||||
log.debug("이벤트 전파");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String resolveStatusCode(String event) {
|
||||
switch (event) {
|
||||
case "CONTROL_START": return "C"; //점검
|
||||
case "CONTROL_END": return "N"; //정상
|
||||
case "ERROR_START": return "E"; //장애
|
||||
case "ERROR_END": return "N"; //정상
|
||||
case "DELAY_START": return "D"; //지연
|
||||
case "DELAY_END": return "N"; //정상
|
||||
default:
|
||||
log.warn("알 수 없는 이벤트: {}", event);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.eactive.eai.rms.ext.djb.apistatus;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class ApiStatusDetectionService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiStatusDetectionService.class);
|
||||
|
||||
/**
|
||||
* 이벤트 감지
|
||||
* @param event "CONTROL_START" : 점검시작
|
||||
"CONTROL_END" : 점검종료
|
||||
"ERROR_START" : 장애시작
|
||||
"ERROR_END" : 장애종료
|
||||
"DELAY_START" : 지연시작
|
||||
"DELAY_END" : 지연종료
|
||||
* @param apiIds API IDs
|
||||
*/
|
||||
public void detect(String event, List<String> apiIds) {
|
||||
log.debug("이벤트 감지: {} {}", event, apiIds);
|
||||
}
|
||||
|
||||
// API FSM 내 아직 장애로 남아있는 API 목록
|
||||
public void remainDownApiIds() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 정상 동작 - detect()에서 일괄 처리 (복구 = 점검종료, 장애종료, 지연종료)
|
||||
// public void recovered(String event, String[] apiIds) {
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
+13
-8
@@ -1,10 +1,12 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.apistatus;
|
||||
package com.eactive.eai.rms.ext.djb.apistatus;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.apistatus.ApiStatus;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.apistatus.ApiStatusEvent;
|
||||
|
||||
public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
||||
|
||||
@@ -22,9 +24,11 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
||||
@Query(nativeQuery = true, value =
|
||||
" SELECT EAISVCNAME"
|
||||
+ " , (SELECT EAISVCDESC FROM TSEAIHE01 WHERE A.EAISVCNAME = EAISVCNAME) AS EAISVCDESC"
|
||||
+ " , PREV_STATUS_CODE "
|
||||
+ " , EVENT"
|
||||
+ " FROM ("
|
||||
+ " SELECT EAISVCNAME"
|
||||
+ " , STATUS_CODE AS PREV_STATUS_CODE "
|
||||
+ " , CASE WHEN STATUS_CODE != 'C' AND CTRL_YN = 'Y' THEN 'CONTROL_START'"
|
||||
+ " WHEN STATUS_CODE = 'C' AND CTRL_YN = 'N' THEN 'CONTROL_END'"
|
||||
+ " WHEN STATUS_CODE IN ('N','D') AND ERR_YN = 'Y' THEN 'ERROR_START'"
|
||||
@@ -34,14 +38,15 @@ public interface ApiStatusRepository extends BaseRepository<ApiStatus, String> {
|
||||
+ " ELSE 'STAY' END AS EVENT"
|
||||
+ " FROM ("
|
||||
+ " SELECT A.EAISVCNAME"
|
||||
+ " , NVL(B.STATUS_CODE, '1') AS STATUS_CODE"
|
||||
+ " , NVL((SELECT 'Y' FROM TSEAITI01"
|
||||
+ " WHERE (TO_CHAR(SYSDATE,'HH24MI') BETWEEN SUBSTR(EAICTRLDSTICCTNT,16,4) AND SUBSTR(EAICTRLDSTICCTNT,21,4)"
|
||||
+ " OR SUBSTR(EAICTRLDSTICCTNT,16,9) = '0000|0000')"
|
||||
+ " AND A.EAISVCNAME = EAICTRLNAME),'N') AS CTRL_YN"
|
||||
+ " , NVL(B.STATUS_CODE, 'N') AS STATUS_CODE"
|
||||
//TODO: 게시판 임시로 생성하여 사용. 유차장이 완료하면 변경할것
|
||||
+ " , NVL(( SELECT 'Y' FROM PTL_NOTICE_API X "
|
||||
+ " WHERE EXISTS (SELECT 1 FROM EMSAPP.PTL_NOTICE Y WHERE X.NOTICE_ID = Y.ID)"
|
||||
//+ " AND TO_CHAR(SYSDATE, 'YYYYMMDDHH24MI') BETWEEN START_TIME AND END_TIME) "
|
||||
+ " AND A.EAISVCNAME = X.API_NAME),'N') AS CTRL_YN "
|
||||
+ " , (SELECT CASE WHEN TOTAL = 0 THEN 'X'"
|
||||
+ " WHEN (TOTAL - SUCCESS) * 100 / TOTAL > :errorRate THEN 'Y'"
|
||||
+ " ELSE 'N' END"
|
||||
+ " WHEN (TOTAL - SUCCESS) * 100 / TOTAL > :errorRate THEN 'Y'"
|
||||
+ " ELSE 'N' END"
|
||||
+ " FROM (SELECT SUM(SUCCESS_CNT + TIMEOUT_CNT + SYSTEM_ERR_CNT + BIZ_ERR_CNT) AS TOTAL"
|
||||
+ " , SUM(SUCCESS_CNT) AS SUCCESS"
|
||||
+ " FROM API_STATS_MINUTE"
|
||||
@@ -0,0 +1,133 @@
|
||||
package com.eactive.eai.rms.ext.djb.apistatus;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.eai.rms.data.entity.man.role.Role;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.apistatus.ApiStatus;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.apistatus.ApiStatusEvent;
|
||||
import com.eactive.eai.rms.ext.djb.util.UmsManager;
|
||||
|
||||
|
||||
@Service
|
||||
@Transactional
|
||||
public class ApiStatusService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(ApiStatusService.class);
|
||||
|
||||
@Autowired
|
||||
private ApiStatusRepository apiStatusRepository;
|
||||
|
||||
@Autowired
|
||||
private UmsManager ums;
|
||||
|
||||
@Autowired
|
||||
private ApiStatusDetectionService apiStatusDectionService;
|
||||
|
||||
|
||||
public void updateApiStatus(HashMap<String, String> param) {
|
||||
|
||||
List<ApiStatusEvent> list = apiStatusRepository.findApiStatusEvents(
|
||||
Integer.parseInt(param.get("errorRate")),
|
||||
Integer.parseInt(param.get("errorRangeMinute")),
|
||||
Integer.parseInt(param.get("delayRangeMinute")),
|
||||
Integer.parseInt(param.get("delayAvgRespTime"))
|
||||
);
|
||||
|
||||
HashMap<String, List<String>> eventMap = new HashMap<>();
|
||||
|
||||
|
||||
for (ApiStatusEvent event : list) {
|
||||
String newStatusCode = resolveStatusCode(event.getEvent());
|
||||
if (newStatusCode == null) continue;
|
||||
|
||||
ApiStatus apiStatus = apiStatusRepository.findById(event.getEaisvcname()).orElse(new ApiStatus());
|
||||
|
||||
apiStatus.setEaisvcname(event.getEaisvcname());
|
||||
apiStatus.setStatusCode(newStatusCode);
|
||||
|
||||
apiStatusRepository.save(apiStatus); // PK 있으면 UPDATE, 없으면 INSERT
|
||||
log.debug("API 상태 변경: {}-{} {} → {}", event.getEaisvcname(), event.getEaisvcdesc(), event.getEvent(), newStatusCode);
|
||||
|
||||
|
||||
//이벤트별로 api분리 저장
|
||||
List<String> apis = (List<String>)eventMap.get(event.getEvent());
|
||||
if (apis == null) {
|
||||
apis = new ArrayList<String>();
|
||||
apis.add(event.getEaisvcname());
|
||||
eventMap.put(event.getEvent(), apis);
|
||||
} else {
|
||||
apis.add(event.getEaisvcname());
|
||||
}
|
||||
}
|
||||
|
||||
//이벤트별로 ums, webhook을 발송한다
|
||||
for (Map.Entry<String, List<String>> entry : eventMap.entrySet()) {
|
||||
String event = entry.getKey();
|
||||
List<String> apiIds = entry.getValue();
|
||||
|
||||
String message = getSwingChatMessage(event, apiIds);
|
||||
ums.sendMessenger("api-monitor", MessageCode.API_STATUS_CHANGED, message);
|
||||
|
||||
//제휴사 웹훅 발송
|
||||
ums.sendWebhook(event, apiIds);
|
||||
|
||||
//개발자포탈 API상태모니터링 화면을 위한 처리
|
||||
apiStatusDectionService.detect(event, apiIds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String resolveStatusCode(String event) {
|
||||
switch (event) {
|
||||
case "CONTROL_START": return "C"; //점검
|
||||
case "CONTROL_END": return "N"; //정상
|
||||
case "ERROR_START": return "E"; //장애
|
||||
case "ERROR_END": return "N"; //정상
|
||||
case "DELAY_START": return "D"; //지연
|
||||
case "DELAY_END": return "N"; //정상
|
||||
default:
|
||||
log.warn("알 수 없는 이벤트: {}", event);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String getSwingChatMessage(String event, List<String> apiIds) {
|
||||
String message = "";
|
||||
switch (event) {
|
||||
case "CONTROL_START":
|
||||
message = "API 서비스 점검이 시작되었습니다"; //점검
|
||||
break;
|
||||
case "CONTROL_END":
|
||||
message = "API 서비스 점검이 완료되었습니다"; //정상
|
||||
break;
|
||||
case "ERROR_START":
|
||||
message = "API 서비스 장애가 발생하였습니다"; //장애
|
||||
break;
|
||||
case "ERROR_END":
|
||||
message = "API 서비스 장애가 복구되었습니다"; //정상
|
||||
break;
|
||||
case "DELAY_START":
|
||||
message = "API 서비스 지연이 발생하였습니다"; //지연
|
||||
break;
|
||||
case "DELAY_END":
|
||||
message = "API 서비스 지연이 복구되었습니다"; //정상
|
||||
break;
|
||||
default:
|
||||
message = "";
|
||||
}
|
||||
|
||||
return message + "\n- " + String.join(",", apiIds);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.async;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class AsyncConfig {
|
||||
|
||||
@Bean("asyncExecutor")
|
||||
public Executor asyncExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(2);
|
||||
executor.setMaxPoolSize(5);
|
||||
executor.setQueueCapacity(20);
|
||||
executor.setThreadNamePrefix("async-");
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.async;
|
||||
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.event.TransactionPhase;
|
||||
import org.springframework.transaction.event.TransactionalEventListener;
|
||||
|
||||
import com.eactive.eai.rms.ext.djb.event.ApiStatusChangedEvent;
|
||||
import com.eactive.eai.rms.ext.djb.event.InflowTokenInsufficientEvent;
|
||||
import com.eactive.eai.rms.ext.djb.swing.service.SwingSendManager;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.service.WebhookSendManager;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AsyncEventListener {
|
||||
|
||||
private final WebhookSendManager webhookSendManager;
|
||||
|
||||
private final SwingSendManager swingSendManager;
|
||||
|
||||
@Async("asyncExecutor")
|
||||
@TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT)
|
||||
public void onApiStatusChanged(ApiStatusChangedEvent event) {
|
||||
log.debug("API 상태 변경 이벤트 수신: {} {}", event.getEaisvcname(), event.getEvent());
|
||||
webhookSendManager.send(event.getEaisvcname(), event.getEvent());
|
||||
swingSendManager.send(null, 0, 0);
|
||||
}
|
||||
|
||||
@Async("asyncExecutor")
|
||||
@EventListener // 트랜잭션 write 없이 read만 하므로 TransactionalEventListener 불필요
|
||||
public void onInflowTokenFail(InflowTokenInsufficientEvent event) {
|
||||
log.debug("유량제어 토큰획득 실패 이벤트 수신: {} {}건", event.getEaisvcname(), event.getCnt());
|
||||
swingSendManager.send(event.getEaisvcname(), event.getCnt(), event.getRangeMinute());
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.event;
|
||||
|
||||
import com.eactive.eai.rms.data.ext.djb.apistatus.ApiStatusEvent;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class ApiStatusChangedEvent {
|
||||
private final String eaisvcname;
|
||||
private final String eaisvcdesc;
|
||||
private final String event;
|
||||
|
||||
public static ApiStatusChangedEvent from(ApiStatusEvent source) {
|
||||
return new ApiStatusChangedEvent(source.getEaisvcname(), source.getEaisvcdesc(), source.getEvent());
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.event;
|
||||
|
||||
import com.eactive.eai.rms.data.ext.djb.inflow.InflowTokenInsufficient;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public class InflowTokenInsufficientEvent {
|
||||
private final String eaisvcname;
|
||||
private final String eaisvcdesc;
|
||||
private final long cnt;
|
||||
private final long rangeMinute;
|
||||
|
||||
public static InflowTokenInsufficientEvent from(InflowTokenInsufficient summary, long rangeMinute) {
|
||||
return new InflowTokenInsufficientEvent(summary.getEaisvcname(), summary.getEaisvcdesc(), summary.getCnt(), rangeMinute);
|
||||
}
|
||||
}
|
||||
+4
-1
@@ -1,9 +1,12 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
package com.eactive.eai.rms.ext.djb.inflow;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.inflow.InflowTokenInsufficient;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.inflow.InflowTokenInsufficientLog;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.inflow.InflowTokenInsufficientLogId;
|
||||
|
||||
public interface InflowTokenRepository extends BaseRepository<InflowTokenInsufficientLog, InflowTokenInsufficientLogId> {
|
||||
|
||||
+9
-7
@@ -1,15 +1,17 @@
|
||||
package com.eactive.eai.rms.data.ext.djb.inflow;
|
||||
package com.eactive.eai.rms.ext.djb.inflow;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.eactive.eai.rms.ext.djb.event.InflowTokenInsufficientEvent;
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.eai.rms.data.entity.man.role.Role;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.inflow.InflowTokenInsufficient;
|
||||
import com.eactive.eai.rms.ext.djb.util.UmsManager;
|
||||
|
||||
|
||||
@Service
|
||||
@@ -22,16 +24,16 @@ public class InflowTokenService {
|
||||
private InflowTokenRepository inflowTokenRepository;
|
||||
|
||||
@Autowired
|
||||
private ApplicationEventPublisher eventPublisher;
|
||||
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());
|
||||
|
||||
//내부직원 알림 발송
|
||||
eventPublisher.publishEvent(InflowTokenInsufficientEvent.from(info, rangeMinute));
|
||||
String message = "유량제어 토큰 획득 실패하였습니다 \n" + info.getEaisvcname();
|
||||
|
||||
ums.sendMessenger("api-monitor", MessageCode.INFLOW_TOKEN_FAILED, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
|
||||
import com.eactive.eai.rms.common.util.CommonUtil;
|
||||
import com.eactive.eai.rms.data.ext.djb.apistatus.ApiStatusService;
|
||||
import com.eactive.eai.rms.ext.djb.apistatus.ApiStatusService;
|
||||
import com.eactive.eai.rms.onl.common.util.DateUtil;
|
||||
|
||||
/**
|
||||
@@ -88,11 +88,11 @@ public class ApiStatusMonitorJob implements Job {
|
||||
monitoringContext = (MonitoringContext) appContext.getBean("monitoringContext");
|
||||
ApiStatusService apiStatusUpdateService = appContext.getBean(ApiStatusService.class);
|
||||
|
||||
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||
try {
|
||||
apiStatusUpdateService.updateApiStatus(param);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("ApiStatusUpdateJob execution failed", e);
|
||||
throw new JobExecutionException(e);
|
||||
|
||||
@@ -18,7 +18,7 @@ import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
|
||||
import com.eactive.eai.rms.common.util.CommonUtil;
|
||||
import com.eactive.eai.rms.data.ext.djb.inflow.InflowTokenService;
|
||||
import com.eactive.eai.rms.ext.djb.inflow.InflowTokenService;
|
||||
import com.eactive.eai.rms.onl.common.util.DateUtil;
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package com.eactive.eai.rms.ext.djb.job;
|
||||
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceContextHolder;
|
||||
import com.eactive.eai.rms.common.datasource.DataSourceTypeManager;
|
||||
import com.eactive.eai.rms.common.util.CommonUtil;
|
||||
import com.eactive.eai.rms.onl.apim.portalInquiry.PortalInquiryClosingService;
|
||||
import com.eactive.eai.rms.onl.common.util.DateUtil;
|
||||
import org.quartz.DisallowConcurrentExecution;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/**
|
||||
* 매일 00:05 실행 - RESPONDED 상태 문의글 자동 종료 배치
|
||||
*
|
||||
* <p>종료 조건 (기본 7일):</p>
|
||||
* <ul>
|
||||
* <li>답변완료 후 댓글이 7일간 없는 경우</li>
|
||||
* <li>관리자 댓글 등록 후 7일간 포탈사용자 댓글이 없는 경우</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>Cron: 0 5 0 * * ?</p>
|
||||
*
|
||||
* <p>Job 파라미터 (JobDataMap):</p>
|
||||
* <ul>
|
||||
* <li>{@value #KEY_INQUIRY_COMMENT_CLOSING_DAY}: 종료 기준 일수 (기본값: 7)</li>
|
||||
* </ul>
|
||||
*/
|
||||
@DisallowConcurrentExecution
|
||||
public class PortalInquiryClosingJob implements Job {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(PortalInquiryClosingJob.class);
|
||||
|
||||
/** Job 파라미터 키: 댓글종료 기간(일) */
|
||||
public static final String KEY_INQUIRY_COMMENT_CLOSING_DAY = "inquiry.comment.closing_day";
|
||||
|
||||
private static final int DEFAULT_CLOSING_DAYS = 7;
|
||||
|
||||
@Autowired
|
||||
private PortalInquiryClosingService inquiryCommentClosingService;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext context) throws JobExecutionException {
|
||||
log.info("*** START PortalInquiryCommentClosingService run({})", CommonUtil.getToday("yyyy-MM-dd HH:mm"));
|
||||
|
||||
int closingDays = DEFAULT_CLOSING_DAYS;
|
||||
String closingDayParam = context.getMergedJobDataMap().getString(KEY_INQUIRY_COMMENT_CLOSING_DAY);
|
||||
if (closingDayParam != null) {
|
||||
try {
|
||||
closingDays = Integer.parseInt(closingDayParam);
|
||||
} catch (NumberFormatException e) {
|
||||
log.warn("잘못된 {} 파라미터 값: '{}', 기본값 {}일 사용", KEY_INQUIRY_COMMENT_CLOSING_DAY, closingDayParam, DEFAULT_CLOSING_DAYS);
|
||||
}
|
||||
}
|
||||
|
||||
DataSourceContextHolder.setDataSourceType(
|
||||
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.APIGW));
|
||||
try {
|
||||
int closedCount = inquiryCommentClosingService.closeExpiredInquiries(closingDays);
|
||||
log.info("PortalInquiryCommentClosingService 완료: {}건 CLOSED 처리", closedCount);
|
||||
} catch (Exception e) {
|
||||
log.error("PortalInquiryCommentClosingService execution failed", e);
|
||||
throw new JobExecutionException(e);
|
||||
} finally {
|
||||
DataSourceContextHolder.clearDataSourceType();
|
||||
}
|
||||
|
||||
log.info("*** END PortalInquiryCommentClosingService run({})", DateUtil.getDateTime("yyyy-MM-dd HH:mm"));
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.swing.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class SwingSendManager {
|
||||
|
||||
public void send(String eaisvcname, long cnt, long rangeMinute) {
|
||||
log.info("[Swing] 발송 준비: {} 최근 {}분 {}건", eaisvcname, rangeMinute, cnt);
|
||||
// TODO: 알림 발송 로직
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.eactive.eai.rms.ext.djb.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.eactive.apim.portal.template.entity.MessageCode;
|
||||
import com.eactive.apim.portal.template.service.MessageHandlerService;
|
||||
import com.eactive.apim.portal.template.service.MessageRecipient;
|
||||
import com.eactive.apim.portal.user.entity.UserInfo;
|
||||
import com.eactive.eai.rms.data.entity.man.user.UserInfoService;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendRequest;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.service.WebhookService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class UmsManager {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(UmsManager.class);
|
||||
|
||||
private final MessageHandlerService messageHandlerService;
|
||||
private final UserInfoService userInfoService;
|
||||
private final WebhookService webhookService;
|
||||
|
||||
/**
|
||||
* role 역할을 가진 내부직원에게 메신저(Swing chat) 발송
|
||||
* @param role
|
||||
* @param messageCode
|
||||
* @param message
|
||||
* @return
|
||||
*/
|
||||
public void sendMessenger(String roleId, MessageCode messageCode, String message) {
|
||||
|
||||
List<UserInfo> users = userInfoService.findAllByRoleId(roleId);
|
||||
if (users.isEmpty()) {
|
||||
log.info("sendMessenger: no users found for role '{}'", roleId);
|
||||
return;
|
||||
}
|
||||
|
||||
for (UserInfo user : users) {
|
||||
MessageRecipient recipient = MessageRecipient.builder()
|
||||
.userId(user.getUserid())
|
||||
.username(user.getUsername())
|
||||
.build();
|
||||
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("message", message);
|
||||
|
||||
messageHandlerService.publishEvent(messageCode, recipient, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 내부직원에게 메신저 발송
|
||||
* @param user
|
||||
* @param messageCode
|
||||
* @param message
|
||||
*/
|
||||
public void sendMessenger(UserInfo user, MessageCode messageCode, String message) {
|
||||
MessageRecipient recipient = MessageRecipient.builder()
|
||||
.userId(user.getUserid())
|
||||
.username(user.getUsername())
|
||||
.build();
|
||||
|
||||
HashMap<String, Object> params = new HashMap<>();
|
||||
params.put("message", message);
|
||||
|
||||
messageHandlerService.publishEvent(messageCode, recipient, params);
|
||||
}
|
||||
|
||||
/**
|
||||
* event를 구독중인 제휴사에게 웹훅 발송 (비동기)
|
||||
* @param event
|
||||
* @param apiIds
|
||||
*/
|
||||
@Async("webhookExecutor")
|
||||
public void sendWebhook(String event, List<String> apiIds) {
|
||||
List<WebhookSendRequest> list = webhookService.findSendList(event, apiIds);
|
||||
for (WebhookSendRequest req : list) {
|
||||
webhookService.send(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.config;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
|
||||
@Configuration
|
||||
@EnableAsync
|
||||
public class WebhookAsyncConfig {
|
||||
|
||||
@Bean(name = "webhookExecutor")
|
||||
public Executor webhookExecutor() {
|
||||
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
|
||||
executor.setCorePoolSize(2);
|
||||
executor.setMaxPoolSize(10);
|
||||
executor.setQueueCapacity(100);
|
||||
executor.setThreadNamePrefix("webhook-");
|
||||
executor.setWaitForTasksToCompleteOnShutdown(true);
|
||||
executor.setAwaitTerminationSeconds(30);
|
||||
executor.initialize();
|
||||
return executor;
|
||||
}
|
||||
}
|
||||
+5
-9
@@ -11,7 +11,7 @@ import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import com.eactive.eai.rms.data.ext.djb.webhook.WebhookSendLog;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.WebhookSendLog;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendRequest;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.service.WebhookReceiveService;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.service.WebhookService;
|
||||
@@ -38,16 +38,12 @@ public class WebhookSendController {
|
||||
public ResponseEntity<Map<String, Object>> sendWebhook(
|
||||
@RequestBody WebhookSendRequest request) {
|
||||
|
||||
WebhookSendLog result = webhookService.send(
|
||||
request.getTargetUrl(),
|
||||
request.getEventType(),
|
||||
request.getData()
|
||||
);
|
||||
webhookService.send(request);
|
||||
|
||||
Map<String, Object> response = new HashMap<>();
|
||||
response.put("logId", result.getId());
|
||||
response.put("success", result.getSuccess());
|
||||
response.put("statusCode", result.getStatusCode());
|
||||
// response.put("logId", result.getId());
|
||||
// response.put("success", result.getSuccess());
|
||||
// response.put("statusCode", result.getStatusCode());
|
||||
|
||||
return ResponseEntity.ok(response);
|
||||
}
|
||||
|
||||
@@ -6,8 +6,9 @@ import lombok.Setter;
|
||||
@Getter
|
||||
@Setter
|
||||
public class WebhookSendRequest {
|
||||
|
||||
private String orgId;
|
||||
private String targetUrl;
|
||||
private String eventType;
|
||||
private String secret;
|
||||
private Object data;
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.repository;
|
||||
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.WebhookReq;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
@Repository
|
||||
@EMSDataSource
|
||||
public interface WebhookReqRepository extends JpaRepository<WebhookReq, String> {
|
||||
}
|
||||
+1
-1
@@ -10,7 +10,7 @@ import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
import com.eactive.eai.rms.data.ext.djb.webhook.WebhookSendLog;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.WebhookSendLog;
|
||||
|
||||
@Repository
|
||||
@EMSDataSource
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.service;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WebhookSendManager {
|
||||
|
||||
public void send(String eaisvcname, String eventType) {
|
||||
log.info("[Webhook] 발송 준비: {} {}", eaisvcname, eventType);
|
||||
// TODO: PTL_WEBHOOK_REQ 조인 조회 후 WebhookService.send() 호출
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,16 @@ package com.eactive.eai.rms.ext.djb.webhook.service;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -18,10 +22,17 @@ import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.eactive.eai.rms.data.ext.djb.webhook.WebhookSendLog;
|
||||
import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.QWebhookReq;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.QWebhookReqApi;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.QWebhookReqEvent;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.WebhookSendLog;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookPayload;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendRequest;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.repository.WebhookSendLogRepository;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.querydsl.core.Tuple;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -34,19 +45,63 @@ public class WebhookService {
|
||||
private final WebhookSendLogRepository sendLogRepository;
|
||||
private final ObjectMapper objectMapper;
|
||||
private final RestTemplate restTemplate;
|
||||
private final MonitoringContext monitoringContext;
|
||||
|
||||
|
||||
private String secretKey = "HW8JtFpkPmQqsVmr0Rb81P4qDypaNIVbGf3ZNMMPfyerhOHshoKABLaMBo1HA4BldTxhw1NjYmVnoPu9IIV7cyRXjecL3b2UctyR7DnVaJausltZLLr8Qm4Bzs4wRmgf";
|
||||
@PersistenceContext(unitName = "entityManagerFactoryForEMS")
|
||||
private EntityManager entityManager;
|
||||
|
||||
private static final String HMAC_ALGORITHM = "HmacSHA256";
|
||||
private static final int MAX_RETRY = 3;
|
||||
private static final int DEFAULT_RETRY_COUNT = 3;
|
||||
private static final int DEFAULT_RETRY_TIME = 10000;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<WebhookSendRequest> findSendList(String event, List<String> apiIds) {
|
||||
QWebhookReq req = QWebhookReq.webhookReq;
|
||||
QWebhookReqEvent evt = QWebhookReqEvent.webhookReqEvent;
|
||||
QWebhookReqApi api = QWebhookReqApi.webhookReqApi;
|
||||
|
||||
List<Tuple> tuples = new JPAQueryFactory(entityManager)
|
||||
.select(req.orgId, req.targetUrl, req.secret, api.id.apiId)
|
||||
.from(req)
|
||||
.join(evt).on(req.id.eq(evt.id.webhookReqId))
|
||||
.join(api).on(req.id.eq(api.id.webhookReqId))
|
||||
.where(evt.id.eventType.eq(event)
|
||||
.and(api.id.apiId.in(apiIds)))
|
||||
.fetch();
|
||||
|
||||
// orgId + targetUrl + secret 기준으로 그룹핑, apiId를 data(List)로 집계
|
||||
Map<String, WebhookSendRequest> resultMap = new LinkedHashMap<>();
|
||||
for (Tuple t : tuples) {
|
||||
String key = t.get(req.orgId) + "|" + t.get(req.targetUrl);
|
||||
resultMap.computeIfAbsent(key, k -> {
|
||||
WebhookSendRequest wr = new WebhookSendRequest();
|
||||
wr.setOrgId(t.get(req.orgId));
|
||||
wr.setTargetUrl(t.get(req.targetUrl));
|
||||
wr.setSecret(t.get(req.secret));
|
||||
wr.setEventType(event);
|
||||
wr.setData(new ArrayList<String>());
|
||||
return wr;
|
||||
});
|
||||
((List<String>) resultMap.get(key).getData()).add(t.get(api.id.apiId));
|
||||
}
|
||||
|
||||
return new ArrayList<>(resultMap.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 웹훅 발송 메인 메서드
|
||||
*/
|
||||
@Transactional
|
||||
public WebhookSendLog send(String targetUrl, String eventType, Object data) {
|
||||
public void send(WebhookSendRequest req) {
|
||||
|
||||
String targetUrl = req.getTargetUrl();
|
||||
String secret = req.getSecret();
|
||||
String eventType = req.getEventType();
|
||||
Object data = req.getData();
|
||||
|
||||
WebhookSendLog sendLog = new WebhookSendLog();
|
||||
sendLog.setOrgId(req.getOrgId());
|
||||
sendLog.setTargetUrl(targetUrl);
|
||||
sendLog.setEventType(eventType);
|
||||
|
||||
@@ -57,7 +112,7 @@ public class WebhookService {
|
||||
sendLog.setPayload(payloadJson);
|
||||
|
||||
// 2. Secret Key로 HMAC-SHA256 서명 생성
|
||||
String signature = generateSignature(payloadJson);
|
||||
String signature = generateSignature(secret, payloadJson);
|
||||
sendLog.setSignature(signature);
|
||||
|
||||
// 3. HTTP 요청 헤더 구성
|
||||
@@ -67,18 +122,20 @@ public class WebhookService {
|
||||
headers.set("X-Webhook-Event", eventType);
|
||||
headers.set("X-Webhook-Timestamp", String.valueOf(webhookPayload.getTimestamp()));
|
||||
|
||||
// 4. 발송
|
||||
// 4. 발송 (재시도 포함)
|
||||
int retryCount = monitoringContext.getIntProperty(MonitoringContext.API_WEBHOOK_RETRY_COUNT, DEFAULT_RETRY_COUNT);
|
||||
int retryTime = monitoringContext.getIntProperty(MonitoringContext.API_WEBHOOK_RETRY_TIME, DEFAULT_RETRY_TIME);
|
||||
sendLog.setSentAt(LocalDateTime.now());
|
||||
HttpEntity<String> request = new HttpEntity<>(payloadJson, headers);
|
||||
ResponseEntity<String> response = restTemplate.postForEntity(targetUrl, request, String.class);
|
||||
HttpEntity<String> httpRequest = new HttpEntity<>(payloadJson, headers);
|
||||
ResponseEntity<String> response = sendWithRetry(targetUrl, httpRequest, sendLog, retryCount, retryTime);
|
||||
|
||||
// 5. 성공 로그
|
||||
sendLog.setStatusCode(response.getStatusCode().value());
|
||||
sendLog.setResponseBody(response.getBody());
|
||||
sendLog.setSuccess(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
log.info("[Webhook] 발송 성공 - eventType: {}, url: {}, status: {}",
|
||||
eventType, targetUrl, response.getStatusCode());
|
||||
log.info("[Webhook] 발송 성공 - eventType: {}, url: {}, status: {}, retryCount: {}",
|
||||
eventType, targetUrl, response.getStatusCode(), sendLog.getRetryCount());
|
||||
|
||||
} catch (HttpClientErrorException | HttpServerErrorException e) {
|
||||
sendLog.setStatusCode(e.getStatusCode().value());
|
||||
@@ -95,40 +152,46 @@ public class WebhookService {
|
||||
eventType, targetUrl, e.getMessage());
|
||||
}
|
||||
|
||||
return sendLogRepository.save(sendLog);
|
||||
sendLogRepository.save(sendLog);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 실패 건 재시도
|
||||
* 재시도 포함 HTTP 발송
|
||||
* - 4xx: 클라이언트 오류이므로 즉시 throw (재시도 불필요)
|
||||
* - 5xx / 네트워크 오류: 최대 RETRY_COUNT회까지 exponential backoff 재시도 (1s → 2s → 4s)
|
||||
*/
|
||||
@Transactional
|
||||
public void retryFailedWebhooks() {
|
||||
List<WebhookSendLog> failedLogs =
|
||||
sendLogRepository.findFailedLogs(MAX_RETRY);
|
||||
|
||||
for (WebhookSendLog failedLog : failedLogs) {
|
||||
private ResponseEntity<String> sendWithRetry(String targetUrl, HttpEntity<String> request, WebhookSendLog sendLog, int retryCount, int retryTime) throws Exception {
|
||||
Exception lastException = null;
|
||||
for (int attempt = 0; attempt <= retryCount; attempt++) {
|
||||
try {
|
||||
log.info("[Webhook] 재시도 - id: {}, retry: {}", failedLog.getId(), failedLog.getRetryCount());
|
||||
failedLog.setRetryCount(failedLog.getRetryCount() + 1);
|
||||
sendLogRepository.save(failedLog);
|
||||
|
||||
send(failedLog.getTargetUrl(), failedLog.getEventType(),
|
||||
objectMapper.readValue(failedLog.getPayload(), Object.class));
|
||||
|
||||
if (attempt > 0) {
|
||||
long delayMs = retryTime * (1L << (attempt - 1));
|
||||
log.info("[Webhook] 재시도 {}/{} - url: {}, delay: {}ms", attempt, retryCount, targetUrl, delayMs);
|
||||
Thread.sleep(delayMs);
|
||||
sendLog.setRetryCount(attempt);
|
||||
}
|
||||
return restTemplate.postForEntity(targetUrl, request, String.class);
|
||||
} catch (HttpClientErrorException e) {
|
||||
throw e; // 4xx는 재시도 불필요
|
||||
} catch (Exception e) {
|
||||
log.error("[Webhook] 재시도 실패 - id: {}", failedLog.getId(), e);
|
||||
lastException = e;
|
||||
log.warn("[Webhook] 발송 실패 (attempt {}/{}) - url: {}, error: {}", attempt, retryCount, targetUrl, e.getMessage());
|
||||
}
|
||||
}
|
||||
throw lastException;
|
||||
}
|
||||
|
||||
/**
|
||||
* HMAC-SHA256 서명 생성
|
||||
* Java 17 미만은 HexFormat 미지원이므로 직접 변환
|
||||
*/
|
||||
private String generateSignature(String payload) throws Exception {
|
||||
private String generateSignature(String secret, String payload) throws Exception {
|
||||
Mac mac = Mac.getInstance(HMAC_ALGORITHM);
|
||||
SecretKeySpec keySpec = new SecretKeySpec(
|
||||
secretKey.getBytes(StandardCharsets.UTF_8), HMAC_ALGORITHM);
|
||||
secret.getBytes(StandardCharsets.UTF_8), HMAC_ALGORITHM);
|
||||
mac.init(keySpec);
|
||||
byte[] hash = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8));
|
||||
return bytesToHex(hash);
|
||||
|
||||
@@ -124,4 +124,10 @@ public class PortalApprovalManController extends BaseAnnotationController {
|
||||
}
|
||||
return ResponseEntity.ok(resultMap);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/approval/portalApprovalMan.json", params = "cmd=UPDATE")
|
||||
public ResponseEntity<Void> update(String id, String expectEndDate) {
|
||||
portalApprovalManService.update(id, expectEndDate);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +87,16 @@ public class PortalApprovalManService extends BaseService {
|
||||
* 마스킹된 상세 정보 조회
|
||||
*/
|
||||
public PortalApprovalUI selectDetail(String id) {
|
||||
//2026.06.05 관리자가 승인요청을 조회시 심사중으로 상태 변경
|
||||
//APP 유형이고 REQUESTED 상태인 경우 관리자 조회 시 PROCESSING으로 변경
|
||||
approvalService.findById(id).ifPresent(approval -> {
|
||||
if (approval.getApprovalType().equals(ApprovalType.APP)
|
||||
&& approval.getApprovalStatus() instanceof RequestedState) {
|
||||
approval.setApprovalStatus(new ProcessingState());
|
||||
approvalService.save(approval);
|
||||
}
|
||||
});
|
||||
|
||||
PortalApprovalUI result = getDetailWithMaskOption(id, false);
|
||||
if (result == null) {
|
||||
throw new IllegalArgumentException("승인 정보를 찾을 수 없습니다. ID: " + id);
|
||||
@@ -331,6 +341,13 @@ public class PortalApprovalManService extends BaseService {
|
||||
sendEvent(id, ApprovalEvent.DENY, options);
|
||||
}
|
||||
|
||||
public void update(String id, String expectEndDate) {
|
||||
Approval approval = approvalService.findById(id)
|
||||
.orElseThrow(() -> new IllegalArgumentException("승인 정보를 찾을 수 없습니다. ID: " + id));
|
||||
approval.setExpectEndDate(expectEndDate);
|
||||
approvalService.save(approval);
|
||||
}
|
||||
|
||||
public void redeploy(String id) {
|
||||
Map options = new HashMap<>();
|
||||
Approval approval = approvalService.findById(id).orElseThrow(() -> new IllegalArgumentException("승인 정보를 찾을 수 없습니다. ID: " + id));
|
||||
|
||||
@@ -38,6 +38,8 @@ public class PortalApprovalUI {
|
||||
@DateTimeFormat(pattern = "yyyyMMddHHmmssSSS")
|
||||
private String approvalDate;
|
||||
|
||||
private String expectEndDate;
|
||||
|
||||
public String getApprovalTypeDescription() {
|
||||
return approvalType != null ? approvalType.getDescription() : "";
|
||||
}
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package com.eactive.eai.rms.onl.apim.portalInquiry;
|
||||
|
||||
import com.eactive.apim.portal.qna.entity.Inquiry;
|
||||
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryCommentRepository;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryCommentService;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* RESPONDED 상태 문의글 중 아래 조건에 해당하는 경우 CLOSED로 변경한다.
|
||||
* - 조건 A: 활성 댓글이 없고 답변완료일(responseDate)로부터 N일 경과
|
||||
* - 조건 B: 마지막 관리자 댓글(adminYn=Y) 이후 N일간 포탈사용자(adminYn=N) 댓글 없음
|
||||
*/
|
||||
@Service
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class PortalInquiryClosingService {
|
||||
|
||||
private static final String RESPONDED = "RESPONDED";
|
||||
private static final String CLOSED = "CLOSED";
|
||||
|
||||
private final PortalInquiryService portalInquiryService;
|
||||
private final PortalInquiryCommentService portalInquiryCommentService;
|
||||
private final PortalInquiryCommentRepository inquiryCommentRepository;
|
||||
|
||||
public int closeExpiredInquiries(int closingDays) {
|
||||
LocalDateTime threshold = LocalDateTime.now().minusDays(closingDays);
|
||||
List<Inquiry> respondedInquiries = portalInquiryService.findByInquiryStatus(RESPONDED);
|
||||
|
||||
int closedCount = 0;
|
||||
for (Inquiry inquiry : respondedInquiries) {
|
||||
if (shouldClose(inquiry, threshold)) {
|
||||
inquiry.setInquiryStatus(CLOSED);
|
||||
portalInquiryService.save(inquiry);
|
||||
closedCount++;
|
||||
log.info("문의글 CLOSED 처리: id={}", inquiry.getId());
|
||||
}
|
||||
}
|
||||
log.info("InquiryCommentClosingService: 총 {}건 CLOSED 처리 (기준={}일)", closedCount, closingDays);
|
||||
return closedCount;
|
||||
}
|
||||
|
||||
private boolean shouldClose(Inquiry inquiry, LocalDateTime threshold) {
|
||||
long activeCommentCount = portalInquiryCommentService.countActiveByInquiryId(inquiry.getId());
|
||||
|
||||
// 댓글 없음 → 답변완료일 기준 N일 경과 여부만 확인
|
||||
if (activeCommentCount == 0) {
|
||||
LocalDateTime responseDate = inquiry.getResponseDate();
|
||||
return responseDate != null && !responseDate.isAfter(threshold);
|
||||
}
|
||||
|
||||
// 가장 최근 활성 댓글 확인
|
||||
Optional<InquiryComment> lastComment = inquiryCommentRepository
|
||||
.findTopByInquiry_IdAndDelYnOrderByCreatedDateDesc(inquiry.getId(), "N");
|
||||
|
||||
if (!lastComment.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 포탈사용자(adminYn != 'Y')가 마지막 댓글 작성자 → CLOSED 불가
|
||||
if (!"Y".equals(lastComment.get().getAdminYn())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 관리자가 마지막 댓글 작성자 → N일 경과 여부 확인
|
||||
LocalDateTime lastAdminDate = lastComment.get().getCreatedDate();
|
||||
return lastAdminDate != null && !lastAdminDate.isAfter(threshold);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.eactive.eai.rms.onl.apim.portalInquiry;
|
||||
|
||||
import com.eactive.apim.portal.file.entity.FileInfo;
|
||||
import com.eactive.eai.data.converter.LocalDateTimeFormatters;
|
||||
import com.eactive.eai.rms.onl.apim.portaluser.PortalUserUI;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@Data
|
||||
public class PortalInquiryCommentUI {
|
||||
|
||||
private String id;
|
||||
|
||||
private String inquiryId;
|
||||
|
||||
private String commentDetail;
|
||||
|
||||
private String delYn;
|
||||
|
||||
private String createdBy;
|
||||
|
||||
private String writerName;
|
||||
|
||||
private String lastModifiedBy;
|
||||
|
||||
@JsonFormat(pattern = LocalDateTimeFormatters.FORMAT_YYYYMMDDHHMMSS_14)
|
||||
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
||||
private LocalDateTime createdDate;
|
||||
|
||||
@JsonFormat(pattern = LocalDateTimeFormatters.FORMAT_YYYYMMDDHHMMSS_14)
|
||||
@DateTimeFormat(pattern = "yyyyMMddHHmmss")
|
||||
private LocalDateTime lastModifiedDate;
|
||||
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package com.eactive.eai.rms.onl.apim.portalInquiry;
|
||||
|
||||
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.ReportingPolicy;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
|
||||
public interface PortalInquiryCommentUIMapper {
|
||||
|
||||
@Mapping(target = "inquiryId", source = "inquiry.id")
|
||||
PortalInquiryCommentUI toVo(InquiryComment entity);
|
||||
|
||||
List<PortalInquiryCommentUI> toVoList(List<InquiryComment> entities);
|
||||
}
|
||||
+18
@@ -73,5 +73,23 @@ public class PortalInquiryManController extends BaseAnnotationController {
|
||||
portalInquiryManService.deleteBulk(ids);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/portalinquiry/portalInquiryMan.json", params = "cmd=LIST_COMMENT")
|
||||
public ResponseEntity<List<PortalInquiryCommentUI>> selectCommentList(String id) {
|
||||
return ResponseEntity.ok(portalInquiryManService.selectCommentList(id));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/portalinquiry/portalInquiryMan.json", params = "cmd=INSERT_COMMENT")
|
||||
public ResponseEntity<String> insertComment(HttpServletRequest request, PortalInquiryCommentUI portalInquiryCommentUI) {
|
||||
String userid = SessionManager.getUserId(request);
|
||||
portalInquiryManService.insertComment(portalInquiryCommentUI, userid);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/portalinquiry/portalInquiryMan.json", params = "cmd=DELETE_COMMENT")
|
||||
public ResponseEntity<Void> deleteComment(String id) {
|
||||
portalInquiryManService.deleteComment(id);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,10 +4,14 @@ import com.eactive.apim.portal.file.entity.FileInfo;
|
||||
import com.eactive.apim.portal.file.service.FileService;
|
||||
import com.eactive.apim.portal.portaluser.entity.PortalUser;
|
||||
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums;
|
||||
import com.eactive.apim.portal.portaluser.repository.PortalUserRepository;
|
||||
import com.eactive.apim.portal.qna.entity.Inquiry;
|
||||
import com.eactive.apim.portal.qna.entity.InquiryComment;
|
||||
import com.eactive.apim.portal.user.entity.UserInfo;
|
||||
import com.eactive.eai.rms.common.base.BaseService;
|
||||
import com.eactive.eai.rms.common.exception.IntegrationException;
|
||||
import com.eactive.eai.rms.data.entity.man.user.UserInfoService;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryCommentService;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquirySearch;
|
||||
import com.eactive.eai.rms.data.entity.onl.apim.portalinquiry.PortalInquiryService;
|
||||
import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
|
||||
@@ -22,27 +26,38 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
@Slf4j
|
||||
public class PortalInquiryManService extends BaseService {
|
||||
private final PortalInquiryService portalInquiryService;
|
||||
private final PortalInquiryCommentService portalInquiryCommentService;
|
||||
private final PortalInquiryUIMapper portalInquiryUIMapper;
|
||||
private final PortalInquiryCommentUIMapper portalInquiryCommentUIMapper;
|
||||
private final UserInfoService userInfoService;
|
||||
private final PortalUserRepository portalUserRepository;
|
||||
private final FileService fileService;
|
||||
|
||||
public static final String PENDING = "PENDING";
|
||||
public static final String RESPONDED = "RESPONDED";
|
||||
public static final String CLOSED = "CLOSED";
|
||||
|
||||
|
||||
public PortalInquiryManService(PortalInquiryService portalInquiryService,
|
||||
PortalInquiryCommentService portalInquiryCommentService,
|
||||
PortalInquiryUIMapper portalInquiryUIMapper,
|
||||
PortalInquiryCommentUIMapper portalInquiryCommentUIMapper,
|
||||
UserInfoService userInfoService,
|
||||
PortalUserRepository portalUserRepository,
|
||||
FileService fileService){
|
||||
this.portalInquiryService = portalInquiryService;
|
||||
this.portalInquiryCommentService = portalInquiryCommentService;
|
||||
this.portalInquiryUIMapper = portalInquiryUIMapper;
|
||||
this.portalInquiryCommentUIMapper = portalInquiryCommentUIMapper;
|
||||
this.userInfoService = userInfoService;
|
||||
this.portalUserRepository = portalUserRepository;
|
||||
this.fileService = fileService;
|
||||
}
|
||||
|
||||
@@ -55,6 +70,7 @@ public class PortalInquiryManService extends BaseService {
|
||||
if (ui.getInquirer() != null) {
|
||||
maskPortalInquiryUI(ui);
|
||||
}
|
||||
ui.setCommentCount((int) portalInquiryCommentService.countActiveByInquiryId(inquiry.getId()));
|
||||
return setInquiryAttachmentStatus(ui);
|
||||
});
|
||||
}
|
||||
@@ -141,6 +157,7 @@ public class PortalInquiryManService extends BaseService {
|
||||
UserInfo userinfo = userInfoService.getById(userId);
|
||||
|
||||
Inquiry inquiry = portalInquiryService.getById(portalInquiryUI.getId());
|
||||
validateNotClosed(inquiry);
|
||||
// 답변 대기중 상태일 경우만 답변완료로 상태 변경
|
||||
if(inquiry.getInquiryStatus().equals(PENDING)) {
|
||||
inquiry.setInquiryStatus(RESPONDED);
|
||||
@@ -161,5 +178,53 @@ public class PortalInquiryManService extends BaseService {
|
||||
List<String> idList = Arrays.asList(ids.split(","));
|
||||
portalInquiryService.deleteByIds(idList);
|
||||
}
|
||||
|
||||
public List<PortalInquiryCommentUI> selectCommentList(String inquiryId) {
|
||||
List<InquiryComment> comments = portalInquiryCommentService.findByInquiryId(inquiryId);
|
||||
List<PortalInquiryCommentUI> result = portalInquiryCommentUIMapper.toVoList(comments);
|
||||
result.forEach(ui -> ui.setWriterName(resolveWriterName(ui.getCreatedBy())));
|
||||
return result;
|
||||
}
|
||||
|
||||
private String resolveWriterName(String userId) {
|
||||
if (StringUtils.isBlank(userId)) return "";
|
||||
// 직원(내부 사용자) 여부 먼저 확인 → 이름 그대로 반환
|
||||
Optional<UserInfo> staff = userInfoService.findById(userId);
|
||||
if (staff.isPresent()) {
|
||||
return staff.get().getUsername();
|
||||
}
|
||||
// 포털 회원이면 이름 마스킹 처리 (김수민 → 김수*)
|
||||
Optional<PortalUser> portalUser = portalUserRepository.findById(userId);
|
||||
if (portalUser.isPresent()) {
|
||||
return MaskingUtils.maskName(portalUser.get().getUserName());
|
||||
}
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void insertComment(PortalInquiryCommentUI commentUI, String userId) {
|
||||
Inquiry inquiry = portalInquiryService.getById(commentUI.getInquiryId());
|
||||
validateNotClosed(inquiry);
|
||||
|
||||
InquiryComment comment = new InquiryComment();
|
||||
comment.setInquiry(inquiry);
|
||||
comment.setCommentDetail(commentUI.getCommentDetail());
|
||||
comment.setDelYn("N");
|
||||
comment.setAdminYn("Y");
|
||||
|
||||
portalInquiryCommentService.save(comment);
|
||||
}
|
||||
|
||||
public void deleteComment(String commentId) {
|
||||
InquiryComment comment = portalInquiryCommentService.getById(commentId);
|
||||
validateNotClosed(comment.getInquiry());
|
||||
comment.setDelYn("Y");
|
||||
portalInquiryCommentService.save(comment);
|
||||
}
|
||||
|
||||
private void validateNotClosed(Inquiry inquiry) {
|
||||
if (CLOSED.equals(inquiry.getInquiryStatus())) {
|
||||
throw new IntegrationException("답변종료되어 수정할 수 없습니다.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -55,4 +55,6 @@ public class PortalInquiryUI {
|
||||
private LocalDateTime lastModifiedDate;
|
||||
|
||||
private String orgName;
|
||||
|
||||
private int commentCount;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
package com.eactive.eai.rms.onl.common.service.ums;
|
||||
|
||||
import com.eactive.apim.portal.template.entity.MessageRequest;
|
||||
import com.eactive.apim.portal.template.repository.MessageRequestRepository;
|
||||
import com.eactive.ext.kjb.ums.KjbEmailSendModule;
|
||||
import com.eactive.ext.kjb.ums.KjbUmsService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
@@ -21,6 +7,23 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import com.eactive.apim.portal.template.entity.MessageRequest;
|
||||
import com.eactive.apim.portal.template.repository.MessageRequestRepository;
|
||||
import com.eactive.ext.djb.ums.DjbMessengerService;
|
||||
import com.eactive.ext.kjb.ums.KjbEmailSendModule;
|
||||
import com.eactive.ext.kjb.ums.KjbUmsService;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
@Slf4j
|
||||
@@ -67,15 +70,19 @@ public class UmsDispatchService {
|
||||
// KjbEmailSendModule.getInstance().setRepository(messageRequestRepository);
|
||||
log.info("UmsDispatchService initialized - KjbUmsService and KjbEmailSendModule ready via singleton");
|
||||
}
|
||||
|
||||
private DjbMessengerService getMessengerService() {
|
||||
return DjbMessengerService.getInstance();
|
||||
}
|
||||
|
||||
private KjbUmsService getUmsService() {
|
||||
return KjbUmsService.getInstance();
|
||||
}
|
||||
|
||||
private KjbEmailSendModule getEmailModule() {
|
||||
return KjbEmailSendModule.getInstance();
|
||||
}
|
||||
|
||||
// private KjbUmsService getUmsService() {
|
||||
// return KjbUmsService.getInstance();
|
||||
// }
|
||||
//
|
||||
// private KjbEmailSendModule getEmailModule() {
|
||||
// return KjbEmailSendModule.getInstance();
|
||||
// }
|
||||
//
|
||||
@SuppressWarnings("unchecked")
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
public void processMessages() {
|
||||
@@ -112,7 +119,7 @@ public class UmsDispatchService {
|
||||
|
||||
log.info("Starting to submit {} messages for processing", messagesToProcess.size());
|
||||
for (MessageRequest message : messagesToProcess) {
|
||||
//submitMessageTask(message);
|
||||
submitMessageTask(message);
|
||||
}
|
||||
} else {
|
||||
log.info("No pending messages found");
|
||||
@@ -123,62 +130,45 @@ public class UmsDispatchService {
|
||||
}
|
||||
|
||||
|
||||
// private void submitMessageTask(MessageRequest message) {
|
||||
// int queueSize = executorService.getQueue().size();
|
||||
// log.debug("Current queue size before submission: {}", queueSize);
|
||||
//
|
||||
// executorService.submit(() -> {
|
||||
// try {
|
||||
// transactionTemplate.execute(status -> {
|
||||
// try {
|
||||
// // 광주은행에서는 사용하지 않는 메소드
|
||||
//// processMessage(message);
|
||||
//
|
||||
// if (KjbUmsService.isAllowChannel(message)) {
|
||||
// getUmsService().send(message);
|
||||
// }
|
||||
//
|
||||
// if (KjbEmailSendModule.isAllowChannel(message)) {
|
||||
// getEmailModule().sendEmail(message);
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// } catch (Exception e) {
|
||||
// log.error("Failed to process message: {} - Error: {}",
|
||||
// message.getId(), e.getMessage(), e);
|
||||
// updateMessageStatus(message, "FAILED");
|
||||
// status.setRollbackOnly();
|
||||
// return null;
|
||||
// }
|
||||
// });
|
||||
// } catch (Exception e) {
|
||||
// log.error("Transaction execution failed for message: {} - Error: {}",
|
||||
// message.getId(), e.getMessage(), e);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
private void submitMessageTask(MessageRequest message) {
|
||||
int queueSize = executorService.getQueue().size();
|
||||
log.debug("Current queue size before submission: {}", queueSize);
|
||||
|
||||
/**
|
||||
* kbank 방식으로 광주은행에서는 사용하지 않음
|
||||
* @param message
|
||||
* @throws IOException
|
||||
*/
|
||||
// @Deprecated
|
||||
// public void processMessage(MessageRequest message) throws IOException {
|
||||
// try {
|
||||
// String standardMessage = messageFactory.createMessage(message);
|
||||
// log.debug("Processing message ID: {} - Type: {}", message.getId(), message.getMessageType());
|
||||
//
|
||||
// umsSender.sendMessage(standardMessage);
|
||||
// updateMessageStatus(message, "SENT");
|
||||
// log.debug("Successfully processed and sent message ID: {}", message.getId());
|
||||
// } catch (Exception e) {
|
||||
// log.error("Message processing failed for ID: {} - Error: {}",
|
||||
// message.getId(), e.getMessage(), e);
|
||||
// updateMessageStatus(message, "FAILED");
|
||||
// throw e;
|
||||
// }
|
||||
// }
|
||||
executorService.submit(() -> {
|
||||
try {
|
||||
transactionTemplate.execute(status -> {
|
||||
try {
|
||||
if (DjbMessengerService.isAllowChannel(message)) {
|
||||
getMessengerService().send(message);
|
||||
}
|
||||
if (KjbUmsService.isAllowChannel(message)) {
|
||||
getUmsService().send(message);
|
||||
}
|
||||
if (KjbEmailSendModule.isAllowChannel(message)) {
|
||||
getEmailModule().sendEmail(message);
|
||||
}
|
||||
updateMessageStatus(message, "SENT");
|
||||
return null;
|
||||
} catch (Exception e) {
|
||||
// checked exception을 RuntimeException으로 감싸 전파 → TransactionTemplate이 rollback 후 re-throw
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to process message: {} - Error: {}", message.getId(), e.getMessage(), e);
|
||||
try {
|
||||
transactionTemplate.execute(s -> {
|
||||
updateMessageStatus(message, "FAILED");
|
||||
return null;
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
log.error("Failed to update FAIL status for message: {}", message.getId(), ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void updateMessageStatus(MessageRequest message, String status) {
|
||||
message.setRequestStatus(status);
|
||||
|
||||
+8
@@ -85,4 +85,12 @@ public class InflowAdapterControlManController extends OnlBaseAnnotationControll
|
||||
return new ModelAndView("jsonView", resultMap);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/onl/admin/inflow/inflowAdapterControlMan.json", params = "cmd=LIST_BUCKET_STATUS")
|
||||
public ModelAndView getBucketStatus(HttpServletRequest request, HttpServletResponse response, String adapterId) {
|
||||
List<Map<String, Object>> statusList = service.getAdapterBucketStatus(adapterId);
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("servers", statusList);
|
||||
return new ModelAndView("jsonView", resultMap);
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -83,4 +83,12 @@ public class InflowClientControlManController extends OnlBaseAnnotationControlle
|
||||
return new ModelAndView("jsonView", resultMap);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/onl/admin/inflow/inflowClientControlMan.json", params = "cmd=LIST_BUCKET_STATUS")
|
||||
public ModelAndView getBucketStatus(HttpServletRequest request, HttpServletResponse response, String clientId) {
|
||||
List<Map<String, Object>> statusList = service.getClientBucketStatus(clientId);
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("servers", statusList);
|
||||
return new ModelAndView("jsonView", resultMap);
|
||||
}
|
||||
|
||||
}
|
||||
+75
@@ -1,12 +1,21 @@
|
||||
package com.eactive.eai.rms.onl.manage.inflow.inflow;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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.Service;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.eactive.eai.data.entity.onl.inflow.InflowControl;
|
||||
import com.eactive.eai.data.entity.onl.inflow.InflowControlId;
|
||||
@@ -14,10 +23,13 @@ import com.eactive.eai.rms.common.base.BaseService;
|
||||
import com.eactive.eai.rms.common.combo.ComboService;
|
||||
import com.eactive.eai.rms.data.entity.onl.inflow.InflowControlService;
|
||||
import com.eactive.eai.rms.data.entity.onl.inflow.InflowControlServiceDto;
|
||||
import com.eactive.eai.rms.onl.common.service.EaiServerInfoService;
|
||||
|
||||
@Service
|
||||
public class InflowControlManService extends BaseService {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(InflowControlManService.class);
|
||||
|
||||
private static final String ADAPTER_TYPE_INFLOW = "01";
|
||||
private static final String INTERFACE_TYPE_INFLOW = "02";
|
||||
private static final String CLIENT_TYPE_INFLOW = "03";
|
||||
@@ -32,6 +44,11 @@ public class InflowControlManService extends BaseService {
|
||||
@Autowired
|
||||
private InflowControlManMapper mapper;
|
||||
|
||||
@Autowired
|
||||
private EaiServerInfoService eaiServerInfoService;
|
||||
|
||||
private RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
// 어댑터 유량제어
|
||||
public Page<InflowControlManUI> selectAdapterList(Pageable pageable, String searchName) {
|
||||
Page<InflowControlServiceDto> dtoList = service.findAllForAdapter(pageable, searchName);
|
||||
@@ -123,6 +140,64 @@ public class InflowControlManService extends BaseService {
|
||||
InflowControlId id = toId(CLIENT_TYPE_INFLOW, name);
|
||||
service.findById(id).ifPresent(service::delete);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, Object>> getClientBucketStatus(String clientId) {
|
||||
return getBucketStatus("client", clientId, "클라이언트가 로드되지 않음", "클라이언트 버킷 상태 조회 실패");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, Object>> getAdapterBucketStatus(String adapterId) {
|
||||
return getBucketStatus("adapter", adapterId, "어댑터가 로드되지 않음", "어댑터 버킷 상태 조회 실패");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<Map<String, Object>> getInterfaceBucketStatus(String interfaceId) {
|
||||
return getBucketStatus("interface", interfaceId, "인터페이스가 로드되지 않음", "인터페이스 버킷 상태 조회 실패");
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<Map<String, Object>> getBucketStatus(String target, String targetId, String noDataMessage, String logPrefix) {
|
||||
List<Map<String, Object>> result = new ArrayList<>();
|
||||
List<Map<String, String>> serverList = eaiServerInfoService.getEaiServerIpList();
|
||||
|
||||
for (Map<String, String> server : serverList) {
|
||||
String serverName = server.get("EAISVRINSTNM");
|
||||
String serverIp = server.get("EAISVRIP");
|
||||
String serverPort = server.get("WEBSERVERPORT");
|
||||
|
||||
if (StringUtils.isEmpty(serverPort)) {
|
||||
serverPort = server.get("EAISVRLSNPORT");
|
||||
}
|
||||
|
||||
Map<String, Object> serverStatus = new HashMap<>();
|
||||
serverStatus.put("serverName", serverName);
|
||||
serverStatus.put("serverIp", serverIp);
|
||||
serverStatus.put("serverPort", serverPort);
|
||||
|
||||
try {
|
||||
String url = String.format("http://%s:%s/manage/inflow/%s/%s/bucket-status",
|
||||
serverIp, serverPort, target, targetId);
|
||||
ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);
|
||||
|
||||
if (response.getBody() != null && Boolean.TRUE.equals(response.getBody().get("success"))) {
|
||||
serverStatus.put("status", "online");
|
||||
serverStatus.put("data", response.getBody().get("data"));
|
||||
} else {
|
||||
serverStatus.put("status", "no_data");
|
||||
serverStatus.put("message", noDataMessage);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("{} - server: {}, error: {}", logPrefix, serverName, e.getMessage());
|
||||
serverStatus.put("status", "offline");
|
||||
serverStatus.put("message", "서버 연결 실패");
|
||||
}
|
||||
|
||||
result.add(serverStatus);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private InflowControlId toId(InflowControlManUI ui) {
|
||||
|
||||
+8
@@ -83,4 +83,12 @@ public class InflowInterfaceControlManController extends OnlBaseAnnotationContro
|
||||
return new ModelAndView("jsonView", resultMap);
|
||||
}
|
||||
|
||||
@RequestMapping(value = "/onl/admin/inflow/inflowInterfaceControlMan.json", params = "cmd=LIST_BUCKET_STATUS")
|
||||
public ModelAndView getBucketStatus(HttpServletRequest request, HttpServletResponse response, String interfaceId) {
|
||||
List<Map<String, Object>> statusList = service.getInterfaceBucketStatus(interfaceId);
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("servers", statusList);
|
||||
return new ModelAndView("jsonView", resultMap);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user