Merge branch 'jenkins_with_weblogic' of http://192.168.240.178:18080/eapim/eapim-admin.git into jenkins_with_weblogic

This commit is contained in:
cho
2026-02-20 16:01:47 +09:00
35 changed files with 471 additions and 460 deletions
@@ -24,7 +24,6 @@ function init(url){
dataType:"json",
data:{cmd: 'LIST_INIT_COMBO'},
success:function(json){
debugger;
//new makeOptions("CODE","NAME").setObj($("select[name=flovrSevrName]")).setNoValueInclude(true).setNoValue(' ','전체').setData(json.serverRows).rendering();
new makeOptions("CODE","NAME").setObj($("select[name=flovrSevrName]")).setData(json.serverRows).rendering();
detail(url);
@@ -29,7 +29,7 @@
}
$(document).ready(function() {
debugger;
//debugger;
init( detail);
$('#grid').jqGrid({
datatype:"json",
@@ -35,7 +35,6 @@
success : function(json) {
var data = json;
var detail = json.detail;
debugger;
// $("select[name=workGrpCd]").attr("disabled",true);
// $("select[name=sndRcvKind]").attr("disabled",true);
// $("select[name=adptrKind]").attr("disabled",true);
@@ -110,7 +110,7 @@
var name = $(this).attr("name");
var rowId = name.split("_")[2];
var rows = $('#grid').jqGrid('getGridParam','reccount');
debugger;
//debugger;
for ( var i = Number(rowId)+1 ; i <= rows; i ++){
var newVal = $('#grid').jqGrid('getCell',i,'MSGCLMNSEQ');
newVal = Number(newVal)-1;
@@ -154,7 +154,7 @@
var name = $(this).attr("name");
var rowId = name.split("_")[2];
var rows = $('#grid').jqGrid('getGridParam','reccount');
debugger;
//debugger;
for ( var i = Number(rowId)+1 ; i <= rows; i ++){
var newVal = $('#grid').jqGrid('getCell',i,'MSGCLMNSEQ');
newVal = Number(newVal)-1;
@@ -44,7 +44,6 @@ $(document).ready(function() {
var holdyYmd ="${param.holdyYmd}";
var holdyDstcd ="${param.holdyDstcd}";
var evntSchdrHoldyCtnt ="${param.evntSchdrHoldyCtnt}";
debugger;
if (holdyYmd != "" && holdyYmd !="null"){
isDetail = true;
}
@@ -76,7 +76,7 @@ function getOgranFile(key){
$("select[name=bjobMsgDstcd],select[name=osidInstiDstcd]").empty();
new makeOptions("CODE","NAME").setObj($("select[name=osidInstiDstcd]")).setData(json.osidInstiDstcd).rendering();
new makeOptions("CODE","NAME").setObj($("select[name=bjobMsgDstcd]")).setData(json.bjobMsgDstcd).rendering();
debugger;
//debugger;
if ( !isDetail ){
getBjobPtrnDstcd(key);
}else{
@@ -51,7 +51,7 @@ $(function(){
$(document).ready(function() {
var returnUrl = getReturnUrlForReturn();
debugger;
//debugger;
var key ="${param.infId}";
delFlag = "${param.delFlag}";
@@ -177,7 +177,7 @@ $(document).ready(function() {
$("#btn_modify").click(function(){
debugger;
//debugger;
if (!isValid())return;
if($("#grid tr#" + lastsel2).attr("editable") == 1){ //editable=1 means row in edit mode
$("#grid").saveRow(lastsel2,false,"clientArray");
@@ -92,7 +92,7 @@
url:url,
data:postData,
success:function(args){
debugger;
//debugger;
$("#grid").trigger("reloadGrid");
alert( args.result );
},
@@ -200,7 +200,7 @@ $(document).ready(function() {
},
gridComplete: function(){
debugger;
//debugger;
var ids = $(this).getDataIDs();
for(var i=0;i<ids.length;i++){
var cl = ids[i];
@@ -68,7 +68,7 @@ $(document).ready(function() {
},
loadError: function (jqXHR, textStatus, errorThrown) {
debugger
//debugger
if(jqXHR.status == 401) {
var location ='<%=request.getContextPath()%>/';
@@ -126,7 +126,7 @@ $(document).ready(function() {
postData.push({name:"adapterName" ,value:data["adapterName"]});
postData.push({name:"adapterType" ,value:data["adapterGroupSimple"].split('_')[3]}); // REST 타입 추가
// postData.push({name:"adapterType" ,value:"HTT"});
debugger;
//debugger;
var msgStartStop = control=='start'?'<%= localeMessage.getString("adapterStat.start") %>':'<%= localeMessage.getString("adapterStat.close") %>';
var resultConfirm = confirm(replaceMsg("<%= localeMessage.getString("common.confirmMsg1") %>",msgStartStop,data["adapterGroupName"],data["adapterName"]));
// // data["adapterGroupName"]+ " "+ data["adapterName"]+ "을\n\n"+ msgStartStop+ " 하시겠습니까?"
@@ -375,10 +375,20 @@
url:url,
data:postData,
success:function(args){
alert("<%=localeMessage.getString("common.saveMsg")%>");
if(isPop == "true"){
alert("<%=localeMessage.getString("common.saveMsg")%> \n저장 후 변환정보 수정이 필수입니다. 변환정보를 확인하세요");
const origin = window.location.origin;
const layoutName = $("input[name='loutName']").val();
parent.postMessage({
action: 'LAYOUT_SAVED_OPEN_TRANSFORM',
layoutPartName: '${param.layoutPartName}'
}, origin);
window.close();
} else {
alert("<%=localeMessage.getString("common.saveMsg")%>");
goNav(returnUrl);
}
},
@@ -880,7 +880,7 @@
});
$("input[name=auto]").click(function(){
debugger;
//debugger;
jsPlumbInstance.deleteEveryConnection();
const sourceData = sourceGrid.getRowData();
@@ -104,7 +104,7 @@ $(document).ready(function() {
resizeJqGridWidth('grid','title','1000');
$("#btn_close").click(function(){
debugger;
//debugger;
window.close();
});
$("body").css("overflow-x","hidden");
@@ -154,7 +154,7 @@ function w2GridToExcelSubmit(url_excel,cmd,gridObj,formObject,fileName){
// var form="<form action='"+url_excel+"' method='post' target='excelDown' accept-charset='utf-8' >";
var form="<form action='"+url_excel+"' method='post' target='excelDown'>";
$.each(postData,function(_,obj){
debugger;
//debugger;
form +="<input type='hidden' name='"+obj.name+"' value='"+obj.value+"'/>";
});
form += "</form>";
@@ -140,7 +140,7 @@ function w2GridToExcelSubmit(url_excel,cmd,gridObj,formObject,fileName){
// var form="<form action='"+url_excel+"' method='post' target='excelDown' accept-charset='utf-8' >";
var form="<form action='"+url_excel+"' method='post' target='excelDown'>";
$.each(postData,function(_,obj){
debugger;
//debugger;
form +="<input type='hidden' name='"+obj.name+"' value='"+obj.value+"'/>";
});
form += "</form>";
@@ -1153,19 +1153,46 @@
addLayoutBtnEvent('outboundErrResponse', '아웃바운드 오류', 'TGTE');
window.addEventListener('message', function(e) {
if (e.origin !== window.location.origin) return;
const popupMessage = e.data;
if('DELETE' == popupMessage.cmd){
if('layout' == popupMessage.type){
$('#'+popupMessage.layoutPartName).val('');
if (!popupMessage) return;
if ('DELETE' == popupMessage.cmd) {
if ('layout' == popupMessage.type) {
$('#' + popupMessage.layoutPartName).val('');
}
if('transform' == popupMessage.type){
if ('transform' == popupMessage.type) {
const partName = popupMessage.transformName.endsWith('REQ') ? '#requestTransform' : '#responseTransform';
$(partName).val('');
}
transformSetStateChange();
return;
}
// 레이아웃 저장 후 변환 팝업 자동 실행 로직
if (popupMessage.action === 'LAYOUT_SAVED_OPEN_TRANSFORM') {
// 눈이 보이지않는 팝업창 popup창 닫기
if ($('.ui-dialog-content').length > 0) {
$('.ui-dialog-content').dialog('close');
}
const part = popupMessage.layoutPartName || "";
setTimeout(function() {
if (part.includes('Request')) {
modifyTransform('request');
} else if (part.includes('Response')) {
modifyTransform('response');
} else if (part.includes('ErrResponse')) {
modifyTransform('errResponse');
}
}, 300);
}
});
// modifyLayout('inboundRequestLayout', '인바운드 요청', 'CBSS')
$('#requestTransformButton').on("click", function(event) {
modifyTransform('request');
});
@@ -1175,7 +1202,6 @@
$('#errResponseTransformButton').on("click", function(event) {
modifyTransform('errResponse');
});
// modifyLayout('inboundRequestLayout', '인바운드 요청', 'CBSS')
// 함수 사용 예시에 인바운드 응답 처리 추가
$("#fromAdapter").change(function() {
@@ -15,6 +15,14 @@
<jsp:include page="/jsp/common/include/css.jsp"/>
<jsp:include page="/jsp/common/include/script.jsp"/>
<style>
#tab4 div {
display: block;
overflow-wrap: break-word;
word-break: break-all;
white-space: normal;
}
</style>
<script language="javascript" >
// var eaiBzwkDstcd = window.dialogArguments["eaiBzwkDstcd"];
@@ -30,6 +38,7 @@
let fullMessageData;
let layoutInfo = [];
let bzwkdatatntInfo;
var isPrettyView = false;
var eaiSvcCode = "";
@@ -364,10 +373,6 @@
$('#btn_pretty_body').click(function(){
const syntax = $('#selectBodySyntax').val();
// FLAT view를 위해 생성된 데이터 -> 기존 업무데이터
bodyCodeEditor.setValue(bzwkdatatntInfo);
const value = bodyCodeEditor.getValue();
let prettyValue = value;
if(syntax === 'JSN'){
@@ -407,7 +412,6 @@
$('#btn_pretty_body').css('display', 'block');
bodyCodeEditor.setOption("mode", "application/json");
}else if(syntax === 'XML'){
$('#btn_pretty_body').css('display', 'block');
$('#btn_pretty_body').css('display', 'block');
bodyCodeEditor.setOption("mode", "application/xml");
}else{
@@ -805,78 +809,101 @@ $(document).ready(function() {
alert('전체 전문 복사되었습니다.')
});
// FLAT 데이터를 전문정보로 잘라서 JSON / XML VIEW 로 볼 수 있는 버튼
$('#btn_convert_view').click(function() {
var type = $('select[id=selectBodySyntax]').val();
if (!fullMessageData || !layoutInfo) {
alert("데이터가 없습니다.");
$('#btn_pretty_print').click(function () {
var $button = $(this);
// Pretty View → 원본 복구
if (typeof isPrettyView !== 'undefined' && isPrettyView) {
var originalData = (typeof bzwkdatatntInfo !== 'undefined')
? bzwkdatatntInfo
: "";
if (typeof bodyCodeEditor !== 'undefined') {
bodyCodeEditor.setValue(originalData);
}
isPrettyView = false;
$button.text("PRETTY_PRINT");
return;
}
parserCommon(fullMessageData, layoutInfo, type);
});
var intrefaceId = ($("input[name=eaiSvcName]").val() || "").trim();
var logProcessNo = ($("input[name=logPrcssSerno]").val() || "").trim();
var bizData = (typeof bzwkdatatntInfo !== 'undefined')
? bzwkdatatntInfo
: "";
function parserCommon(flatData, layoutInfo, type) {
var cursor = 0;
var parsedList = [];
var error = false;
layoutInfo.forEach(function(field) {
var fieldLen = field.length;
if (fieldLen > 0) {
var rawValue = flatData.substring(cursor, cursor + fieldLen);
parsedList.push({
engName: field.name,
korName: field.desc || field.name,
value: rawValue // trim 금지.
});
cursor += fieldLen;
}
});
// CodeMirror 에디터에 값 세팅
var finalString = "";
if (type == "JSN") {
var jsonResult = {};
parsedList.forEach(function(item) {
jsonResult[item.engName] = {
"한글명": item.korName,
"값": item.value
};
});
finalString = JSON.stringify(jsonResult, null, 4);
} else if (type == "XML") {
var xmlResult = "<Root>\n";
parsedList.forEach(function(item) {
var cleanTagName = item.korName.replace(/[^a-zA-Z0-9가-힣]/g, "");
if (!cleanTagName) cleanTagName = item.engName;
xmlResult += "\t<" + cleanTagName + ">" + item.value + "</" + cleanTagName + ">\n";
});
xmlResult += "</Root>";
finalString = xmlResult;
} else {
finalString = flatData;
if (!intrefaceId || !logProcessNo || !bizData) {
alert("필수값이 누락되어 조회가 불가능합니다.");
return;
}
bodyCodeEditor.setValue(finalString);
$('#selectBodySyntax').val(type).trigger('change');
$.ajax({
type: "POST",
url: url,
dataType: "json",
data: {
cmd: "DETAIL_PRETTY_VIEW",
intrefaceId: intrefaceId,
logProcessNo: logProcessNo,
bizData: bizData
},
// console.log("변환 완료:", parsedList);
}
success: function (response) {
var xmlString = response.result;
if (xmlString) {
if (typeof bodyCodeEditor !== 'undefined') {
bodyCodeEditor.setValue(xmlString);
}
$('#selectBodySyntax')
.val('XML')
.trigger('change');
isPrettyView = true;
$button.text("업무데이터 보기");
} else {
alert("변환된 데이터 내용이 없습니다.");
}
},
error: function (xhr, status, error) {
console.error("AJAX Error:", xhr);
var errorMsg = "처리 중 오류가 발생했습니다.";
if (xhr.responseJSON) {
var errResponse = xhr.responseJSON;
if (errResponse.result) {
errorMsg = errResponse.result;
}
else if (errResponse.message) {
errorMsg = errResponse.message;
}
}
// JSON 파싱 실패 대비
else if (xhr.responseText) {
errorMsg = xhr.responseText;
}
alert(errorMsg);
}
});
});
});
</script>
@@ -919,14 +946,14 @@ html,hbody {
<td style="width:30%;"><input type="text" name="msgDpstYMS" readonly="readonly"/> </td>
</tr>
<tr>
<th><%=localeMessage.getString("trackingDetail.eaiSvcName")%></th><td><input type="text" name="eaiSvcName" readonly="readonly" />
<th>API ID</th><td><input type="text" name="eaiSvcName" readonly="readonly" />
<%-- <img src="<c:url value="/images/bt/pop_detail.gif"/>" alt="" id="eaiSvcName" class="eaiSvcName_btn" /> --%>
<%-- <button type="button" class="cssbtn smallBtn2" id="eaiSvcName" style="vertical-align:middle; font-weight:bold;"><i class="material-icons">details</i><%= localeMessage.getString("button.detail") %></button>--%>
</td>
<th><%=localeMessage.getString("trackingDetail.msgPrcssYMS")%></th><td><input type="text" name="msgPrcssYMS" readonly="readonly"/> </td>
</tr>
<tr>
<th><%=localeMessage.getString("trackingDetail.eaiSvcDesc")%></th><td><input type="text" name="eaiSvcDesc" readonly="readonly"/> </td>
<th>API 명</th><td><input type="text" name="eaiSvcDesc" readonly="readonly"/> </td>
<th>ORG GUID</th><td><input type="text" name="pguid" readonly="readonly"/> </td>
</tr>
<tr>
@@ -994,7 +1021,7 @@ html,hbody {
<button type="button" class="cssbtn" id="btn_pretty_body" ><i class="material-icons">format_align_left</i> <%= localeMessage.getString("trackingDetail.btnMakePretty") %></button>
</td>
<td>
<button type="button" class="cssbtn" id="btn_convert_view" ><i class="material-icons">format_align_left</i>FLAT_View</button>
<button type="button" class="cssbtn" id="btn_pretty_print" ><i class="material-icons">format_align_left</i>PRETTY_PRINT</button>
</td>
<td style="text-align: right;">
<span style="text-align: center;">
@@ -23,7 +23,7 @@
var serviceType = null;
var guid = null;
//alert(window.dialogArguments.length);
debugger;
//debugger;
if(window.dialogArguments != null && window.dialogArguments != undefined){
eaiBzwkDstcd = window.dialogArguments["eaiBzwkDstcd"];
msgDpstYMS = window.dialogArguments["msgDpstYMS"];
@@ -1675,7 +1675,7 @@ $(document).ready(function () {
});
$("input[name=srcLayout],[name=tgtLayout]").dblclick(function(){
debugger;
//debugger;
var layoutName = $(this).val();
if($.trim(layoutName) =="") return;
+1 -1
View File
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx2g
org.gradle.jvmargs=-Xmx4g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configureondemand=true
Binary file not shown.
@@ -10,6 +10,7 @@ import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@@ -33,6 +34,16 @@ public class GlobalExceptionController {
.map(SQLException::getMessage)
.orElse("");
errMsg = errMsg + "중복 KEY 에러발생.\n자세한 사항은 관리자에게 문의바랍니다. ";
} else if (e instanceof DataIntegrityViolationException) {
errMsg = "입력값이 올바르지 않습니다. 필수 항목을 확인해주세요.";
} else if (e instanceof DataAccessException) {
errMsg = "데이터베이스 처리 중 오류가 발생했습니다.";
} else if (e instanceof SQLException) {
errMsg = "데이터베이스 처리 중 오류가 발생했습니다.";
}
if (errMsg != null && (errMsg.contains("NestedSQLException") || errMsg.contains("nested exception"))) {
errMsg = "데이터베이스 처리 중 오류가 발생했습니다.";
}
if (request.getServletPath().endsWith(".json")) {
@@ -46,20 +57,21 @@ public class GlobalExceptionController {
}
}
@ExceptionHandler(RuntimeException.class)
public ModelAndView handleBizException(Exception e, HttpServletRequest request, HttpServletResponse response) {
logger.error("GlobalExceptionController] handleBizException ", e);
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
if (request.getServletPath().endsWith(".json")) {
HashMap resultMap = new HashMap();
resultMap.put("status", "fail");
resultMap.put("errorMsg", e.getMessage());
ModelAndView modelAndView = new ModelAndView("jsonView", resultMap);
return modelAndView;
} else {
return null;
}
}
// 26.02.10 - 웹취약점 관련(시스템 운영정보 노출, Exception 과 보다 먼저 처리되어 필요성이 없는듯하여 주석으로 삭제 처리
// @ExceptionHandler(RuntimeException.class)
// public ModelAndView handleBizException(Exception e, HttpServletRequest request, HttpServletResponse response) {
// logger.error("GlobalExceptionController] handleBizException ", e);
// response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
//
// if (request.getServletPath().endsWith(".json")) {
// HashMap resultMap = new HashMap();
// resultMap.put("status", "fail");
// resultMap.put("errorMsg", e.getMessage());
// ModelAndView modelAndView = new ModelAndView("jsonView", resultMap);
// return modelAndView;
// } else {
// return null;
// }
// }
}
@@ -795,7 +795,7 @@ public class MainController implements InterceptorSkipController {
// 3. 비밀번호 체크
if (!userInfo.getPassword().equals(Seed.encrypt(resetPassword))
&& !userInfo.getUserid().equals(resetUserId)) {
|| !userInfo.getUserid().equals(resetUserId)) {
UserAccessLogger.log(request, LOG_CATEGORY_LOGIN, "F",
localeMessage
.getString("login.pwdmismatch5"));
@@ -2,6 +2,9 @@ package com.eactive.eai.rms.data.entity.onl.apim.obp;
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
import com.eactive.apim.portal.obp.repository.ObpGwMetricRepository;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -50,6 +53,24 @@ public class ObpGwMetricService {
return repository.findByTimesliceGreaterThanEqual(timeslice);
}
/**
* 특정 시간대 이후의 GwMetric 데이터 조회 (row 제한)
*
* @param timeslice 조회 시작 시간대
* @param limit 최대 조회 건수 (0이면 무제한)
* @return 조회된 지표 목록 (timeslice ASC 정렬)
*/
public List<ObpGwMetric> findByTimesliceGreaterThanEqual(LocalDateTime timeslice, int limit) {
if (limit <= 0) {
// 무제한 조회 (기존 동작 유지)
return repository.findByTimesliceGreaterThanEqual(timeslice);
} else {
// 제한적 조회 (timeslice ASC 정렬 + limit)
Pageable pageable = PageRequest.of(0, limit, Sort.by(Sort.Order.asc("timeslice")));
return repository.findByTimesliceGreaterThanEqual(timeslice, pageable);
}
}
/**
* 엔티티 저장 (INSERT 또는 UPDATE)
*/
@@ -118,21 +118,23 @@ public class EAILogRepositoryImpl implements EAILogRepository {
.where(qeaiLog.id.logprcssserno.eq(eaiLogSearch.getSearchLogPrcssSerno()));
return;
}
if (StringUtils.isNotBlank(eaiLogSearch.getSearchStartTime())) {
query
boolean hasSvcSerno = StringUtils.isNotBlank(eaiLogSearch.getSearchEaiSvcSerno());
if (hasSvcSerno) {
query.where(qeaiLog.id.eaisvcserno.contains(eaiLogSearch.getSearchEaiSvcSerno()));
} else {
if (StringUtils.isNotBlank(eaiLogSearch.getSearchStartTime())) {
query
.where(qeaiLog.id.msgdpstyms
.between(eaiLogSearch.getSearchStartTime(), eaiLogSearch.getSearchEndTime()));
.between(eaiLogSearch.getSearchStartTime(), eaiLogSearch.getSearchEndTime()));
}
}
if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiBzwkDstcd())) {
query.where(qeaiLog.id.eaibzwkdstcd.eq(eaiLogSearch.getSearchEaiBzwkDstcd()));
}
if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiSvcSerno())) {
query.where(qeaiLog.id.eaisvcserno.contains(eaiLogSearch.getSearchEaiSvcSerno()));
}
if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiSvcName())) {
query.where(qeaiLog.eaisvcname.containsIgnoreCase(eaiLogSearch.getSearchEaiSvcName()));
}
@@ -7,8 +7,9 @@ import com.eactive.ext.kjb.common.KjbPropertyHolder;
import com.eactive.ext.kjb.common.KjbUmsException;
import com.eactive.ext.kjb.ums.KjbUmsService;
import com.eactive.ext.kjb.ums.UmsBizWorkCode;
import com.eactive.ext.kjb.ums.gson.IUmsGsonObject;
import com.eactive.ext.kjb.ums.gson.GsonUtil;
import com.eactive.ext.kjb.ums.gson.VerifyPhoneUmsTemplate;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -121,8 +122,7 @@ public class SmsAuthService {
String guid = String.format("EAPIM_EMS-%s",
DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS").format(LocalDateTime.now()));
IUmsGsonObject content = null;
content = VerifyPhoneUmsTemplate.builder().authNumber(authCode).build();
JsonObject content = GsonUtil.toJsonObject(VerifyPhoneUmsTemplate.builder().authNumber(authCode).build());
getUmsService().sendKakaoAlimTalk(guid, UmsBizWorkCode.VERIFY_PHONE, cleanedPhone, content);
log.info("SMS 인증번호 발송 완료 - guid: {}, phone: {}****{}",
@@ -1,137 +0,0 @@
package com.eactive.eai.rms.onl.apim.obp;
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
import com.google.gson.annotations.SerializedName;
import lombok.Data;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* ObpGwMetric JSON 응답 DTO (after-timeslice 엔드포인트용)
*
* <p>예시 출력 형식에 맞춤:</p>
* <pre>
* {
* "apiId": "1ba56b82-a9c9-41e2-b3ab-ff9377667d56",
* "apiName": "[해외송금] 가상계좌 입금실패 정보조회",
* "apiRoutingUri": "/api/obs/remittance/remittancefail*",
* "httpMethod": "POST",
* "orgId": "ORG001",
* "partnerCode": "000008-01",
* "appId": "APP001",
* "appKey": "l7xx2fd7efc523794be5a1b126873a5de613",
* "requestUri": "-1",
* "timeslice": "2025-12-02T03:00:00.000+0000",
* "attemptedCount": 3,
* "completedCount": 3
* }
* </pre>
*/
@Data
public class ObpGwMetricAfterDTO {
private static final DateTimeFormatter ISO8601_MILLIS_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'+0000'");
@SerializedName("apiId")
private String apiId;
@SerializedName("apiName")
private String apiName;
@SerializedName("apiRoutingUri")
private String apiRoutingUri;
@SerializedName("httpMethod")
private String httpMethod;
@SerializedName("orgId")
private String orgId;
@SerializedName("partnerCode")
private String partnerCode;
@SerializedName("appId")
private String appId;
@SerializedName("appKey")
private String appKey;
@SerializedName("requestUri")
private String requestUri;
@SerializedName("timeslice")
private String timeslice;
@SerializedName("attemptedCount")
private Long attemptedCount;
@SerializedName("completedCount")
private Long completedCount;
// AS-IS 호환을 위한 필드 (null 값으로 리턴)
@SerializedName("clusterHostname")
private String clusterHostname = null;
@SerializedName("apiDatabaseId")
private Integer apiDatabaseId = null;
@SerializedName("unauthorizedCount")
private Integer authorizedCount = null;
@SerializedName("backMinTime")
private Integer backMinTime = null;
@SerializedName("backMaxTime")
private Integer backMaxTime = null;
@SerializedName("backSumTime")
private Integer backSumTime = null;
@SerializedName("frontMinTime")
private Integer frontMinTime = null;
@SerializedName("frontMaxTime")
private Integer frontMaxTime = null;
@SerializedName("frontSumTime")
private Integer frontSumTime = null;
/**
* Entity DTO 변환
*/
public static ObpGwMetricAfterDTO from(ObpGwMetric entity) {
ObpGwMetricAfterDTO dto = new ObpGwMetricAfterDTO();
dto.setApiId(entity.getApiId());
dto.setApiName(entity.getApiName());
dto.setApiRoutingUri(entity.getUri());
dto.setHttpMethod(entity.getMethod());
dto.setOrgId(entity.getOrgId());
dto.setPartnerCode(entity.getPartnerCode());
dto.setAppId(entity.getAppId());
dto.setAppKey(entity.getClientId());
dto.setRequestUri(entity.getRequestUri());
dto.setTimeslice(formatTimeslice(entity.getTimeslice()));
dto.setAttemptedCount(entity.getAttemptedCount());
dto.setCompletedCount(entity.getCompletedCount());
// 260224 - AS-IS 개발자포탈에서 쓰이던 ID 필드 삭제(OBP 디비 필드 형식과 맞지 않음)
dto.setOrgId(null);
dto.setAppId(null);
return dto;
}
/**
* timeslice를 ISO8601 형식 (밀리초 포함) + UTC 시간대로 변환
* : 2025-12-02T03:00:00.000+0000
*/
private static String formatTimeslice(LocalDateTime timeslice) {
if (timeslice == null) return null;
return timeslice.format(ISO8601_MILLIS_FORMATTER);
}
}
@@ -55,12 +55,12 @@ public class ObpGwMetricController extends BaseRestController {
produces = JSON_CONTENT_TYPE
)
@ResponseBody
public String getGwMetricsAfterTimesliceV2(
public String getGwMetricsAfterTimeslice(
@PathVariable("timeslice") String timeslice,
@PathVariable("providerCode") String providerCode,
@RequestParam(value = "pretty", required = false) Boolean pretty) {
log.debug("GwMetric after-timeslice 조회 요청 (v2): timeslice={}, providerCode={}, pretty={}",
log.debug("GwMetric after-timeslice 조회 요청: timeslice={}, providerCode={}, pretty={}",
timeslice, providerCode, pretty);
long startTime = System.currentTimeMillis();
@@ -85,7 +85,7 @@ public class ObpGwMetricController extends BaseRestController {
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.MONITORING));
// 5. 데이터 조회
List<ObpGwMetricAfterDTO> metrics = obpGwMetricManService.findByTimesliceAfter(timesliceHour);
List<ObpGwMetricDTO> metrics = obpGwMetricManService.findByTimesliceAfter(timesliceHour);
// 6. JSON 변환
String json = toJson(metrics, pretty);
@@ -104,90 +104,4 @@ public class ObpGwMetricController extends BaseRestController {
throw new BizException("Failed to retrieve metrics: " + e.getMessage(), e);
}
}
/**
* 특정 시간대의 GwMetric 데이터 조회
*
* @param datetime 조회 시간대 (형식: yyyy-MM-dd_HH:mm:ss)
* @param pretty true면 JSON 들여쓰기 적용
* @return JSON Array
*/
@RequestMapping(
value = "/kjb/gw-metrics/{datetime}.json",
produces = JSON_CONTENT_TYPE
)
@ResponseBody
public String getGwMetrics(
@PathVariable("datetime") String datetime,
@RequestParam(value = "pretty", required = false) Boolean pretty) {
log.debug("GwMetric 조회 요청: datetime={}, pretty={}", datetime, pretty);
long startTime = System.currentTimeMillis();
try {
// Path 파라미터 파싱
LocalDateTime targetTime = LocalDateTime.parse(datetime, PATH_FORMATTER);
LocalDateTime timeslice = targetTime.withMinute(0).withSecond(0).withNano(0);
// 조회
List<ObpGwMetricDTO> metrics = obpGwMetricManService.findByTimeslice(timeslice);
// JSON 변환 (GSON)
String json = toJson(metrics, pretty);
long elapsed = System.currentTimeMillis() - startTime;
log.info("GwMetric 조회 완료: datetime={}, count={}, size={}, elapsed={}ms",
datetime, metrics.size(), getFormattedJsonSize(json), elapsed);
return json;
} catch (Exception e) {
log.error("GwMetric 조회 실패: datetime={}", datetime, e);
throw e;
}
}
/**
* 특정 시간대 이후의 GwMetric 데이터 조회
*
* @param datetime 조회 시작 시간대 (형식: yyyy-MM-dd_HH:mm:ss)
* @param pretty true면 JSON 들여쓰기 적용
* @return JSON Array (해당 시간대 이후의 모든 지표)
* @deprecated Use {@link #getGwMetricsAfterTimesliceV2(String, String, Boolean)} instead.
* Migrate to /api/metrics/afterTimeslice/{timeslice}/{providerCode}
* Will be removed in next major version.
*/
@Deprecated
@RequestMapping(
value = "/kjb/gw-metrics/after-timeslice/{datetime}.json",
produces = JSON_CONTENT_TYPE
)
@ResponseBody
public String getGwMetricsAfterTimeslice(
@PathVariable("datetime") String datetime,
@RequestParam(value = "pretty", required = false) Boolean pretty) {
log.debug("GwMetric after-timeslice 조회 요청: datetime={}, pretty={}", datetime, pretty);
long startTime = System.currentTimeMillis();
try {
// Path 파라미터 파싱
LocalDateTime targetTime = LocalDateTime.parse(datetime, PATH_FORMATTER);
LocalDateTime timeslice = targetTime.withMinute(0).withSecond(0).withNano(0);
// 조회
List<ObpGwMetricAfterDTO> metrics = obpGwMetricManService.findByTimesliceAfter(timeslice);
// JSON 변환 (GSON)
String json = toJson(metrics, pretty);
long elapsed = System.currentTimeMillis() - startTime;
log.info("GwMetric after-timeslice 조회 완료: datetime={}, count={}, size={}, elapsed={}ms",
datetime, metrics.size(), getFormattedJsonSize(json), elapsed);
return json;
} catch (Exception e) {
log.error("GwMetric after-timeslice 조회 실패: datetime={}", datetime, e);
throw e;
}
}
}
@@ -8,32 +8,61 @@ import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* ObpGwMetric JSON 응답 DTO
* Entity 주석에 명시된 JSON Key 사용
* ObpGwMetric JSON 응답 DTO (after-timeslice 엔드포인트용)
*
* <p>예시 출력 형식에 맞춤:</p>
* <pre>
* {
* "apiId": "1ba56b82-a9c9-41e2-b3ab-ff9377667d56",
* "apiName": "[해외송금] 가상계좌 입금실패 정보조회",
* "apiRoutingUri": "/api/obs/remittance/remittancefail*",
* "httpMethod": "POST",
* "orgId": "ORG001",
* "partnerCode": "000008-01",
* "appId": "APP001",
* "appKey": "l7xx2fd7efc523794be5a1b126873a5de613",
* "requestUri": "-1",
* "timeslice": "2025-12-02T03:00:00.000+0000",
* "attemptedCount": 3,
* "completedCount": 3
* }
* </pre>
*/
@Data
public class ObpGwMetricDTO {
private static final DateTimeFormatter ISO8601_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss'+0000'");
private static final DateTimeFormatter ISO8601_MILLIS_FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'+0900'");
@SerializedName("appKey")
private String clientId;
@SerializedName("clusterHostname")
private String hostname;
@SerializedName("timeslice")
private String timeslice;
@SerializedName("apiId")
private String apiId;
@SerializedName("apiName")
private String apiName;
@SerializedName("apiRoutingUri")
private String uri;
private String apiRoutingUri;
@SerializedName("httpMethod")
private String method;
private String httpMethod;
@SerializedName("orgId")
private String orgId;
@SerializedName("partnerCode")
private String partnerCode;
@SerializedName("appId")
private String appId;
@SerializedName("appKey")
private String appKey;
@SerializedName("requestUri")
private String requestUri;
@SerializedName("timeslice")
private String timeslice;
@SerializedName("attemptedCount")
private Long attemptedCount;
@@ -41,62 +70,68 @@ public class ObpGwMetricDTO {
@SerializedName("completedCount")
private Long completedCount;
// EAPIM ID
@SerializedName("apiIdByEapim")
private String apiId;
@SerializedName("appIdByEapim")
private String appId;
// AS-IS 호환을 위한 필드 (null 값으로 리턴)
@SerializedName("clusterHostname")
private String clusterHostname = null;
@SerializedName("orgIdByEapim")
private String orgId;
@SerializedName("apiDatabaseId")
private Integer apiDatabaseId = null;
// AS-IS 호환용 필드
@SerializedName("appId")
private String appIdByCaPortal;
@SerializedName("unauthorizedCount")
private Integer authorizedCount = null;
@SerializedName("portalOrgId")
private String orgIdByCaPortal;
@SerializedName("backMinTime")
private Integer backMinTime = null;
@SerializedName("portalApiId")
private String apiIdByCaPortal;
@SerializedName("backMaxTime")
private Integer backMaxTime = null;
@SerializedName("partnerCode")
private String partnerCode;
@SerializedName("backSumTime")
private Integer backSumTime = null;
@SerializedName("frontMinTime")
private Integer frontMinTime = null;
@SerializedName("frontMaxTime")
private Integer frontMaxTime = null;
@SerializedName("frontSumTime")
private Integer frontSumTime = null;
@SerializedName("apiId")
private String apiIdByCa;
/**
* Entity DTO 변환
*/
public static ObpGwMetricDTO from(ObpGwMetric entity) {
ObpGwMetricDTO dto = new ObpGwMetricDTO();
dto.setClientId(entity.getClientId());
dto.setHostname(entity.getHostname());
dto.setTimeslice(formatTimeslice(entity.getTimeslice()));
dto.setApiId(entity.getApiId());
dto.setApiName(entity.getApiName());
dto.setUri(entity.getUri());
dto.setMethod(entity.getMethod());
dto.setApiRoutingUri(entity.getUri());
dto.setHttpMethod(entity.getMethod());
dto.setOrgId(entity.getOrgId());
dto.setPartnerCode(entity.getPartnerCode());
dto.setAppId(entity.getAppId());
dto.setAppKey(entity.getClientId());
dto.setRequestUri(entity.getRequestUri());
dto.setTimeslice(formatTimeslice(entity.getTimeslice()));
dto.setAttemptedCount(entity.getAttemptedCount());
dto.setCompletedCount(entity.getCompletedCount());
dto.setApiId(entity.getApiId());
dto.setAppId(entity.getAppId());
dto.setOrgId(entity.getOrgId());
dto.setAppIdByCaPortal(entity.getAppIdByCaPortal());
dto.setOrgIdByCaPortal(entity.getOrgIdByCaPortal());
dto.setApiIdByCaPortal(entity.getApiIdByCaPortal());
dto.setPartnerCode(entity.getPartnerCode());
dto.setApiIdByCa(entity.getApiIdByCa());
// 260224 - AS-IS 개발자포탈에서 쓰이던 ID 필드 삭제(OBP 디비 필드 형식과 맞지 않음)
dto.setOrgId(null);
dto.setAppId(null);
return dto;
}
/**
* timeslice를 ISO8601 형식 + UTC 시간대로 변환
* : 2025-12-02T01:00:00+0000
* timeslice를 ISO8601 형식 (밀리초 포함) + UTC 시간대로 변환
* : 2025-12-02T03:00:00.000+0000
*/
private static String formatTimeslice(LocalDateTime timeslice) {
if (timeslice == null) return null;
return timeslice.format(ISO8601_FORMATTER);
return timeslice.format(ISO8601_MILLIS_FORMATTER);
}
}
@@ -10,6 +10,7 @@ import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricJpaDAO;
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricService;
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricVO;
import com.eactive.ext.kjb.common.KjbPropertyHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
@@ -311,30 +312,32 @@ public class ObpGwMetricManService extends BaseService {
return entity;
}
/**
* 특정 시간대의 GwMetric 데이터 조회 (REST API용)
*/
public List<ObpGwMetricDTO> findByTimeslice(LocalDateTime timeslice) {
DataSourceContextHolder.setDataSourceType(
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.MONITORING));
List<ObpGwMetric> entities = obpGwMetricService.findByTimeslice(timeslice);
return entities.stream()
.map(ObpGwMetricDTO::from)
.collect(Collectors.toList());
}
/**
* 특정 시간대 이후의 GwMetric 데이터 조회 (REST API용)
* after-timeslice 엔드포인트에서 사용
*
* <p>조회 범위 제한:</p>
* <ul>
* <li>pageSize 값을 KjbProperty.apiGwMetricPageSize에서 읽어옴 (기본값: 10000)</li>
* <li>0일 경우 무제한 조회</li>
* <li>정렬: timeslice ASC (오래된 데이터부터 반환)</li>
* </ul>
*/
public List<ObpGwMetricAfterDTO> findByTimesliceAfter(LocalDateTime timeslice) {
public List<ObpGwMetricDTO> findByTimesliceAfter(LocalDateTime timeslice) {
DataSourceContextHolder.setDataSourceType(
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.MONITORING));
List<ObpGwMetric> entities = obpGwMetricService.findByTimesliceGreaterThanEqual(timeslice);
// KjbProperty에서 pageSize 읽기
Integer pageSize = KjbPropertyHolder.get().getApiGwMetricPageSize();
if (pageSize == null) {
pageSize = 10000; // 기본값 (null 안전 처리)
}
// Service 호출 (limit 적용)
List<ObpGwMetric> entities = obpGwMetricService.findByTimesliceGreaterThanEqual(timeslice, pageSize);
return entities.stream()
.map(ObpGwMetricAfterDTO::from)
.map(ObpGwMetricDTO::from)
.collect(Collectors.toList());
}
@@ -156,6 +156,11 @@ public class PortalUserManService extends BaseService {
if (StringUtils.isNotBlank(portalUserUI.getOrgId())) {
PortalOrg portalOrg = portalOrgService.getById(portalUserUI.getOrgId());
portalUser.setPortalOrg(portalOrg);
} else {
// 개인사용자이면서 법인을 "없음"으로 선택한 경우 ORG_ID 삭제
if (portalUserUI.getRoleCode() == PortalUserEnums.RoleCode.ROLE_USER) {
portalUser.setPortalOrg(null);
}
}
portalUserService.save(portalUser);
@@ -404,7 +404,7 @@ public class LayoutSyncController extends OnlBaseAnnotationController implements
String resultS = null;
ServletInputStream sis = null;
HashMap<String, String> param = new HashMap<String, String>();
HashMap<String, String> param = new HashMap<>();
String recvTime = DateUtil.getDateTime("yyyyMMddHHmmssSS").substring(0, 16);
// 초기화
@@ -431,43 +431,33 @@ public class LayoutSyncController extends OnlBaseAnnotationController implements
byte[] arg = new byte[request.getContentLength()];
int resultSet = 0;
int total = 0;
try {
resultSet = sis.readLine(arg, 0, arg.length);
while(resultSet != -1) {
total += resultSet;
resultSet = sis.readLine(arg, total, 1024);
}
String xmlContent = null;
try {
resultSet = sis.readLine(arg, 0, arg.length);
while (resultSet != -1) {
total += resultSet;
resultSet = sis.readLine(arg, total, 1024);
}
// ===== 인코딩 확인 로그 시작 =====
logger.info("========== 인코딩 디버깅 정보 ==========");
logger.info("request.getCharacterEncoding(): " + request.getCharacterEncoding());
logger.info("request.getContentType(): " + request.getContentType());
logger.info("Content Length: " + arg.length + " bytes");
xmlContent = new String(arg, "EUC-KR");
// ===== 인코딩 확인 로그 시작 =====
logger.info("========== 인코딩 디버깅 정보 ==========");
// 다양한 인코딩으로 읽어보기
logger.info("request.getCharacterEncoding(): {}", request.getCharacterEncoding());
logger.info("request.getContentType(): {}", request.getContentType());
logger.info("Content Length: {} bytes", arg.length);
logger.info("EUC-KR 전체 내용:\n{}", xmlContent);
logger.info("========================================");
// ===== 인코딩 확인 로그 =====
param.put("recvData", xmlContent);
} catch (Exception e) {
logger.error("MessageSync.err - don't read the XML File", e);
param.put("recvData", "");
}
// 다양한 인코딩으 어보
String asDefaultEncoding = new String(arg);
String asUtf8 = new String(arg, "UTF-8");
String asEucKr = new String(arg, "EUC-KR");
logger.info("Default Encoding 전체 내용:\n" + asDefaultEncoding);
logger.info("UTF-8 전체 내용:\n" + asUtf8);
logger.info("EUC-KR 전체 내용:\n" + asEucKr);
logger.info("========================================");
// ===== 인코딩 확인 로그 =====
param.put("recvData", new String(arg, "EUC-KR"));
} catch(Exception e) {
logger.error("MessageSync.err - don't read the XML File - " + new String(arg, "EUC-KR"), e);
param.put("recvData", "");
}
// byte[]로부터 XML 파싱 (BOM 제거) - EUC-KR로 읽기
String xmlContent = new String(arg, "EUC-KR").trim();
// BOM 제거 (UTF-8 BOM: EF BB BF)
if (xmlContent.startsWith("\uFEFF")) {
xmlContent = xmlContent.substring(1);
}
Document doc = builder.build(new ByteArrayInputStream(xmlContent.getBytes("EUC-KR")));
// byte[]로부터 XML 파싱 - EUC-KR 읽기
Document doc = builder.build(new StringReader(xmlContent));
param.put("logPrcssSeqno", UUIDGenerator.getUUID());
// xml 1.1
@@ -485,9 +475,9 @@ public class LayoutSyncController extends OnlBaseAnnotationController implements
param.put("recvAmndHMS", recvTime);
logger.info(layoutName + " command - [" + command +"]");
HashMap<String, Object> returnMap = new HashMap<String,Object>();
HashMap<String, Object> returnMap = new HashMap<>();
if( command.equals("delete") ) {
HashMap<String,Object> vo = new HashMap<String,Object>();
HashMap<String,Object> vo = new HashMap<>();
vo.put("loutName",layoutName);
service.deleteLayout(vo);
@@ -513,10 +503,10 @@ public class LayoutSyncController extends OnlBaseAnnotationController implements
// }
String layout = body.getChild("data").getText();
logger.info(layoutName + " recv Data - [" + layout + "]");
logger.info("{} recv Data - [{}]]", layoutName, layout);
param.put("recvData", layout);
Document doc2 = builder.build(new ByteArrayInputStream(layout.getBytes()));
Document doc2 = builder.build(new StringReader(layout));
HashMap<String,Object> vo = new HashMap<String,Object>();
@@ -601,7 +591,6 @@ public class LayoutSyncController extends OnlBaseAnnotationController implements
} catch( Exception e ) {
logger.error("",e);
logger.error("",e.getStackTrace()[0]);
try {
if( results != null ) {
if (e instanceof UseSystemException) {
@@ -4,6 +4,7 @@ import com.eactive.eai.common.EAITable;
import com.eactive.eai.common.logger.HttpAdapterExtraLogVo;
import com.eactive.eai.common.util.MessageUtil;
import com.eactive.eai.data.entity.onl.adapter.AdapterGroup;
import com.eactive.eai.data.entity.onl.server.EAIServer;
import com.eactive.eai.rms.common.combo.ComboVo;
import com.eactive.eai.rms.common.context.MonitoringContext;
import com.eactive.eai.rms.common.logging.UserAccessLogger;
@@ -12,10 +13,12 @@ import com.eactive.eai.rms.common.vo.GridResponse;
import com.eactive.eai.rms.data.entity.onl.adapter.AdapterGroupService;
import com.eactive.eai.rms.data.entity.onl.logger.EAILogDetailSearch;
import com.eactive.eai.rms.data.entity.onl.logger.EAILogSearch;
import com.eactive.eai.rms.data.entity.onl.server.EAIServerService;
import com.eactive.eai.transformer.message.ISO8583MessageFactory;
import com.eactive.eai.transformer.util.CommonLib;
import com.eactive.eai.transformer.util.IConv;
import com.eactive.eai.transformer.util.ISO8583DumpUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.solab.iso8583.IsoMessage;
import org.apache.commons.io.HexDump;
@@ -24,11 +27,20 @@ import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.client.HttpStatusCodeException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
@@ -44,15 +56,20 @@ public class DbTrackingController {
private final DbTrackingService service;
private final MonitoringContext monitoringContext;
private final AdapterGroupService adapterGroupService;
private final EAIServerService eaiServerService;
private RestTemplate restTemplate = new RestTemplate();
private final ObjectMapper objectMapper = new ObjectMapper();
@Autowired
public DbTrackingController(DbTrackingService service,
MonitoringContext monitoringContext,
AdapterGroupService adapterGroupService) {
AdapterGroupService adapterGroupService,
EAIServerService eaiServerService) {
this.service = service;
this.monitoringContext = monitoringContext;
this.adapterGroupService = adapterGroupService;
this.eaiServerService = eaiServerService;
}
@GetMapping(value = "/onl/transaction/tracking/trackingMan.view")
@@ -538,5 +555,95 @@ public class DbTrackingController {
return new String(byteArrayOutputStream.toByteArray());
}
@RequestMapping(value = "/onl/transaction/tracking/trackingMan.json", params = "cmd=DETAIL_PRETTY_VIEW")
public ResponseEntity<?> selectList(@RequestParam Map<String, Object> paramMap) {
List<EAIServer> serverList = eaiServerService.selectEaiServerIpList();
if (serverList == null || serverList.isEmpty()) {
return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
.body(Collections.singletonMap("error", "접속 가능한 서버 목록이 없습니다."));
}
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(2000);
factory.setReadTimeout(5000);
RestTemplate restTemplate = new RestTemplate(factory);
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("intrefaceId", paramMap.get("intrefaceId"));
requestBody.put("logProcessNo", paramMap.get("logProcessNo"));
requestBody.put("bizData", paramMap.get("bizData"));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(requestBody, headers);
Map<String, Object> resultResponse = null;
boolean isSuccess = false;
String lastErrorMsg = "";
for(EAIServer server : serverList) {
String ip = server.getEaisevrip();
String port = server.getSevrlsnportname();
if(ip == null || port == null) continue;
String targetUrl = "http://" + ip + ":" + port + "/PrettyPrint";
try {
ResponseEntity<Map> response = restTemplate.exchange(
targetUrl,
HttpMethod.POST,
entity,
Map.class
);
if(response.getStatusCode() == HttpStatus.OK && response.getBody() != null) {
resultResponse = response.getBody();
isSuccess = true;
break;
}
} catch (ResourceAccessException e) {
lastErrorMsg = "Network Error: " + e.getMessage();
logger.debug("서버 접속 실패 : " + lastErrorMsg);
continue;
} catch (HttpStatusCodeException e) {
String errorBodyString = e.getResponseBodyAsString();
logger.debug("서버 내부 에러 [" + targetUrl + "] : " + errorBodyString);
try {
// 에러 문자열을 Map(JSON 객체)으로 변환 시도
Map<String, Object> errorMap = objectMapper.readValue(errorBodyString, Map.class);
return ResponseEntity.status(e.getStatusCode()).body(errorMap);
} catch (Exception parseError) {
// 일반 텍스트를 보냈다면 수동으로 Map 생성
Map<String, Object> manualErrorMap = new HashMap<>();
manualErrorMap.put("error", true);
manualErrorMap.put("result", errorBodyString);
return ResponseEntity.status(e.getStatusCode()).body(manualErrorMap);
}
}
}
if (isSuccess && resultResponse != null) {
return ResponseEntity.ok(resultResponse);
} else {
// 모든 서버 실패
Map<String, Object> errorMap = new HashMap<>();
errorMap.put("error", true);
errorMap.put("result", "서버 연결 실패");
// errorMap.put("result", "서버 연결 실패 (Last Error: " + lastErrorMsg + ")");
logger.debug("서버 POST 요청 에러 : " + lastErrorMsg);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(errorMap);
}
}
}
@@ -308,7 +308,7 @@ public class DbTrackingService extends BaseService {
Matcher matcher = pattern.matcher(input);
if (matcher.find()) {
return matcher.group(1).trim();
return matcher.group(1);
}
return null;