Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| edf024f0a3 | |||
| a1a1f27498 | |||
| c62f395983 | |||
| c3955cefd8 | |||
| 5c378eac0d | |||
| e51cdbc42a | |||
| 142d402bad | |||
| f23cb02b1c | |||
| eca120812c | |||
| 71b0fc7009 | |||
| 7b12ef2fb5 | |||
| 292e27e66e | |||
| 61d710dd8c | |||
| 8494758fcd | |||
| f2b25d2775 |
@@ -54,10 +54,18 @@ function detail(key){
|
||||
$('#systemCode').val(data.systemCode);
|
||||
$('#logTypeText').val(data.logTypeText);
|
||||
$('#remoteAddress').val(data.remoteAddress);
|
||||
$('#logMsg').val(data.message);
|
||||
$('#logSubMsg').val(data.command);
|
||||
$('#parameters').val(data.parameters);
|
||||
|
||||
// 사유(message)는 값이 있을 때만 노출
|
||||
if (data.message) {
|
||||
$('#logMsg').val(data.message);
|
||||
$('#messageRow').show();
|
||||
} else {
|
||||
$('#logMsg').val('');
|
||||
$('#messageRow').hide();
|
||||
}
|
||||
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
@@ -121,6 +129,9 @@ $(document).ready(function() {
|
||||
<tr>
|
||||
<th><%= localeMessage.getString("auditLogMan.command") %></th><td><input type="text" id="logSubMsg" name="logSubMsg" readonly="readonly"/></td>
|
||||
</tr>
|
||||
<tr id="messageRow" style="display:none;">
|
||||
<th><%= localeMessage.getString("auditLogMan.message") %></th><td><textarea id="logMsg" name="logMsg" style="width:100%;height:80px" readonly="readonly"></textarea></td>
|
||||
</tr>
|
||||
<tr height="100px">
|
||||
<th><%= localeMessage.getString("auditLogMan.parameters") %></th><td><textarea id="parameters" name="parameters" style="width:100%;height:200px" readonly="readonly"></textarea></td>
|
||||
</tr>
|
||||
|
||||
@@ -531,6 +531,88 @@
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* 사유 입력 모달 - 확인 시 입력한 사유 문자열을 onConfirm(reason)으로 전달
|
||||
* @param {string} message - 안내 메시지
|
||||
* @param {object} options - (title, confirmText, cancelText, placeholder, required, onConfirm, onCancel)
|
||||
* required 기본 true (빈 사유 차단)
|
||||
*/
|
||||
function showReasonPrompt(message, options) {
|
||||
options = options || {};
|
||||
var title = options.title || '사유 입력';
|
||||
var confirmText = options.confirmText || '확인';
|
||||
var cancelText = options.cancelText || '취소';
|
||||
var placeholder = options.placeholder || '사유를 입력하세요.';
|
||||
var required = options.required !== false;
|
||||
var onConfirm = options.onConfirm || function(){};
|
||||
var onCancel = options.onCancel || function(){};
|
||||
|
||||
// 기존 모달 제거
|
||||
$('#commonReasonModal').remove();
|
||||
|
||||
var iconHtml = getAlertIcon('warning');
|
||||
|
||||
var modalHtml =
|
||||
'<div id="commonReasonModal" class="common-alert-overlay">' +
|
||||
'<div class="common-alert-modal alert-warning">' +
|
||||
'<div class="common-alert-header">' +
|
||||
'<span class="common-alert-icon">' + iconHtml + '</span>' +
|
||||
'<span class="common-alert-title">' + title + '</span>' +
|
||||
'</div>' +
|
||||
'<div class="common-alert-body">' +
|
||||
'<p class="common-alert-message">' + message + '</p>' +
|
||||
'<textarea id="commonReasonInput" maxlength="200" placeholder="' + placeholder + '" style="width:100%;height:80px;margin-top:10px;box-sizing:border-box;font-size:13px;padding:8px;border:1px solid #ddd;border-radius:4px;resize:vertical;"></textarea>' +
|
||||
'<p id="commonReasonError" style="display:none;color:#f44336;font-size:12px;margin:6px 0 0;">사유를 입력해 주세요.</p>' +
|
||||
'</div>' +
|
||||
'<div class="common-alert-footer">' +
|
||||
'<button type="button" class="common-confirm-cancel-btn" id="commonReasonCancelBtn">' + cancelText + '</button>' +
|
||||
'<button type="button" class="common-alert-btn" id="commonReasonOkBtn">' + confirmText + '</button>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
|
||||
$('body').append(modalHtml);
|
||||
|
||||
setTimeout(function() {
|
||||
$('#commonReasonModal').addClass('show');
|
||||
$('#commonReasonInput').focus();
|
||||
}, 10);
|
||||
|
||||
// 확인 버튼
|
||||
$('#commonReasonOkBtn').on('click', function() {
|
||||
var reason = $.trim($('#commonReasonInput').val());
|
||||
if (required && reason === '') {
|
||||
$('#commonReasonError').show();
|
||||
$('#commonReasonInput').focus();
|
||||
return;
|
||||
}
|
||||
closeCommonReason(function() { onConfirm(reason); });
|
||||
});
|
||||
|
||||
// 취소 버튼
|
||||
$('#commonReasonCancelBtn').on('click', function() {
|
||||
closeCommonReason(onCancel);
|
||||
});
|
||||
|
||||
// ESC 키로 취소
|
||||
$(document).on('keydown.commonReason', function(e) {
|
||||
if (e.keyCode === 27) {
|
||||
closeCommonReason(onCancel);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function closeCommonReason(callback) {
|
||||
$('#commonReasonModal').removeClass('show');
|
||||
setTimeout(function() {
|
||||
$('#commonReasonModal').remove();
|
||||
$(document).off('keydown.commonReason');
|
||||
if (typeof callback === 'function') {
|
||||
callback();
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- 공용 Alert 모달 스타일 -->
|
||||
|
||||
@@ -91,7 +91,10 @@
|
||||
data: $('#loginForm').serialize(),
|
||||
dataType: 'json',
|
||||
success: function(response) {
|
||||
if (response.smsAuthRequired) {
|
||||
if (response.changePassword) {
|
||||
showChangeInitPassword(response);
|
||||
}
|
||||
else if (response.smsAuthRequired) {
|
||||
// SMS 인증 필요
|
||||
showSmsAuthModal(response);
|
||||
} else if (response.success) {
|
||||
@@ -108,6 +111,13 @@
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showChangeInitPassword(data) {
|
||||
$('input[name="resetUserId"]').val($('input[name="userId"]').val());
|
||||
$('input[name="resetPassword"]').val($('input[name="password"]').val());
|
||||
$('#changeInitPassword').hide();
|
||||
$('#pwdChgModal').modal('show');
|
||||
}
|
||||
|
||||
// SMS 인증 모달 표시
|
||||
function showSmsAuthModal(data) {
|
||||
@@ -218,44 +228,39 @@
|
||||
clearInterval(resendTimer);
|
||||
$('#smsAuthModal').modal('hide');
|
||||
}
|
||||
function changePwd(){
|
||||
|
||||
function checkPwd(){
|
||||
if ($("input[name=resetUserId]").val() == null || $("input[name=resetUserId]").val().length == 0 ){
|
||||
alert("<%= localeMessage.getString("login.checkid") %>");
|
||||
$("input[name=resetUserId]").trigger("focus");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if ($("input[name=resetPassword]").val() == null || $("input[name=resetPassword]").val().trim().length == 0 ){
|
||||
alert("<%= localeMessage.getString("login.checkpwd1") %>");
|
||||
$("input[name=resetPassword]").trigger("focus");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if ($("input[name=changePassword]").val() == null || $("input[name=changePassword]").val().trim().length == 0 ){
|
||||
alert("<%= localeMessage.getString("login.checkpwd2") %>");
|
||||
$("input[name=changePassword]").trigger("focus");
|
||||
return ;
|
||||
return false;
|
||||
}
|
||||
if ($("input[name=confirmPassword]").val() == null || $("input[name=confirmPassword]").val().trim().length == 0 ){
|
||||
alert("<%= localeMessage.getString("login.checkpwd3") %>");
|
||||
return ;
|
||||
return false;
|
||||
}
|
||||
if ($("input[name=confirmPassword]").val() != $("input[name=confirmPassword]").val()){
|
||||
if ($("input[name=changePassword]").val() != $("input[name=confirmPassword]").val()){
|
||||
alert("<%= localeMessage.getString("login.checkpwd4") %>");
|
||||
$("input[name=confirmPassword]").trigger("focus");
|
||||
return ;
|
||||
return false;
|
||||
}
|
||||
if ($("input[name=resetUserId]").val() == $("input[name=changePassword]").val()){
|
||||
alert("<%= localeMessage.getString("login.checkpwd5") %>");
|
||||
$("input[name=changePassword]").trigger("focus");
|
||||
return ;
|
||||
return false;
|
||||
}
|
||||
|
||||
//if (idCheck.checked){
|
||||
// setCookie("key",id);
|
||||
//}
|
||||
<%-- $("form").attr("action","<c:url value="/changePassword.do"/>");
|
||||
//$("form").action = "<%=request.getContextPath()%>/changePassword.do";
|
||||
--%>
|
||||
$("form").submit();
|
||||
return true;
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
@@ -271,14 +276,22 @@
|
||||
});
|
||||
$("input[name=changePassword]").keydown(function(event){
|
||||
if ( event.which == 13 ) {
|
||||
changePwd();
|
||||
$('#modalLoginForm').submit();
|
||||
}
|
||||
});
|
||||
$("input[name=confirmPassword]").keydown(function(event){
|
||||
if ( event.which == 13 ) {
|
||||
changePwd();
|
||||
$('#modalLoginForm').submit();
|
||||
}
|
||||
});
|
||||
// Password Change 링크로 직접 열 때만 초기화 (JS에서 modal('show') 호출 시 relatedTarget 없음)
|
||||
$('#pwdChgModal').on('show.bs.modal', function(event) {
|
||||
if (event.relatedTarget) {
|
||||
$('#modalLoginForm')[0].reset();
|
||||
$('#changeInitPassword').show();
|
||||
}
|
||||
});
|
||||
|
||||
$("select[name=serviceType]").change(function(){
|
||||
fncPreMain();
|
||||
});
|
||||
@@ -286,9 +299,7 @@
|
||||
$("#btn_login").click(function(){
|
||||
fncPreMain();
|
||||
});
|
||||
$("#changePwd").click(function(){
|
||||
changePwd();
|
||||
});
|
||||
|
||||
$("#btn_sso_login").click(function(){
|
||||
fncSsoLogin();
|
||||
});
|
||||
@@ -366,7 +377,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 비밀번호 변경 모달 -->
|
||||
<div class="modal fade" id="pwdChgModal" tabindex="-1" role="dialog" aria-labelledby="pwdChgModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
@@ -376,13 +387,15 @@
|
||||
<span aria-hidden="true">X</span>
|
||||
</button>
|
||||
</div>
|
||||
<form name="form" id="modalLoginForm" action="<c:url value="/changePassword.do"/>" method="post">
|
||||
<form id="modalLoginForm" action="<c:url value="/changePassword.do"/>" method="post" onsubmit="return checkPwd()" novalidate>
|
||||
<div class="modal-body">
|
||||
<div class="form-group d-flex">
|
||||
<input type="text" name="resetUserId" class="form-control rounded-left" placeholder="User Id" required>
|
||||
</div>
|
||||
<div class="form-group d-flex">
|
||||
<input type="password" name="resetPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderCurrentPassword") %>" autocomplete="off" required>
|
||||
<div id="changeInitPassword">
|
||||
<div class="form-group d-flex">
|
||||
<input type="text" name="resetUserId" class="form-control rounded-left" placeholder="User Id" required>
|
||||
</div>
|
||||
<div class="form-group d-flex">
|
||||
<input type="password" name="resetPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderCurrentPassword") %>" autocomplete="off" required>
|
||||
</div>
|
||||
</div>
|
||||
<p><%= localeMessage.getString("login.toChangePasswordMessage") %></p>
|
||||
<div class="form-group d-flex">
|
||||
@@ -391,9 +404,12 @@
|
||||
<div class="form-group d-flex">
|
||||
<input type="password" name="confirmPassword" class="form-control rounded-left" placeholder="<%= localeMessage.getString("login.placeholderConfirmationPassword") %>" autocomplete="off" required>
|
||||
</div>
|
||||
<span style="font-size:0.8em; color:red">
|
||||
※ 7글자 이상 & 영문/숫자/특수문자 2종류 이상
|
||||
</span>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="button" id ="changePwd" class="form-control btn btn-primary rounded submit px-3" value="변경">
|
||||
<button type="submit" id="changePwd" class="form-control btn btn-primary rounded submit px-3">변경</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
var url = '<c:url value="/onl/admin/authserver/scopeMan.json" />';
|
||||
var url_view = '<c:url value="/onl/admin/authserver/scopeMan.view" />';
|
||||
var api_url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view" />';
|
||||
var mapping_url = '<c:url value="/onl/admin/authserver/apiScopeMan.json" />';
|
||||
|
||||
var isDetail = false;
|
||||
function isValid(){
|
||||
@@ -65,9 +64,9 @@ function mappingInfo(key){
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url: mapping_url,
|
||||
url: url,
|
||||
dataType: "json",
|
||||
data: {cmd: 'LIST', searchScopeId : key},
|
||||
data: {cmd: 'API_LIST', searchScopeId : key},
|
||||
success: function(json){
|
||||
var mappingData = json.rows;
|
||||
|
||||
@@ -131,45 +130,6 @@ function init(key, callback){
|
||||
}
|
||||
}
|
||||
|
||||
function saveApiGridData(scopeId, returnUrl) {
|
||||
var postData = [];
|
||||
var rows = $("#selectedApiGrid").jqGrid('getRowData');
|
||||
|
||||
$.each(rows, function(index, item) {
|
||||
item.scopeId = scopeId;
|
||||
});
|
||||
|
||||
postData.push({
|
||||
name: "apiList",
|
||||
value: JSON.stringify(rows)
|
||||
});
|
||||
|
||||
postData.push({ name: "cmd" , value:"INSERT_APILIST" });
|
||||
postData.push({ name: "scopeId" , value:scopeId });
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:mapping_url,
|
||||
data: postData,
|
||||
beforeSend: function() {
|
||||
$("[id^='btn_']").prop("disabled", true);
|
||||
$("#btn_modify").text("처리중 . . . . .");
|
||||
},
|
||||
success:function(args){
|
||||
alert("저장 되었습니다.");
|
||||
|
||||
goNav(returnUrl);//LIST로 이동
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
},
|
||||
complete: function() {
|
||||
$("[id^='btn_']").prop("disabled", false);
|
||||
$("#btn_modify").text("수정");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
var returnUrl = getReturnUrlForReturn();
|
||||
var key ="${param.scopeId}";
|
||||
@@ -182,28 +142,39 @@ $(document).ready(function() {
|
||||
if (!isValid()){
|
||||
return;
|
||||
}
|
||||
var scopeId = $('input[name=scopeId]').val();
|
||||
var postData = $('#ajaxForm').serializeArray();
|
||||
|
||||
var rows = $("#selectedApiGrid").jqGrid('getRowData');
|
||||
$.each(rows, function(index, item) {
|
||||
item.scopeId = scopeId;
|
||||
});
|
||||
postData.push({ name: "apiList" , value: JSON.stringify(rows) });
|
||||
|
||||
if (isDetail){
|
||||
postData.push({ name: "cmd" , value:"UPDATE"});
|
||||
}else{
|
||||
postData.push({ name: "cmd" , value:"INSERT"});
|
||||
}
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data:postData,
|
||||
beforeSend: function() {
|
||||
$("[id^='btn_']").prop("disabled", true);
|
||||
$("#btn_modify").text("처리중 . . . . .");
|
||||
},
|
||||
success:function(args){
|
||||
alert("SCOPE 정보가 저장 되었습니다. 이어서 API 리스트를 저장합니다.");
|
||||
|
||||
if(!isDetail) { // INSERT 일 경우 ScopeId를 업데이트
|
||||
key = $('input[name=scopeId]').val();
|
||||
}
|
||||
saveApiGridData(key, returnUrl); // API LIST 저장.
|
||||
|
||||
|
||||
alert("저장 되었습니다.");
|
||||
goNav(returnUrl);//LIST로 이동
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
},
|
||||
complete: function() {
|
||||
$("[id^='btn_']").prop("disabled", false);
|
||||
$("#btn_modify").text("수정");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
|
||||
$('#grid').children().remove();
|
||||
|
||||
const itemTypes = ['Field', 'Grid', 'Group', 'Attr'];
|
||||
const itemTypes = ['Field', 'Grid', 'Group', 'Attr', 'Array'];
|
||||
|
||||
columns = [ // for columnData prop
|
||||
{ title: '<%= localeMessage.getString("layoutMan.itmeEn") %>', name: 'loutItemName', type: 'text', width:280, resize:true, minWidth:120 },
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
const LAYOUT_ITEM_TYPE_GROUP = "Group";
|
||||
const LAYOUT_ITEM_TYPE_GRID = "Grid";
|
||||
const LAYOUT_ITEM_TYPE_FIELD = "Field";
|
||||
const LAYOUT_ITEM_TYPE_ARRAY = "Array";
|
||||
|
||||
var isDetail = false;
|
||||
|
||||
@@ -550,6 +551,14 @@
|
||||
return data;
|
||||
}
|
||||
|
||||
// 항목 자신이 Array인 경우, 경로/변환명령 끝에 반복 표시 [*]를 추가
|
||||
function addArrayTag(loutItemType, data) {
|
||||
if (loutItemType == LAYOUT_ITEM_TYPE_ARRAY && !data.endsWith("[*]")) {
|
||||
data = data + "[*]";
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
//변환명에 있는 서비스코드와 if서비스 코드 매칭
|
||||
function validation(){
|
||||
if ($('input[name=cnvsnName]').val() == '') {
|
||||
@@ -889,10 +898,10 @@
|
||||
let selectValue = "";
|
||||
let targetValue = "";
|
||||
for ( var i = 0; i < sourceData.length; i++) {
|
||||
if (sourceData[i]['loutItemType'] != "Field" && sourceData[i]['loutItemType'] != "Attr") continue;
|
||||
if (sourceData[i]['loutItemType'] != "Field" && sourceData[i]['loutItemType'] != "Attr" && sourceData[i]['loutItemType'] != "Array") continue;
|
||||
selectValue = (sourceData[i]['LOUTITEMPATH']).substr(sourceData[i]['loutName'].length+1);
|
||||
for (var j = 0; j <targetData.length; j++) {
|
||||
if (targetData[j]['loutItemType'] != "Field" && targetData[j]['loutItemType'] != "Attr") continue;
|
||||
if (targetData[j]['loutItemType'] != "Field" && targetData[j]['loutItemType'] != "Attr" && targetData[j]['loutItemType'] != "Array") continue;
|
||||
targetValue = (targetData[j]['LOUTITEMPATH']).substr(targetData[j]['loutName'].length+1);
|
||||
if (targetValue == selectValue ) {
|
||||
var data = sourceData[i]['LOUTITEMPATH'];
|
||||
@@ -916,8 +925,8 @@
|
||||
//field, ATTR 여부 판단
|
||||
var sourceRow = sourceGrid.getRowData( srcRowId );
|
||||
var targetRow = targetGrid.getRowData( tgtRowId );
|
||||
if ( (sourceRow["loutItemType"] == 'Field' || sourceRow["loutItemType"] == 'Attr') &&
|
||||
(targetRow["loutItemType"] == 'Field' || targetRow["loutItemType"] == 'Attr') ){
|
||||
if ( (sourceRow["loutItemType"] == 'Field' || sourceRow["loutItemType"] == 'Attr' || sourceRow["loutItemType"] == 'Array') &&
|
||||
(targetRow["loutItemType"] == 'Field' || targetRow["loutItemType"] == 'Attr' || targetRow["loutItemType"] == 'Array') ){
|
||||
;
|
||||
}else{
|
||||
alert('<%=localeMessage.getString("transformManDetail.alert3")%>');
|
||||
@@ -936,15 +945,15 @@
|
||||
var targetValue = "";
|
||||
var j=tgtIndex-1-1;
|
||||
for ( var i = srcIndex-1; i < sourceData.length; i++) {
|
||||
if (sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_FIELD) continue;
|
||||
if (sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_FIELD && sourceData[i]['loutItemType'] != LAYOUT_ITEM_TYPE_ARRAY) continue;
|
||||
j++;
|
||||
while (targetData.length -1 >= j &&targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_FIELD){
|
||||
while (targetData.length -1 >= j && targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_FIELD && targetData[j]["loutItemType"] != LAYOUT_ITEM_TYPE_ARRAY){
|
||||
j++;
|
||||
}
|
||||
if (targetData.length -1 < j) break;
|
||||
var targetRowId = targetData[j]['id'];
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNCMDNAME',addGroupTag(srcGroup,sourceData[i]['LOUTITEMPATH']));
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNRSULTITEMPATHNAME',addGroupTag(tgtGroup,targetData[j]['LOUTITEMPATH']));
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNCMDNAME',addArrayTag(sourceData[i]['loutItemType'], addGroupTag(srcGroup,sourceData[i]['LOUTITEMPATH'])));
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNRSULTITEMPATHNAME',addArrayTag(targetData[j]['loutItemType'], addGroupTag(tgtGroup,targetData[j]['LOUTITEMPATH'])));
|
||||
targetGrid.jqGrid('setCell',targetRowId,'CNVSNITEMSERNO',targetData[j]['loutItemSerno']);
|
||||
|
||||
const sourceEndpointElementId = sourceGrid.getEndpointElementId(sourceData[i]['id']);
|
||||
@@ -1015,7 +1024,7 @@
|
||||
var targetData = targetGrid.getRowData();
|
||||
var gridData = new Array();
|
||||
for (var i = 0; i <targetData.length; i++) {
|
||||
if ((targetData[i]['loutItemType'] != "Field") && (targetData[i]['loutItemType'] != "Attr")) {
|
||||
if ((targetData[i]['loutItemType'] != "Field") && (targetData[i]['loutItemType'] != "Attr") && (targetData[i]['loutItemType'] != "Array")) {
|
||||
continue;
|
||||
}
|
||||
if (targetData[i]['CNVSNCMDNAME']==null
|
||||
@@ -1158,7 +1167,7 @@
|
||||
function srcformatterFunction(cellvalue,options,rowObject){
|
||||
var rowId = options["rowId"];
|
||||
var loutItemType = rowObject["loutItemType"];
|
||||
if (loutItemType == 'Field' || loutItemType == 'Attr'){
|
||||
if (loutItemType == 'Field' || loutItemType == 'Attr' || loutItemType == 'Array'){
|
||||
return "<div id='div_src_"+rowId+"' name='src_"+rowId+"' style='width:28px;height:17px;background-color: #D12F35; border-color: #ab1717; border-style: solid; border-width: 1px; border-radius: 3px;' />";
|
||||
}else{
|
||||
return "<div id='div_srcgroup_"+rowId+"' name='srcgroup_"+rowId+"' style='width:28px;height:17px;' />";
|
||||
@@ -1170,7 +1179,7 @@
|
||||
function tgtformatterFunction(cellvalue,options,rowObject){
|
||||
var rowId = options["rowId"];
|
||||
var loutItemType = rowObject["loutItemType"];
|
||||
if (loutItemType == 'Field' || loutItemType == 'Attr'){
|
||||
if (loutItemType == 'Field' || loutItemType == 'Attr' || loutItemType == 'Array'){
|
||||
return "<div id='div_tgt_"+rowId+"_base' name='div_tgt_"+rowId+"_base' style='width:30px;height:20px; background-color:gray;' >"
|
||||
+ "<div id='div_tgt_"+rowId+"' name='tgt_"+rowId+"' style='width:28px;height:17px; background-color: #3E7E9C; border-color: #217ca7; border-style: solid; border-width: 1px; border-radius: 3px;' onclick='jqGridOnTargetGridEndpointClick(this)'>"
|
||||
+ "</div></div>";
|
||||
@@ -1669,8 +1678,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sourceRow["loutItemType"] != 'Field' && sourceRow["loutItemType"] != 'Attr')
|
||||
|| (targetRow["loutItemType"] != 'Field' && targetRow["loutItemType"] != 'Attr')) {
|
||||
if ((sourceRow["loutItemType"] != 'Field' && sourceRow["loutItemType"] != 'Attr' && sourceRow["loutItemType"] != 'Array')
|
||||
|| (targetRow["loutItemType"] != 'Field' && targetRow["loutItemType"] != 'Attr' && targetRow["loutItemType"] != 'Array')) {
|
||||
alert('<%=localeMessage.getString("transformManDetail.alert3")%>');
|
||||
return ;
|
||||
}
|
||||
@@ -1684,7 +1693,7 @@
|
||||
|
||||
if (targetRow['CNVSNCMDNAME'] == '') {
|
||||
// 변환 명령 값이 한번 설정 되면 변경 되지 않게 함.
|
||||
var cnvsnCmdName = addGroupTag(srcGroup,sourceRow["LOUTITEMPATH"]);
|
||||
var cnvsnCmdName = addArrayTag(sourceRow["loutItemType"], addGroupTag(srcGroup,sourceRow["LOUTITEMPATH"]));
|
||||
// function까지 처리되도록 수정했으나, parameter가 하나인 경우에만 정상처리됨
|
||||
if($('#functionCombo').val() != "") {
|
||||
cnvsnCmdName = $('#functionCombo').val() + "(" + cnvsnCmdName + ")";
|
||||
@@ -1693,7 +1702,7 @@
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNCMDNAME', cnvsnCmdName);
|
||||
}
|
||||
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNRSULTITEMPATHNAME',addGroupTag(tgtGroup,targetRow["LOUTITEMPATH"]));
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNRSULTITEMPATHNAME',addArrayTag(targetRow["loutItemType"], addGroupTag(tgtGroup,targetRow["LOUTITEMPATH"])));
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNITEMSERNO',targetRow['loutItemSerno']);
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'CNVSNSRCITEMS', cnvsnSrcItems);
|
||||
targetGrid.jqGrid('setCell',tgtRowId,'ISVALIDMAPPING', true);
|
||||
@@ -1885,8 +1894,8 @@
|
||||
if (loutItemType == LAYOUT_ITEM_TYPE_GRID || loutItemType == LAYOUT_ITEM_TYPE_GROUP) {
|
||||
// group 인 경우
|
||||
items = createGridGroupContextMenuItems(grid, rowId);
|
||||
} else if(loutItemType == LAYOUT_ITEM_TYPE_FIELD) {
|
||||
// field 인 경우
|
||||
} else if(loutItemType == LAYOUT_ITEM_TYPE_FIELD || loutItemType == LAYOUT_ITEM_TYPE_ARRAY) {
|
||||
// field, array 인 경우
|
||||
items = createFieldContextMenuItems(grid, positionElement.attr('id'));
|
||||
} else {
|
||||
return false;
|
||||
@@ -1989,7 +1998,7 @@
|
||||
break;
|
||||
}
|
||||
|
||||
if (loutItemType == LAYOUT_ITEM_TYPE_FIELD) {
|
||||
if (loutItemType == LAYOUT_ITEM_TYPE_FIELD || loutItemType == LAYOUT_ITEM_TYPE_ARRAY) {
|
||||
loutItemPath = loutItemPath.replace(new RegExp("^" + prefix), "");
|
||||
console.debug(grid.getId() + " : loutItemPath : " + loutItemPath);
|
||||
rowData['GROUP_LOUTITEMPATH'] = loutItemPath;
|
||||
|
||||
@@ -131,6 +131,24 @@
|
||||
// var reverseNumber = records - ((page - 1) * rowNum + i);
|
||||
$(this).setCell(rows[i], 'rowNum', number);
|
||||
}
|
||||
|
||||
// 승인 상태별 행 배경색: 요청됨(#fff3cd) / 진행중(#d1ecf1) 강조
|
||||
if (d && d.rows) {
|
||||
for (var j = 0; j < d.rows.length; j++) {
|
||||
var st = d.rows[j].approvalStatus || {};
|
||||
var code = st.code || '';
|
||||
var desc = st.description || '';
|
||||
var bg = '';
|
||||
if (code === 'REQUESTED' || desc === '요청됨') {
|
||||
bg = '#fff3cd';
|
||||
} else if (code === 'PROCESSING' || desc === '진행중') {
|
||||
bg = '#d1ecf1';
|
||||
}
|
||||
if (bg) {
|
||||
$('#grid tr#' + $.jgrid.jqID(d.rows[j].id)).css('background-color', bg);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
loadError: function(jqXHR, textStatus, errorThrown) {
|
||||
var location = '<%=request.getContextPath()%>/';
|
||||
|
||||
@@ -312,7 +312,9 @@ $(document).ready(function() {
|
||||
<div class="content_middle" id="content_middle">
|
||||
<div class="search_wrap">
|
||||
<button type="button" class="cssbtn" id="btn_new" level="W"><i class="material-icons">add</i> <%= localeMessage.getString("button.new") %></button>
|
||||
<c:if test="${hardDeleteEnabled}">
|
||||
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i class="material-icons">delete_forever</i> 선택 삭제</button>
|
||||
</c:if>
|
||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
||||
</div>
|
||||
<%--법인정보관리--%>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
response.setHeader("Expires", "0");
|
||||
|
||||
MonitoringContext monitoringContext = (MonitoringContext)CommonUtil.getBean(request, "monitoringContext");
|
||||
String reverseProxyUrl = monitoringContext.getStringProperty("djb.reverse_proxy.url", "");
|
||||
String reverseProxyUrl = monitoringContext.getStringProperty(MonitoringContext.RMS_WEBHOOK_REVERSE_PROXY_URL, "");
|
||||
%>
|
||||
<%!
|
||||
public String getRequiredLabel(String label) {
|
||||
@@ -138,7 +138,11 @@
|
||||
$("#btn_delete").hide();
|
||||
}
|
||||
|
||||
$("#approvalStatus").val(portalOrgData.approvalStatus);
|
||||
$("select[name=approvalStatus]").val(portalOrgData.approvalStatus);
|
||||
// 승인상태는 읽기전용(수정 불가) - 값은 그대로 제출되도록 disabled 대신 잠금 처리
|
||||
$("select[name=approvalStatus]")
|
||||
.css({'pointer-events':'none', 'background-color':'#eee'})
|
||||
.attr('tabindex', '-1');
|
||||
$("#compRegNo").val(formatCompanyRegNo(portalOrgData.compRegNo));
|
||||
$("#corpRegNo").val(formatCorpRegNo(portalOrgData.corpRegNo));
|
||||
$("#createdDate").inputmask("9999-99-99 99:99:99", {'autoUnmask': true});
|
||||
@@ -480,8 +484,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
if (confirm("<%= localeMessage.getString("common.checkSave")%>") !== true)
|
||||
return;
|
||||
// 저장 확인/사유 입력은 유효성 검사 및 FormData 구성 후 처리 (하단 submit 분기)
|
||||
|
||||
// FormData 생성 전에 분리된 전화번호 필드 제거
|
||||
$("#scPhonePrefix, #scPhoneMiddle, #scPhoneLast, #orgPhonePrefix, #orgPhoneMiddle, #orgPhoneLast").removeAttr('name');
|
||||
@@ -516,23 +519,47 @@
|
||||
}
|
||||
|
||||
|
||||
// cmd 파라미터 추가
|
||||
formData.append("cmd", isDetail ? "UPDATE" : "INSERT");
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success:function(json){
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
// cmd 및 사유(auditReason) 첨부 후 전송
|
||||
function submitOrg(cmd, auditReason) {
|
||||
formData.append("cmd", cmd);
|
||||
// 감사로그(AUDIT_LOG) 발화를 위한 systemCode. 법인/가입자 리포지토리는 고정 EMS 스키마라 스키마 전환 영향 없음
|
||||
formData.append("serviceType", "APIGW");
|
||||
if (auditReason) {
|
||||
formData.append("auditReason", auditReason);
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data: formData,
|
||||
processData: false,
|
||||
contentType: false,
|
||||
success:function(json){
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isDetail) {
|
||||
// 수정: 상태를 REMOVED로 바꾼 경우 삭제(cmd=DELETE)로 감사 기록 + 익명화
|
||||
var targetCmd = ($("#orgStatus").val() === 'REMOVED') ? "DELETE" : "UPDATE";
|
||||
var isRemove = (targetCmd === "DELETE");
|
||||
showReasonPrompt(
|
||||
isRemove ? "해당 법인을 삭제(탈퇴) 처리합니다. 사유를 입력해 주세요." : "법인 정보를 수정합니다. 사유를 입력해 주세요.",
|
||||
{
|
||||
title: isRemove ? "삭제 사유" : "수정 사유",
|
||||
onConfirm: function(reason) { submitOrg(targetCmd, reason); }
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// 신규 등록: 사유 불필요
|
||||
if (confirm("<%= localeMessage.getString("common.checkSave")%>") !== true) return;
|
||||
submitOrg("INSERT", null);
|
||||
}
|
||||
});
|
||||
|
||||
$("#btn_previous").click(function() {
|
||||
@@ -541,25 +568,28 @@
|
||||
|
||||
$("#btn_delete").click(function(){
|
||||
|
||||
if(confirm("<%= localeMessage.getString("common.confirmMsg")%>")){
|
||||
var postData = $('#ajaxForm').serializeArray();
|
||||
postData.push({name: "cmd" , value:"DELETE"});
|
||||
showReasonPrompt("해당 법인을 삭제 처리합니다. 사유를 입력해 주세요.", {
|
||||
title: "삭제 사유",
|
||||
onConfirm: function(reason) {
|
||||
var postData = $('#ajaxForm').serializeArray();
|
||||
postData.push({name: "cmd" , value:"DELETE"});
|
||||
postData.push({name: "serviceType", value: "APIGW"});
|
||||
postData.push({name: "auditReason", value: reason});
|
||||
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data:postData,
|
||||
success:function(args){
|
||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}else{
|
||||
return false;
|
||||
}
|
||||
$.ajax({
|
||||
type : "POST",
|
||||
url:url,
|
||||
data:postData,
|
||||
success:function(args){
|
||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error:function(e){
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
@@ -347,9 +347,11 @@
|
||||
<button type="button" class="cssbtn" id="btn_new" level="W"><i
|
||||
class="material-icons">add</i> <%= localeMessage.getString("button.new") %>
|
||||
</button>
|
||||
<c:if test="${hardDeleteEnabled}">
|
||||
<button type="button" class="cssbtn" id="btn_delete_selected" level="W" style="background-color: #dc3545; border-color: #dc3545; color: white;"><i
|
||||
class="material-icons">delete_forever</i> 선택 삭제
|
||||
</button>
|
||||
</c:if>
|
||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i
|
||||
class="material-icons">search</i> <%= localeMessage.getString("button.search") %>
|
||||
</button>
|
||||
|
||||
@@ -165,6 +165,10 @@
|
||||
$("#userStatus").val(data.userStatus);
|
||||
$("#roleCode").val(data.roleCode).trigger('change');
|
||||
$("#approvalStatus").val(data.approvalStatus);
|
||||
// 승인상태는 읽기전용(수정 불가) - 값은 그대로 제출되도록 disabled 대신 잠금 처리
|
||||
$("#approvalStatus")
|
||||
.css({'pointer-events':'none', 'background-color':'#eee'})
|
||||
.attr('tabindex', '-1');
|
||||
|
||||
// 탈퇴 상태 처리
|
||||
if (originalUserStatus === STATUS.REMOVED) {
|
||||
@@ -488,29 +492,49 @@
|
||||
formData.push({name: 'mobileNumber', value: mobileNumber});
|
||||
}
|
||||
|
||||
formData.push({
|
||||
name: 'cmd',
|
||||
value: isDetail ? "UPDATE" : "INSERT"
|
||||
});
|
||||
|
||||
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: formData,
|
||||
success: function (json) {
|
||||
if (json.status === "fail") {
|
||||
alert(json.errorMsg || "저장에 실패했습니다.");
|
||||
return;
|
||||
}
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
// cmd 및 사유(auditReason) 첨부 후 전송
|
||||
function submitUser(cmd, auditReason) {
|
||||
formData.push({ name: 'cmd', value: cmd });
|
||||
// 감사로그(AUDIT_LOG) 발화를 위한 systemCode. 가입자 리포지토리는 고정 EMS 스키마라 스키마 전환 영향 없음
|
||||
formData.push({ name: 'serviceType', value: 'APIGW' });
|
||||
if (auditReason) {
|
||||
formData.push({ name: 'auditReason', value: auditReason });
|
||||
}
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: formData,
|
||||
success: function (json) {
|
||||
if (json.status === "fail") {
|
||||
alert(json.errorMsg || "저장에 실패했습니다.");
|
||||
return;
|
||||
}
|
||||
alert("<%= localeMessage.getString("common.saveMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (isDetail) {
|
||||
// 수정: 상태를 REMOVED로 바꾼 경우 삭제(cmd=DELETE)로 감사 기록 + 익명화
|
||||
var targetCmd = ($("#userStatus").val() === 'REMOVED') ? "DELETE" : "UPDATE";
|
||||
var isRemove = (targetCmd === "DELETE");
|
||||
showReasonPrompt(
|
||||
isRemove ? "해당 가입자를 삭제(탈퇴) 처리합니다. 사유를 입력해 주세요." : "가입자 정보를 수정합니다. 사유를 입력해 주세요.",
|
||||
{
|
||||
title: isRemove ? "삭제 사유" : "수정 사유",
|
||||
onConfirm: function(reason) { submitUser(targetCmd, reason); }
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// 신규 등록: 사유 불필요
|
||||
if (!confirm("<%= localeMessage.getString("common.checkSave")%>")) return;
|
||||
submitUser("INSERT", null);
|
||||
}
|
||||
});
|
||||
|
||||
$("#btn_previous").click(function () {
|
||||
@@ -518,21 +542,26 @@
|
||||
});
|
||||
|
||||
$("#btn_delete").click(function () {
|
||||
if (!confirm("<%= localeMessage.getString("common.confirmMsg")%>")) return;
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: {
|
||||
cmd: "DELETE",
|
||||
id: $('input[name=id]').val()
|
||||
},
|
||||
success: function () {
|
||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
showReasonPrompt("해당 가입자를 삭제 처리합니다. 사유를 입력해 주세요.", {
|
||||
title: "삭제 사유",
|
||||
onConfirm: function(reason) {
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: url,
|
||||
data: {
|
||||
cmd: "DELETE",
|
||||
id: $('input[name=id]').val(),
|
||||
serviceType: "APIGW",
|
||||
auditReason: reason
|
||||
},
|
||||
success: function () {
|
||||
alert("<%= localeMessage.getString("common.deleteMsg") %>");
|
||||
goNav(returnUrl);
|
||||
},
|
||||
error: function (e) {
|
||||
alert(e.responseText);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,242 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
||||
<%@ page import="java.io.*" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||
<%
|
||||
response.setHeader("Pragma", "No-cache");
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
||||
<style>
|
||||
.url-cell { display:inline-block; max-width:380px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; vertical-align:middle; }
|
||||
.succ-y { color:#1a73e8; font-weight:bold; }
|
||||
.succ-n { color:#d93025; font-weight:bold; }
|
||||
</style>
|
||||
<script language="javascript">
|
||||
var url = '<c:url value="/onl/apim/webhook/webhookSendLogMan.json" />';
|
||||
var url_view = '<c:url value="/onl/apim/webhook/webhookSendLogMan.view" />';
|
||||
var combo;
|
||||
|
||||
function escapeHtmlJs(s) { return $('<div>').text(s == null ? '' : s).html(); }
|
||||
function escapeAttr(s) { return escapeHtmlJs(s).replace(/"/g, '"'); }
|
||||
|
||||
function formatTargetUrl(cellvalue, options, rowObject) {
|
||||
var v = cellvalue || '';
|
||||
return '<span class="url-cell" title="' + escapeAttr(v) + '">' + escapeHtmlJs(v) + '</span>';
|
||||
}
|
||||
|
||||
// 이벤트유형 코드 → 모니터링 공통코드(EVENT_TYPE) 코드명
|
||||
function formatEventType(cellvalue, options, rowObject) {
|
||||
if (!combo || !combo.eventTypeList) {
|
||||
return escapeHtmlJs(cellvalue);
|
||||
}
|
||||
for (var i = 0; i < combo.eventTypeList.length; i++) {
|
||||
if (combo.eventTypeList[i].CODE == cellvalue) {
|
||||
return escapeHtmlJs(combo.eventTypeList[i].NAME);
|
||||
}
|
||||
}
|
||||
return escapeHtmlJs(cellvalue);
|
||||
}
|
||||
|
||||
function formatSuccess(cellvalue, options, rowObject) {
|
||||
if (cellvalue === true) return '<span class="succ-y">성공</span>';
|
||||
if (cellvalue === false) return '<span class="succ-n">실패</span>';
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
|
||||
$("#startDatepicker").datepicker().inputmask("yyyy-mm-dd",{'autoUnmask':true});
|
||||
$("#endDatepicker").datepicker().inputmask("yyyy-mm-dd",{'autoUnmask':true});
|
||||
|
||||
var today = getToday();
|
||||
|
||||
$("input[name=searchStartYYYYMMDD]").val(today.substring(0,6)+"01");
|
||||
$("input[name=searchEndYYYYMMDD]").val(today);
|
||||
$("input[name=searchStartDate]").val(today.substring(0,6)+"01");
|
||||
$("input[name=searchEndDate]").val(today);
|
||||
|
||||
$.ajax({
|
||||
type: "POST", url: url, dataType: "json",
|
||||
data: {cmd: 'LIST_INIT_COMBO'},
|
||||
success: function (json) {
|
||||
combo = json;
|
||||
new makeOptions("CODE", "NAME").setObj($("select[name=searchEventType]"))
|
||||
.setNoValueInclude(true).setNoValue("", "<%=localeMessage.getString("combo.all")%>")
|
||||
.setData(json.eventTypeList).rendering();
|
||||
|
||||
// 뒤로가기 등으로 이전 검색조건 파라미터가 있으면 기본값을 덮어씀
|
||||
putSelectFromParam();
|
||||
|
||||
// 콤보(이벤트유형) 로드 후 그리드 생성 — formatEventType 경합 방지
|
||||
buildGrid();
|
||||
},
|
||||
error: function (e) { alert(e.responseText); }
|
||||
});
|
||||
}
|
||||
|
||||
function buildGrid() {
|
||||
$('#grid').jqGrid({
|
||||
datatype: "json",
|
||||
mtype: 'POST',
|
||||
url: url,
|
||||
postData: getSearchForJqgrid("cmd", "LIST"),
|
||||
colNames: ['id', 'No.', '기관명', '이벤트유형', 'Target URL', 'Proxy URL', 'Status', '성공여부', '발송서버', '발송일시'],
|
||||
colModel: [
|
||||
{name: 'id', align: 'center', key: true, hidden: true},
|
||||
{name: 'rowNum', align: 'center', width: 45, sortable: false},
|
||||
{name: 'orgName', align: 'left', width: 140},
|
||||
{name: 'eventType', align: 'center', width: 120, formatter: formatEventType},
|
||||
{name: 'targetUrl', align: 'left', width: 300, formatter: formatTargetUrl},
|
||||
{name: 'proxyUrl', align: 'left', width: 300, formatter: formatTargetUrl},
|
||||
{name: 'statusCode', align: 'center', width: 60},
|
||||
{name: 'success', align: 'center', width: 70, formatter: formatSuccess},
|
||||
{name: 'sendBy', align: 'center', width: 100},
|
||||
{name: 'sentAt', align: 'center', width: 140}
|
||||
],
|
||||
jsonReader: {repeatitems: false},
|
||||
pager: $('#pager'),
|
||||
page: '${param.page}',
|
||||
rowNum: '${rmsDefaultRowNum}',
|
||||
autoheight: true,
|
||||
height: $("#container").height(),
|
||||
autowidth: true,
|
||||
viewrecords: true,
|
||||
rowList: eval('[${rmsDefaultRowList}]'),
|
||||
ondblClickRow: function (rowId) {
|
||||
var rowData = $(this).getRowData(rowId);
|
||||
var id = rowData['id'];
|
||||
var url2 = url_view + '?cmd=DETAIL';
|
||||
url2 += '&page=' + $(this).getGridParam("page");
|
||||
url2 += '&returnUrl=' + getReturnUrl();
|
||||
url2 += '&menuId=' + '${param.menuId}';
|
||||
url2 += '&id=' + id;
|
||||
url2 += '&' + getSearchUrl();
|
||||
goNav(url2);
|
||||
},
|
||||
loadComplete: function () {
|
||||
var page = $(this).getGridParam('page');
|
||||
var rowNum = $(this).getGridParam('rowNum');
|
||||
var rows = $(this).getDataIDs();
|
||||
var colModel = $(this).getGridParam("colModel");
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
var number = ((page - 1) * rowNum + i) + 1;
|
||||
$(this).setCell(rows[i], 'rowNum', number);
|
||||
}
|
||||
// 서버 고정 정렬(등록일시 역순) — 컬럼 정렬 비활성
|
||||
for (var i = 0; i < colModel.length; i++) {
|
||||
$(this).setColProp(colModel[i].name, {sortable: false});
|
||||
}
|
||||
},
|
||||
loadError: function (jqXHR, textStatus, errorThrown) {
|
||||
var location = '<%=request.getContextPath()%>/';
|
||||
comloadError(jqXHR, textStatus, errorThrown, location);
|
||||
}
|
||||
});
|
||||
resizeJqGridWidth('grid', 'content_middle', '1000');
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
init();
|
||||
|
||||
$("#btn_search").click(function () {
|
||||
var start = $("input[name=searchStartYYYYMMDD]").val().replace(/-/gi, "");
|
||||
var end = $("input[name=searchEndYYYYMMDD]").val().replace(/-/gi, "");
|
||||
|
||||
if (start && start > getToday()) {
|
||||
alert("시작일이 오늘 이후입니다. 시작일을 확인해주세요.");
|
||||
$("input[name=searchStartYYYYMMDD]").focus();
|
||||
return false;
|
||||
}
|
||||
if (start && end && start > end) {
|
||||
alert("조회기간 종료일은 시작일보다 커야합니다.");
|
||||
$("input[name=searchEndYYYYMMDD]").focus();
|
||||
return false;
|
||||
}
|
||||
$("input[name=searchStartDate]").val(start);
|
||||
$("input[name=searchEndDate]").val(end);
|
||||
|
||||
var postData = getSearchForJqgrid("cmd", "LIST");
|
||||
$("#grid").setGridParam({url: url, postData: postData, page: 1}).trigger("reloadGrid");
|
||||
});
|
||||
|
||||
$("select[name^=search]").change(function () { $("#btn_search").click(); });
|
||||
$("input[name^=search]").keydown(function (key) {
|
||||
if (key.keyCode == 13) { $("#btn_search").click(); }
|
||||
});
|
||||
|
||||
|
||||
|
||||
buttonControl();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right_box">
|
||||
<div class="content_top">
|
||||
<ul class="path"><li><a href="#">${rmsMenuPath}</a></li></ul>
|
||||
</div><!-- end content_top -->
|
||||
<div class="content_middle" id="content_middle">
|
||||
<div class="search_wrap">
|
||||
<button type="button" class="cssbtn" id="btn_search" level="R"><i class="material-icons">search</i> <%= localeMessage.getString("button.search") %></button>
|
||||
</div>
|
||||
<div class="title">웹훅 발송 로그<span class="tooltip">외부로 발송된 웹훅 이력을 조회합니다.</span></div>
|
||||
<form id="ajaxForm" onsubmit="return false;">
|
||||
<table class="search_condition" cellspacing=0;>
|
||||
<colgroup>
|
||||
<col style="width:120px;"><col style="width:200px;">
|
||||
<col style="width:120px;"><col style="width:200px;">
|
||||
<col style="width:120px;"><col style="width:200px;">
|
||||
</colgroup>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>기관명</th>
|
||||
<td><input type="text" name="searchOrgName" autocomplete="off"></td>
|
||||
<th>이벤트유형</th>
|
||||
<td>
|
||||
<div class="select-style">
|
||||
<select name="searchEventType"></select>
|
||||
</div>
|
||||
</td>
|
||||
<th>성공여부</th>
|
||||
<td>
|
||||
<div class="select-style">
|
||||
<select name="searchSuccess">
|
||||
<option value="">전체</option>
|
||||
<option value="Y">성공</option>
|
||||
<option value="N">실패</option>
|
||||
</select>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Target URL</th>
|
||||
<td><input type="text" name="searchTargetUrl" autocomplete="off" style="width:95%;"></td>
|
||||
<th>발송기간</th>
|
||||
<td>
|
||||
<input type="text" name="searchStartYYYYMMDD" id="startDatepicker" readonly="readonly" value="" size="10" style="width:40%; border:1px solid #ebebec;">
|
||||
~
|
||||
<input type="text" name="searchEndYYYYMMDD" value="" id="endDatepicker" size="10" readonly="readonly" style="width:40%; border:1px solid #ebebec;">
|
||||
<input type="hidden" name="searchStartDate" value="">
|
||||
<input type="hidden" name="searchEndDate" value="">
|
||||
</td>
|
||||
<th></th>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</form>
|
||||
<table id="grid"></table>
|
||||
<div id="pager"></div>
|
||||
</div><!-- end content_middle -->
|
||||
</div><!-- end right_box -->
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,137 @@
|
||||
<%@ page language="java" contentType="text/html; charset=utf-8" %>
|
||||
<%@ page import="java.io.*" %>
|
||||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
|
||||
<%@ taglib uri="http://www.springframework.org/tags" prefix="spring" %>
|
||||
<%@ include file="/jsp/common/include/localemessage.jsp" %>
|
||||
<%
|
||||
response.setHeader("Pragma", "No-cache");
|
||||
response.setHeader("Cache-Control", "no-cache");
|
||||
response.setHeader("Expires", "0");
|
||||
%>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<jsp:include page="/jsp/common/include/css.jsp"/>
|
||||
<jsp:include page="/jsp/common/include/script.jsp"/>
|
||||
<style>
|
||||
.succ-y { color:#1a73e8; font-weight:bold; }
|
||||
.succ-n { color:#d93025; font-weight:bold; }
|
||||
.pre-wrap { white-space:pre-wrap; word-break:break-all; min-height:60px; line-height:1.5; }
|
||||
</style>
|
||||
<script language="javascript">
|
||||
var url = '<c:url value="/onl/apim/webhook/webhookSendLogMan.json" />';
|
||||
var url_view = '<c:url value="/onl/apim/webhook/webhookSendLogMan.view" />';
|
||||
var key = '${param.id}';
|
||||
|
||||
function escapeHtmlJs(s) { return $('<div>').text(s == null ? '' : s).html(); }
|
||||
|
||||
function detail() {
|
||||
if (!key) return;
|
||||
$.ajax({
|
||||
type: "POST", url: url, dataType: "json",
|
||||
data: {cmd: 'DETAIL', id: key},
|
||||
success: function (data) {
|
||||
$('#id').text(data.id != null ? data.id : '');
|
||||
$('#orgName').text(data.orgName || '');
|
||||
$('#eventType').text(data.eventTypeName || data.eventType || '')
|
||||
.attr('title', data.eventType || '');
|
||||
$('#targetUrl').text(data.targetUrl || '');
|
||||
$('#proxyUrl').text(data.proxyUrl || '');
|
||||
$('#statusCode').text(data.statusCode != null ? data.statusCode : '');
|
||||
$('#retryCount').text(data.retryCount != null ? data.retryCount : '');
|
||||
$('#sendBy').text(data.sendBy || '');
|
||||
$('#sentAt').text(data.sentAt || '');
|
||||
$('#signature').text(data.signature || '');
|
||||
$('#errorMessage').text(data.errorMessage || '');
|
||||
$('#payload').text(data.payload || '');
|
||||
$('#responseBody').text(data.responseBody || '');
|
||||
|
||||
if (data.success === true) {
|
||||
$('#success').html('<span class="succ-y">성공</span>');
|
||||
} else if (data.success === false) {
|
||||
$('#success').html('<span class="succ-n">실패</span>');
|
||||
} else {
|
||||
$('#success').text('');
|
||||
}
|
||||
},
|
||||
error: function (e) { alert(e.responseText); }
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
var returnUrl = getReturnUrlForReturn();
|
||||
|
||||
buttonControl();
|
||||
detail();
|
||||
|
||||
$('#btn_previous').click(function () { goNav(returnUrl); });
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="right_box">
|
||||
<div class="content_top">
|
||||
<ul class="path"><li><a href="#">${rmsMenuPath}</a></li></ul>
|
||||
</div>
|
||||
<div class="content_middle">
|
||||
<div class="search_wrap">
|
||||
<button type="button" class="cssbtn" id="btn_previous" level="R" status="DETAIL,NEW"><i class="material-icons">arrow_back</i> <%= localeMessage.getString("button.previous") %></button>
|
||||
</div>
|
||||
<div class="title" id="title">웹훅 발송 로그 상세</div>
|
||||
<table class="table_row" cellspacing="0">
|
||||
<colgroup>
|
||||
<col style="width:12%"/><col style="width:38%"/>
|
||||
<col style="width:12%"/><col style="width:38%"/>
|
||||
</colgroup>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<td><span id="id"></span></td>
|
||||
<th>기관명</th>
|
||||
<td><span id="orgName"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>이벤트유형</th>
|
||||
<td><span id="eventType"></span></td>
|
||||
<th>Status Code</th>
|
||||
<td><span id="statusCode"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Target URL</th>
|
||||
<td><span id="targetUrl"></span></td>
|
||||
<th>Proxy URL</th>
|
||||
<td><span id="proxyUrl"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>성공여부</th>
|
||||
<td><span id="success"></span></td>
|
||||
<th>재시도횟수</th>
|
||||
<td><span id="retryCount"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>발송서버</th>
|
||||
<td><span id="sendBy"></span></td>
|
||||
<th>발송일시</th>
|
||||
<td><span id="sentAt"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Signature</th>
|
||||
<td colspan="3"><span id="signature"></span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Payload</th>
|
||||
<td colspan="3"><div id="payload" class="pre-wrap"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Response Body</th>
|
||||
<td colspan="3"><div id="responseBody" class="pre-wrap"></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>에러 메세지</th>
|
||||
<td colspan="3"><div id="errorMessage" class="pre-wrap"></div></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -486,6 +486,7 @@
|
||||
}
|
||||
|
||||
if(data.errResponseTransform != null && data.errResponseTransform != '' && data.errTransformYn == 'Y') {
|
||||
$('#toggleTransformYn').bootstrapToggle('on');
|
||||
$('#toggleErrTransformYn').bootstrapToggle('on');
|
||||
$('#rowErrResponseTransform').show();
|
||||
} else {
|
||||
|
||||
+3
-1
@@ -41,10 +41,12 @@ public class AuditLogInterceptor implements HandlerInterceptor {
|
||||
|
||||
if (isAuditableUsecase.isAuditable(userId, command, logType, systemCode)) {
|
||||
String parameters = getParametersAsString(request);
|
||||
String message = request.getParameter("auditReason");
|
||||
log
|
||||
.debug("audit log save : logType={}, cmd={}, user={}, parameters={}", logType, command,
|
||||
userId, parameters);
|
||||
saveAuditLogUseCase.log(systemCode, logType, command, remoteAddress, userId, parameters);
|
||||
saveAuditLogUseCase
|
||||
.log(systemCode, logType, command, remoteAddress, userId, parameters, message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ public class AuditLog {
|
||||
|
||||
private String logTypeText;
|
||||
|
||||
private String message;
|
||||
|
||||
private String parameters;
|
||||
|
||||
private LocalDateTime lastModifiedDate;
|
||||
|
||||
@@ -3,6 +3,6 @@ package com.eactive.eai.rms.common.acl.audit.port.in;
|
||||
public interface SaveAuditLogUseCase {
|
||||
|
||||
public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
|
||||
String parameters);
|
||||
String parameters, String message);
|
||||
|
||||
}
|
||||
|
||||
@@ -59,15 +59,16 @@ class AuditLogService
|
||||
|
||||
@Override
|
||||
public void log(String systemCode, String logType, String command, String remoteAddress, String userId,
|
||||
String parameters) {
|
||||
String parameters, String message) {
|
||||
|
||||
AuditLog auditLog = new AuditLog(systemCode, logType, command, userId, remoteAddress);
|
||||
String auditPointKey = AuditPoint.generateKey(logType, systemCode, command);
|
||||
AuditPoint auditPoint = auditPoints.get(auditPointKey);
|
||||
|
||||
|
||||
auditLog.setLogTypeText(auditPoint.getLogTypeText());
|
||||
auditLog.setLastModifiedDate(LocalDateTime.now());
|
||||
auditLog.setParameters(parameters);
|
||||
auditLog.setMessage(message);
|
||||
|
||||
saveAuditLogPort.save(auditLog);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,8 @@ import lombok.RequiredArgsConstructor;
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
@RequiredArgsConstructor
|
||||
public class UserManService extends BaseService {
|
||||
|
||||
|
||||
|
||||
private final UserInfoService userInfoService;
|
||||
private final UserRoleService userRoleService;
|
||||
@@ -98,9 +100,11 @@ public class UserManService extends BaseService {
|
||||
|
||||
UserInfo userInfo = userUIMapper.toEntity(userUI);
|
||||
userInfo.setRoleidnfiname(CommonConstants.DEPT_DEVELOPER);
|
||||
|
||||
String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
|
||||
|
||||
try {
|
||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256,userUI.getUserId()));
|
||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256,userUI.getUserId()+subfix));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error encrypting password", e);
|
||||
}
|
||||
@@ -140,8 +144,9 @@ public class UserManService extends BaseService {
|
||||
}
|
||||
|
||||
public void updatePassword(UserUI userUI) throws Exception {
|
||||
String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
|
||||
UserInfo userInfo = userInfoService.getById(userUI.getUserId());
|
||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256, userUI.getUserId()));
|
||||
userInfo.setPassword(DamoManager.getInstance().hash(DamoManager.SHA256, userUI.getUserId()+subfix));
|
||||
userUIMapper.updateToEntity(userUI, userInfo);
|
||||
userInfoService.save(userInfo);
|
||||
}
|
||||
|
||||
@@ -258,9 +258,15 @@ public interface MonitoringContext {
|
||||
// 자동 로그아웃 타임아웃 (단위: 분, 기본값: 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";
|
||||
// 웹훅
|
||||
public static final String RMS_WEBHOOK_REVERSE_PROXY_URL = "rms.webhook.reverse_proxy.url";
|
||||
public static final String RMS_WEBHOOK_RETRY_COUNT = "rms.webhook.retry_count";
|
||||
public static final String RMS_WEBHOOK_RETRY_TIME = "rms.webhook.retry_time";
|
||||
|
||||
//비밀번호 초기화 접미사
|
||||
public static final String RMS_PASSWORD_INIT_SUBFIX = "rms.password.init.subfix";
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -45,4 +45,9 @@ public class LoginResponseDto {
|
||||
* 에러 메시지 (로그인 실패 시)
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 초기 비밀번호 변경 필요 여부
|
||||
*/
|
||||
private boolean changePassword;
|
||||
}
|
||||
|
||||
@@ -191,6 +191,19 @@ public class MainController implements InterceptorSkipController {
|
||||
.redirectUrl(redirectUrl)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
// 2.1 초기 비밀번호인 경우, 비밀번호 변경해야 함
|
||||
String subfix = monitoringContext.getStringProperty(MonitoringContext.RMS_PASSWORD_INIT_SUBFIX, "@!");
|
||||
if (userInfo.getPassword().equals(DamoManager.getInstance().hash(DamoManager.SHA256, userInfo.getUserid()+subfix))
|
||||
|| userInfo.getPassword().equals(DamoManager.getInstance().hash(DamoManager.SHA256, userInfo.getUserid()))) {
|
||||
return LoginResponseDto.builder()
|
||||
.success(false)
|
||||
.changePassword(true)
|
||||
.errorMessage("비밀번호 변경후 사용가능합니다.")
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
// 3. SMS 인증 필요 여부 체크
|
||||
SmsAuthService smsAuthService = getSmsAuthService();
|
||||
@@ -758,6 +771,9 @@ public class MainController implements InterceptorSkipController {
|
||||
String changePassword, String confirmPassword,
|
||||
String resetUserId, String resetPassword) {
|
||||
HttpSession session = request.getSession();
|
||||
// AJAX 로그인 인증 후 초기비밀번호 변경 경로에서 세션에 부분 로그인 상태가 남아
|
||||
// root emergency.jsp가 main.do로 잘못 리다이렉트하는 것을 방지
|
||||
session.removeAttribute(CommonConstants.LOGIN);
|
||||
|
||||
try {
|
||||
|
||||
@@ -815,6 +831,8 @@ public class MainController implements InterceptorSkipController {
|
||||
.getString("login.pwdchanged"));
|
||||
session.setAttribute(RESULT_MSG, localeMessage
|
||||
.getString("login.pwdchanged"));
|
||||
logger.debug("\n\n\n\n===================" + localeMessage
|
||||
.getString("login.pwdchanged"));
|
||||
return REDIRECT_LOGIN_URL;
|
||||
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -26,9 +26,12 @@ public class WebhookSendLog {
|
||||
)
|
||||
private Long id;
|
||||
|
||||
@Column(name = "TARGET_URL", nullable = false, length = 500)
|
||||
@Column(name = "TARGET_URL", length = 500)
|
||||
private String targetUrl;
|
||||
|
||||
@Column(name = "PROXY_URL", length = 500)
|
||||
private String proxyUrl;
|
||||
|
||||
@Column(name = "EVENT_TYPE", length = 100)
|
||||
private String eventType;
|
||||
|
||||
@@ -66,6 +69,9 @@ public class WebhookSendLog {
|
||||
@Column(name = "SENT_AT")
|
||||
private LocalDateTime sentAt;
|
||||
|
||||
@Column(name = "SEND_BY", length = 100)
|
||||
private String sendBy;
|
||||
|
||||
/* Boolean 편의 메서드 */
|
||||
public void setSuccess(Boolean success) {
|
||||
this.success = (success != null && success) ? "Y" : "N";
|
||||
|
||||
@@ -126,6 +126,15 @@ public class EAILogRepositoryImpl implements EAILogRepository {
|
||||
query.where(qeaiLog.eaisvcname.containsIgnoreCase(eaiLogSearch.getSearchEaiSvcName()));
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(eaiLogSearch.getSearchEaiSvcDesc())) {
|
||||
QEAIMessageEntity qeaiMessageEntity = QEAIMessageEntity.eAIMessageEntity;
|
||||
JPAQuery<String> subQuery = new JPAQueryFactory(em)
|
||||
.select(qeaiMessageEntity.eaisvcname)
|
||||
.from(qeaiMessageEntity)
|
||||
.where(qeaiMessageEntity.eaisvcdesc.containsIgnoreCase(eaiLogSearch.getSearchEaiSvcDesc()));
|
||||
query.where(qeaiLog.eaisvcname.in(subQuery));
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(eaiLogSearch.getSearchKeyMgtMsgCtnt())) {
|
||||
query.where(qeaiLog.keymgtmsgctnt.contains(eaiLogSearch.getSearchKeyMgtMsgCtnt()));
|
||||
}
|
||||
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.controller;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
import com.eactive.eai.rms.common.base.BaseAnnotationController;
|
||||
import com.eactive.eai.rms.common.combo.ComboService;
|
||||
import com.eactive.eai.rms.common.vo.GridResponse;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendLogUI;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendLogUISearch;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.service.WebhookSendLogManService;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 웹훅 발송 로그(PTL_WEBHOOK_SEND_LOG) 조회 화면 컨트롤러.
|
||||
*
|
||||
* <p>조회 전용 (등록/수정/삭제 없음)</p>
|
||||
*/
|
||||
@Controller
|
||||
@RequiredArgsConstructor
|
||||
public class WebhookSendLogManController extends BaseAnnotationController {
|
||||
|
||||
private final WebhookSendLogManService webhookSendLogManService;
|
||||
private final ComboService comboService;
|
||||
|
||||
@GetMapping(value = "/onl/apim/webhook/webhookSendLogMan.view")
|
||||
public void view() {
|
||||
// 목록 view
|
||||
}
|
||||
|
||||
@GetMapping(value = "/onl/apim/webhook/webhookSendLogMan.view", params = "cmd=DETAIL")
|
||||
public String detailView() {
|
||||
return "/onl/apim/webhook/webhookSendLogManDetail";
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/webhook/webhookSendLogMan.json", params = "cmd=LIST")
|
||||
public ResponseEntity<GridResponse<WebhookSendLogUI>> selectList(
|
||||
@SortDefault(sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable,
|
||||
WebhookSendLogUISearch search) {
|
||||
Page<WebhookSendLogUI> page = webhookSendLogManService.selectList(pageable, search);
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/webhook/webhookSendLogMan.json", params = "cmd=LIST_INIT_COMBO")
|
||||
public ResponseEntity<Map<String, Object>> initCombo() {
|
||||
Map<String, Object> resultMap = new HashMap<>();
|
||||
resultMap.put("eventTypeList", comboService.getMonitoringCodeSortedBySeq(WebhookSendLogManService.CODE_GROUP_EVENT_TYPE));
|
||||
return ResponseEntity.ok(resultMap);
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/apim/webhook/webhookSendLogMan.json", params = "cmd=DETAIL")
|
||||
public ResponseEntity<WebhookSendLogUI> selectDetail(Long id) {
|
||||
return ResponseEntity.ok(webhookSendLogManService.selectDetail(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 웹훅 발송 로그(PTL_WEBHOOK_SEND_LOG) 화면 응답 DTO.
|
||||
*
|
||||
* <p>목록에서는 일부 항목만 사용하고, 상세에서는 전체 항목을 사용한다.
|
||||
* 날짜는 yyyyMMdd HH:mm:ss 형식 문자열로 제공한다.</p>
|
||||
*/
|
||||
@Data
|
||||
public class WebhookSendLogUI {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String orgId;
|
||||
private String orgName;
|
||||
|
||||
private String eventType;
|
||||
/** 모니터링 공통코드(EVENT_TYPE) 코드명. 상세 조회에서만 채워진다(목록은 화면에서 콤보로 변환). */
|
||||
private String eventTypeName;
|
||||
private String targetUrl;
|
||||
private String proxyUrl;
|
||||
|
||||
private String payload;
|
||||
private String signature;
|
||||
|
||||
private Integer statusCode;
|
||||
private String responseBody;
|
||||
|
||||
private Boolean success;
|
||||
private String sendBy;
|
||||
private String errorMessage;
|
||||
private Integer retryCount;
|
||||
|
||||
/* 등록/발송 시간 — yyyyMMdd HH:mm:ss */
|
||||
private String createdAt;
|
||||
private String sentAt;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WebhookSendLogUISearch {
|
||||
|
||||
/* 기관명 (ptl_org.org_name, LIKE 검색) */
|
||||
private String searchOrgName;
|
||||
|
||||
/* 이벤트 유형 (모니터링 공통코드 EVENT_TYPE, 콤보 선택 값과 정확히 일치) */
|
||||
private String searchEventType;
|
||||
|
||||
/* 수신 URL (LIKE 검색) */
|
||||
private String searchTargetUrl;
|
||||
|
||||
/* 성공여부 (Y/N, 공백=전체) */
|
||||
private String searchSuccess;
|
||||
|
||||
/* 발송일시 기간 검색 (yyyyMMdd, 8자리 — userLoginHistoryMan.jsp 기간검색 스타일) */
|
||||
private String searchStartDate;
|
||||
private String searchEndDate;
|
||||
}
|
||||
@@ -8,7 +8,9 @@ import lombok.Setter;
|
||||
public class WebhookSendRequest {
|
||||
private String orgId;
|
||||
private String targetUrl;
|
||||
private String proxyUrl;
|
||||
private String eventType;
|
||||
private String secret;
|
||||
private String reverseProxyPath;
|
||||
private Object data;
|
||||
}
|
||||
+2
-2
@@ -4,17 +4,17 @@ package com.eactive.eai.rms.ext.djb.webhook.repository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import com.eactive.eai.data.jpa.BaseRepository;
|
||||
import com.eactive.eai.rms.data.EMSDataSource;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.WebhookSendLog;
|
||||
|
||||
@Repository
|
||||
@EMSDataSource
|
||||
public interface WebhookSendLogRepository extends JpaRepository<WebhookSendLog, Long> {
|
||||
public interface WebhookSendLogRepository extends BaseRepository<WebhookSendLog, Long> {
|
||||
|
||||
// 오라클 CHAR(1) Y/N 기준 조회
|
||||
@Query("SELECT l FROM WebhookSendLog l " +
|
||||
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package com.eactive.eai.rms.ext.djb.webhook.service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
|
||||
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.monitoringcode.entity.MonitoringCode;
|
||||
import com.eactive.apim.portal.monitoringcode.entity.MonitoringCodeId;
|
||||
import com.eactive.apim.portal.portalorg.entity.QPortalOrg;
|
||||
import com.eactive.eai.rms.common.base.BaseService;
|
||||
import com.eactive.eai.rms.common.util.StringUtils;
|
||||
import com.eactive.eai.rms.data.entity.man.monitoringCode.repository.MonitoringCodeRepository;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.QWebhookSendLog;
|
||||
import com.eactive.eai.rms.data.entity.onl.djb.webhook.WebhookSendLog;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendLogUI;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.dto.WebhookSendLogUISearch;
|
||||
import com.eactive.eai.rms.ext.djb.webhook.repository.WebhookSendLogRepository;
|
||||
import com.eactive.eai.rms.onl.common.exception.BizException;
|
||||
import com.querydsl.core.BooleanBuilder;
|
||||
import com.querydsl.jpa.impl.JPAQueryFactory;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 웹훅 발송 로그(PTL_WEBHOOK_SEND_LOG) 조회 화면 서비스.
|
||||
*
|
||||
* <p>조회 전용. orgId 는 엔티티 연관관계가 아닌 단순 컬럼이므로,
|
||||
* 기관명은 QueryDSL 로 ptl_org 를 별도 조회하여 매핑한다.</p>
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
@Transactional(transactionManager = "transactionManagerForEMS")
|
||||
public class WebhookSendLogManService extends BaseService {
|
||||
|
||||
/** 모니터링 공통코드(tseairm28) 상의 웹훅 이벤트유형 코드 그룹. */
|
||||
public static final String CODE_GROUP_EVENT_TYPE = "EVENT_TYPE";
|
||||
|
||||
private static final DateTimeFormatter FMT_DATETIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
private static final DateTimeFormatter FMT_YYYYMMDD = DateTimeFormatter.ofPattern("yyyyMMdd");
|
||||
|
||||
private final WebhookSendLogRepository webhookSendLogRepository;
|
||||
private final MonitoringCodeRepository monitoringCodeRepository;
|
||||
|
||||
@PersistenceContext(unitName = "entityManagerFactoryForEMS")
|
||||
private EntityManager entityManager;
|
||||
|
||||
public Page<WebhookSendLogUI> selectList(Pageable pageable, WebhookSendLogUISearch search) {
|
||||
QWebhookSendLog log = QWebhookSendLog.webhookSendLog;
|
||||
BooleanBuilder predicate = new BooleanBuilder();
|
||||
|
||||
if (StringUtils.isNotBlank(search.getSearchOrgName())) {
|
||||
List<String> orgIds = findOrgIdsByName(search.getSearchOrgName());
|
||||
if (orgIds.isEmpty()) {
|
||||
// 일치하는 기관이 없으면 쿼리를 실행할 필요 없이 빈 결과를 바로 반환한다.
|
||||
// (QueryDSL의 where false 는 이 프로젝트의 Hibernate HQL 파서에서 지원하지 않음)
|
||||
return Page.empty(pageable);
|
||||
}
|
||||
predicate.and(log.orgId.in(orgIds));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchEventType())) {
|
||||
predicate.and(log.eventType.eq(search.getSearchEventType()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchTargetUrl())) {
|
||||
predicate.and(log.targetUrl.containsIgnoreCase(search.getSearchTargetUrl()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchSuccess())) {
|
||||
predicate.and(log.success.eq(search.getSearchSuccess()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchStartDate())) {
|
||||
predicate.and(log.sentAt.goe(parseYYYYMMDD(search.getSearchStartDate()).atStartOfDay()));
|
||||
}
|
||||
if (StringUtils.isNotBlank(search.getSearchEndDate())) {
|
||||
predicate.and(log.sentAt.loe(parseYYYYMMDD(search.getSearchEndDate()).atTime(23, 59, 59)));
|
||||
}
|
||||
|
||||
Page<WebhookSendLog> page = webhookSendLogRepository.findAll(predicate, pageable);
|
||||
|
||||
Map<String, String> orgNameMap = findOrgNames(page.getContent());
|
||||
// 목록의 이벤트유형 코드명은 화면에서 콤보(LIST_INIT_COMBO) 기준으로 변환하므로 서버에서는 조회하지 않는다(N+1 방지).
|
||||
return page.map(e -> convertToUI(e, orgNameMap.get(e.getOrgId()), null));
|
||||
}
|
||||
|
||||
public WebhookSendLogUI selectDetail(Long id) {
|
||||
WebhookSendLog entity = webhookSendLogRepository.findById(id)
|
||||
.orElseThrow(() -> new BizException("존재하지 않는 웹훅 발송 로그입니다."));
|
||||
|
||||
Map<String, String> orgNameMap = findOrgNames(Collections.singletonList(entity));
|
||||
String eventTypeName = resolveEventTypeName(entity.getEventType());
|
||||
return convertToUI(entity, orgNameMap.get(entity.getOrgId()), eventTypeName);
|
||||
}
|
||||
|
||||
private static LocalDate parseYYYYMMDD(String yyyyMMdd) {
|
||||
return LocalDate.parse(yyyyMMdd, FMT_YYYYMMDD);
|
||||
}
|
||||
|
||||
/** 모니터링 공통코드(EVENT_TYPE)에서 코드명을 조회한다. 코드가 없으면 원본 코드를 그대로 반환한다. */
|
||||
private String resolveEventTypeName(String eventType) {
|
||||
if (StringUtils.isBlank(eventType)) {
|
||||
return eventType;
|
||||
}
|
||||
return monitoringCodeRepository.findById(new MonitoringCodeId(CODE_GROUP_EVENT_TYPE, eventType))
|
||||
.map(MonitoringCode::getCodeName)
|
||||
.orElse(eventType);
|
||||
}
|
||||
|
||||
/** 기관명 LIKE 검색으로 매칭되는 orgId 목록. */
|
||||
private List<String> findOrgIdsByName(String orgName) {
|
||||
QPortalOrg org = QPortalOrg.portalOrg;
|
||||
return new JPAQueryFactory(entityManager)
|
||||
.select(org.id)
|
||||
.from(org)
|
||||
.where(org.orgName.containsIgnoreCase(orgName))
|
||||
.fetch();
|
||||
}
|
||||
|
||||
/** 목록/상세에 필요한 orgId → orgName 매핑 (일괄 조회로 N+1 방지). */
|
||||
private Map<String, String> findOrgNames(List<WebhookSendLog> logs) {
|
||||
Set<String> orgIds = logs.stream()
|
||||
.map(WebhookSendLog::getOrgId)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
if (orgIds.isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
QPortalOrg org = QPortalOrg.portalOrg;
|
||||
return new JPAQueryFactory(entityManager)
|
||||
.select(org.id, org.orgName)
|
||||
.from(org)
|
||||
.where(org.id.in(orgIds))
|
||||
.fetch()
|
||||
.stream()
|
||||
.collect(Collectors.toMap(t -> t.get(org.id), t -> t.get(org.orgName)));
|
||||
}
|
||||
|
||||
private WebhookSendLogUI convertToUI(WebhookSendLog e, String orgName, String eventTypeName) {
|
||||
WebhookSendLogUI ui = new WebhookSendLogUI();
|
||||
ui.setId(e.getId());
|
||||
ui.setOrgId(e.getOrgId());
|
||||
ui.setOrgName(orgName);
|
||||
ui.setEventType(e.getEventType());
|
||||
ui.setEventTypeName(eventTypeName);
|
||||
ui.setTargetUrl(e.getTargetUrl());
|
||||
ui.setProxyUrl(e.getProxyUrl());
|
||||
ui.setPayload(e.getPayload());
|
||||
ui.setSignature(e.getSignature());
|
||||
ui.setStatusCode(e.getStatusCode());
|
||||
ui.setResponseBody(e.getResponseBody());
|
||||
ui.setSuccess(e.getSuccess());
|
||||
ui.setSendBy(e.getSendBy());
|
||||
ui.setErrorMessage(e.getErrorMessage());
|
||||
ui.setRetryCount(e.getRetryCount());
|
||||
ui.setCreatedAt(fmt(e.getCreatedAt(), FMT_DATETIME));
|
||||
ui.setSentAt(fmt(e.getSentAt(), FMT_DATETIME));
|
||||
return ui;
|
||||
}
|
||||
|
||||
private static String fmt(LocalDateTime t, DateTimeFormatter f) {
|
||||
return t == null ? "" : t.format(f);
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,9 @@ import org.springframework.web.client.HttpClientErrorException;
|
||||
import org.springframework.web.client.HttpServerErrorException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.eactive.apim.portal.portalorg.entity.QPortalOrg;
|
||||
import com.eactive.eai.rms.common.context.MonitoringContext;
|
||||
import com.eactive.eai.rms.common.util.ContainerUtil;
|
||||
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;
|
||||
@@ -60,17 +62,21 @@ public class WebhookService {
|
||||
QWebhookReq req = QWebhookReq.webhookReq;
|
||||
QWebhookReqEvent evt = QWebhookReqEvent.webhookReqEvent;
|
||||
QWebhookReqApi api = QWebhookReqApi.webhookReqApi;
|
||||
QPortalOrg org = QPortalOrg.portalOrg;
|
||||
|
||||
String reverseProxyUrl = monitoringContext.getProperty(MonitoringContext.RMS_WEBHOOK_REVERSE_PROXY_URL);
|
||||
|
||||
List<Tuple> tuples = new JPAQueryFactory(entityManager)
|
||||
.select(req.orgId, req.targetUrl, req.secret, api.id.apiId)
|
||||
.select(req.orgId, req.targetUrl, req.secret, org.reverseProxyPath, api.id.apiId)
|
||||
.from(req)
|
||||
.join(evt).on(req.id.eq(evt.id.webhookReqId))
|
||||
.join(api).on(req.id.eq(api.id.webhookReqId))
|
||||
.join(org).on(req.orgId.eq(org.id))
|
||||
.where(evt.id.eventType.eq(event)
|
||||
.and(api.id.apiId.in(apiIds)))
|
||||
.fetch();
|
||||
|
||||
// orgId + targetUrl + secret 기준으로 그룹핑, apiId를 data(List)로 집계
|
||||
// orgId + targetUrl + secret 기준으로 그룹핑, apiIds를 data(List)로 집계
|
||||
Map<String, WebhookSendRequest> resultMap = new LinkedHashMap<>();
|
||||
for (Tuple t : tuples) {
|
||||
String key = t.get(req.orgId) + "|" + t.get(req.targetUrl);
|
||||
@@ -78,6 +84,7 @@ public class WebhookService {
|
||||
WebhookSendRequest wr = new WebhookSendRequest();
|
||||
wr.setOrgId(t.get(req.orgId));
|
||||
wr.setTargetUrl(t.get(req.targetUrl));
|
||||
wr.setProxyUrl(this.getProxyUrl(reverseProxyUrl, t.get(org.reverseProxyPath), t.get(req.targetUrl)));
|
||||
wr.setSecret(t.get(req.secret));
|
||||
wr.setEventType(event);
|
||||
wr.setData(new ArrayList<String>());
|
||||
@@ -88,6 +95,46 @@ public class WebhookService {
|
||||
|
||||
return new ArrayList<>(resultMap.values());
|
||||
}
|
||||
|
||||
//reverse proxy 서버로 발송하기 위한 url 만든다
|
||||
private String getProxyUrl(String proxyUrl, String path, String targetUrl) {
|
||||
String base = stripTrailingSlash(proxyUrl);
|
||||
String normalizedPath = stripSlashes(path);
|
||||
// scheme://host[:port] 부분만 제거하고 이후 path/query/fragment는 그대로 유지
|
||||
String targetPath = targetUrl.replaceFirst("^[a-zA-Z][a-zA-Z0-9+.-]*://[^/]+", "");
|
||||
|
||||
StringBuilder url = new StringBuilder(base);
|
||||
if (!normalizedPath.isEmpty()) {
|
||||
url.append('/').append(normalizedPath);
|
||||
}
|
||||
url.append(targetPath);
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
private String stripTrailingSlash(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
int end = value.length();
|
||||
while (end > 0 && value.charAt(end - 1) == '/') {
|
||||
end--;
|
||||
}
|
||||
return value.substring(0, end);
|
||||
}
|
||||
|
||||
private String stripSlashes(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
String result = value.trim();
|
||||
while (result.startsWith("/")) {
|
||||
result = result.substring(1);
|
||||
}
|
||||
while (result.endsWith("/")) {
|
||||
result = result.substring(0, result.length() - 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 웹훅 발송 메인 메서드
|
||||
@@ -96,6 +143,7 @@ public class WebhookService {
|
||||
public void send(WebhookSendRequest req) {
|
||||
|
||||
String targetUrl = req.getTargetUrl();
|
||||
String proxyUrl = req.getProxyUrl();
|
||||
String secret = req.getSecret();
|
||||
String eventType = req.getEventType();
|
||||
Object data = req.getData();
|
||||
@@ -103,7 +151,9 @@ public class WebhookService {
|
||||
WebhookSendLog sendLog = new WebhookSendLog();
|
||||
sendLog.setOrgId(req.getOrgId());
|
||||
sendLog.setTargetUrl(targetUrl);
|
||||
sendLog.setProxyUrl(proxyUrl);
|
||||
sendLog.setEventType(eventType);
|
||||
sendLog.setSendBy(ContainerUtil.getInstanceName());
|
||||
|
||||
try {
|
||||
// 1. Payload 생성
|
||||
@@ -123,11 +173,11 @@ public class WebhookService {
|
||||
headers.set("X-Webhook-Timestamp", String.valueOf(webhookPayload.getTimestamp()));
|
||||
|
||||
// 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);
|
||||
int retryCount = monitoringContext.getIntProperty(MonitoringContext.RMS_WEBHOOK_RETRY_COUNT, DEFAULT_RETRY_COUNT);
|
||||
int retryTime = monitoringContext.getIntProperty(MonitoringContext.RMS_WEBHOOK_RETRY_TIME, DEFAULT_RETRY_TIME);
|
||||
sendLog.setSentAt(LocalDateTime.now());
|
||||
HttpEntity<String> httpRequest = new HttpEntity<>(payloadJson, headers);
|
||||
ResponseEntity<String> response = sendWithRetry(targetUrl, httpRequest, sendLog, retryCount, retryTime);
|
||||
ResponseEntity<String> response = sendWithRetry(proxyUrl, httpRequest, sendLog, retryCount, retryTime);
|
||||
|
||||
// 5. 성공 로그
|
||||
sendLog.setStatusCode(response.getStatusCode().value());
|
||||
@@ -135,7 +185,7 @@ public class WebhookService {
|
||||
sendLog.setSuccess(response.getStatusCode().is2xxSuccessful());
|
||||
|
||||
log.info("[Webhook] 발송 성공 - eventType: {}, url: {}, status: {}, retryCount: {}",
|
||||
eventType, targetUrl, response.getStatusCode(), sendLog.getRetryCount());
|
||||
eventType, proxyUrl, response.getStatusCode(), sendLog.getRetryCount());
|
||||
|
||||
} catch (HttpClientErrorException | HttpServerErrorException e) {
|
||||
sendLog.setStatusCode(e.getStatusCode().value());
|
||||
@@ -143,13 +193,13 @@ public class WebhookService {
|
||||
sendLog.setSuccess(false);
|
||||
sendLog.setErrorMessage(e.getMessage());
|
||||
log.error("[Webhook] HTTP 오류 - eventType: {}, url: {}, status: {}",
|
||||
eventType, targetUrl, e.getStatusCode());
|
||||
eventType, proxyUrl, e.getStatusCode());
|
||||
|
||||
} catch (Exception e) {
|
||||
sendLog.setSuccess(false);
|
||||
sendLog.setErrorMessage(e.getMessage());
|
||||
log.error("[Webhook] 발송 실패 - eventType: {}, url: {}, error: {}",
|
||||
eventType, targetUrl, e.getMessage());
|
||||
eventType, proxyUrl, e.getMessage());
|
||||
}
|
||||
|
||||
sendLogRepository.save(sendLog);
|
||||
@@ -161,24 +211,25 @@ public class WebhookService {
|
||||
/**
|
||||
* 재시도 포함 HTTP 발송
|
||||
* - 4xx: 클라이언트 오류이므로 즉시 throw (재시도 불필요)
|
||||
* - 5xx / 네트워크 오류: 최대 RETRY_COUNT회까지 exponential backoff 재시도 (1s → 2s → 4s)
|
||||
* - 5xx / 네트워크 오류: 최대 RETRY_COUNT회까지 선형 증가 backoff 재시도 (1s → 2s → 3s → 4s → 5s)
|
||||
*/
|
||||
private ResponseEntity<String> sendWithRetry(String targetUrl, HttpEntity<String> request, WebhookSendLog sendLog, int retryCount, int retryTime) throws Exception {
|
||||
private ResponseEntity<String> sendWithRetry(String proxyUrl, HttpEntity<String> request, WebhookSendLog sendLog, int retryCount, int retryTime) throws Exception {
|
||||
Exception lastException = null;
|
||||
for (int attempt = 0; attempt <= retryCount; attempt++) {
|
||||
try {
|
||||
if (attempt > 0) {
|
||||
long delayMs = retryTime * (1L << (attempt - 1));
|
||||
log.info("[Webhook] 재시도 {}/{} - url: {}, delay: {}ms", attempt, retryCount, targetUrl, delayMs);
|
||||
Thread.sleep(delayMs);
|
||||
long delayMs = (long) retryTime * attempt;
|
||||
log.info("[Webhook] 재시도 {}/{} - url: {}, delay: {}ms", attempt, retryCount, proxyUrl, delayMs);
|
||||
sendLog.setRetryCount(attempt);
|
||||
Thread.sleep(delayMs);
|
||||
}
|
||||
return restTemplate.postForEntity(targetUrl, request, String.class);
|
||||
return restTemplate.postForEntity(proxyUrl, request, String.class);
|
||||
} catch (HttpClientErrorException e) {
|
||||
throw e; // 4xx는 재시도 불필요
|
||||
//throw e; // 4xx는 재시도 불필요
|
||||
lastException = e; //TODO: 재시도 테스트
|
||||
} catch (Exception e) {
|
||||
lastException = e;
|
||||
log.warn("[Webhook] 발송 실패 (attempt {}/{}) - url: {}, error: {}", attempt, retryCount, targetUrl, e.getMessage());
|
||||
log.warn("[Webhook] 발송 실패 (attempt {}/{}) - url: {}, error: {}", attempt, retryCount, proxyUrl, e.getMessage());
|
||||
}
|
||||
}
|
||||
throw lastException;
|
||||
|
||||
@@ -23,6 +23,7 @@ import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@@ -37,8 +38,8 @@ public class PortalOrgManController extends BaseAnnotationController {
|
||||
private final ComboService comboService;
|
||||
|
||||
@GetMapping(value = "/onl/apim/portalorg/portalOrgMan.view")
|
||||
public void view() {
|
||||
// view
|
||||
public void view(Model model) {
|
||||
model.addAttribute("hardDeleteEnabled", portalOrgManService.isHardDeleteEnabled());
|
||||
}
|
||||
|
||||
@GetMapping(value = "/onl/apim/portalorg/portalOrgMan.view", params = "cmd=DETAIL")
|
||||
|
||||
@@ -18,6 +18,7 @@ import com.eactive.eai.rms.onl.apim.masking.MaskingUtils;
|
||||
import com.eactive.eai.rms.onl.apim.portaluser.PortalUserCorpManagerUI;
|
||||
import com.eactive.eai.rms.onl.apim.portaluser.PortalUserCorpManagerUIMapper;
|
||||
import com.eactive.eai.rms.onl.common.exception.BizException;
|
||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@@ -44,15 +45,27 @@ import java.util.Optional;
|
||||
@Slf4j
|
||||
public class PortalOrgManService extends BaseService {
|
||||
|
||||
/** PortalProperty 그룹명 */
|
||||
private static final String PORTAL_PROPERTY_GROUP = "Portal";
|
||||
/** 법인 완전삭제(hard delete) 허용 프로퍼티 키 (true:허용, 기본 false) */
|
||||
private static final String HARD_DELETE_FLAG_KEY = "org.hard-delete.enabled";
|
||||
|
||||
private final PortalOrgService portalOrgService;
|
||||
private final PortalOrgUIMapper portalOrgUIMapper;
|
||||
private final PortalUserService portalUserService;
|
||||
private final PortalUserCorpManagerUIMapper portalUserCorpManagerUIMapper;
|
||||
private final FileService fileService;
|
||||
private final PortalPropertyService portalPropertyService;
|
||||
|
||||
@PersistenceContext(unitName = "entityManagerFactoryForEMS")
|
||||
private EntityManager entityManager;
|
||||
|
||||
/** 법인 목록 '선택 삭제'(완전삭제) 버튼 노출 여부 */
|
||||
public boolean isHardDeleteEnabled() {
|
||||
Map<String, String> properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP);
|
||||
return Boolean.parseBoolean(properties.getOrDefault(HARD_DELETE_FLAG_KEY, "false"));
|
||||
}
|
||||
|
||||
public Page<PortalOrgUI> selectList(Pageable pageable, PortalOrgUISearch portalOrgUISearch) {
|
||||
Page<PortalOrg> portalOrg = portalOrgService.findAll(pageable, portalOrgUISearch);
|
||||
return portalOrg.map(entity -> convertToUIWithMaskOption(entity, true));
|
||||
|
||||
@@ -13,6 +13,7 @@ import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.web.SortDefault;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
|
||||
@@ -32,8 +33,8 @@ public class PortalUserManController extends BaseAnnotationController {
|
||||
private final ComboService comboService;
|
||||
|
||||
@GetMapping(value = "/onl/apim/portaluser/portalUserMan.view")
|
||||
public void view() {
|
||||
// view
|
||||
public void view(Model model) {
|
||||
model.addAttribute("hardDeleteEnabled", portalUserManService.isHardDeleteEnabled());
|
||||
}
|
||||
|
||||
@GetMapping(value = "/onl/apim/portaluser/portalUserMan.view", params = "cmd=DETAIL")
|
||||
|
||||
@@ -46,6 +46,8 @@ public class PortalUserManService extends BaseService {
|
||||
private static final String PORTAL_PROPERTY_GROUP = "Portal";
|
||||
/** 사용자 별 휴대폰 번호 중복 허용 프로퍼티 키 (true:허용, false:허용안함, 기본 false) */
|
||||
private static final String PROP_MOBILE_DUPLICATE_ALLOW = "user.mobile.duplicate.allow";
|
||||
/** 가입자 완전삭제(hard delete) 허용 프로퍼티 키 (true:허용, 기본 false) */
|
||||
private static final String HARD_DELETE_FLAG_KEY = "user.hard-delete.enabled";
|
||||
|
||||
private final PortalUserService portalUserService;
|
||||
private final PortalUserUIMapper portalUserUIMapper;
|
||||
@@ -60,6 +62,11 @@ public class PortalUserManService extends BaseService {
|
||||
private final PortalInquiryService portalInquiryService;
|
||||
private final PortalPropertyService portalPropertyService;
|
||||
|
||||
/** 가입자 목록 '선택 삭제'(완전삭제) 버튼 노출 여부 */
|
||||
public boolean isHardDeleteEnabled() {
|
||||
Map<String, String> properties = portalPropertyService.getPortalPropertiesAsMap(PORTAL_PROPERTY_GROUP);
|
||||
return Boolean.parseBoolean(properties.getOrDefault(HARD_DELETE_FLAG_KEY, "false"));
|
||||
}
|
||||
|
||||
public Page<PortalUserUI> selectList(Pageable pageable, PortalUserUISearch portalUserUISearch) {
|
||||
Page<PortalUser> portalUser = portalUserService.findAll(pageable, portalUserUISearch);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.eactive.eai.rms.onl.manage.authserver.scope;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -8,21 +10,29 @@ import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import com.eactive.eai.agent.authserver.ReloadApiScopeCommand;
|
||||
import com.eactive.eai.agent.command.CommonCommand;
|
||||
import com.eactive.eai.rms.common.base.OnlBaseAnnotationController;
|
||||
import com.eactive.eai.rms.common.vo.GridResponse;
|
||||
import com.eactive.eai.rms.data.entity.onl.authserver.ScopeSearch;
|
||||
import com.eactive.eai.rms.data.entity.onl.eaimsg.ApiScopeSearch;
|
||||
import com.eactive.eai.rms.onl.common.exception.BizException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
@Controller
|
||||
public class ScopeController extends OnlBaseAnnotationController {
|
||||
|
||||
private ScopeManService scopeManService;
|
||||
|
||||
private ApiScopeManService apiScopeManService;
|
||||
|
||||
@Autowired
|
||||
public ScopeController(ScopeManService scopeManService) {
|
||||
public ScopeController(ScopeManService scopeManService, ApiScopeManService apiScopeManService) {
|
||||
this.scopeManService = scopeManService;
|
||||
this.apiScopeManService = apiScopeManService;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/onl/admin/authserver/scopeMan.view")
|
||||
@@ -41,6 +51,12 @@ public class ScopeController extends OnlBaseAnnotationController {
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/admin/authserver/scopeMan.json", params = "cmd=API_LIST")
|
||||
public ResponseEntity<GridResponse<ApiScopeUI>> selectApiList(Pageable pageable, ApiScopeSearch apiScopeSearch) {
|
||||
Page<ApiScopeUI> page = apiScopeManService.selectApiScopeRelationsList(pageable, apiScopeSearch);
|
||||
return ResponseEntity.ok(new GridResponse<>(page));
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/admin/authserver/scopeMan.json", params = "cmd=DETAIL")
|
||||
public ResponseEntity<ScopeUI> selectDetail(String scopeId) {
|
||||
ScopeUI scopeUI = scopeManService.selectDetail(scopeId);
|
||||
@@ -48,14 +64,16 @@ public class ScopeController extends OnlBaseAnnotationController {
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/admin/authserver/scopeMan.json", params = "cmd=INSERT")
|
||||
public ResponseEntity<Void> insert(ScopeUI scopeUI) {
|
||||
public ResponseEntity<Void> insert(ScopeUI scopeUI, @RequestParam(value = "apiList", required = false) String apiListJson) {
|
||||
scopeManService.insert(scopeUI);
|
||||
saveApiScopeRelations(scopeUI.getScopeId(), apiListJson);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PostMapping(value = "/onl/admin/authserver/scopeMan.json", params = "cmd=UPDATE")
|
||||
public ResponseEntity<Void> update(ScopeUI scopeUI) {
|
||||
public ResponseEntity<Void> update(ScopeUI scopeUI, @RequestParam(value = "apiList", required = false) String apiListJson) {
|
||||
scopeManService.update(scopeUI);
|
||||
saveApiScopeRelations(scopeUI.getScopeId(), apiListJson);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@@ -69,8 +87,29 @@ public class ScopeController extends OnlBaseAnnotationController {
|
||||
.args(new String[] {ReloadApiScopeCommand.COMMAND_TYPE_SCOPE, "", scopeId})
|
||||
.build()
|
||||
.broadcast(agentUtilService);
|
||||
|
||||
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
|
||||
private void saveApiScopeRelations(String scopeId, String apiListJson) {
|
||||
if (apiListJson == null || apiListJson.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<ApiScopeUI> apiScopeList;
|
||||
try {
|
||||
apiScopeList = new ObjectMapper().readValue(apiListJson, new TypeReference<List<ApiScopeUI>>() {});
|
||||
} catch (Exception e) {
|
||||
throw new BizException("데이터 변환 중 오류가 발생했습니다.");
|
||||
}
|
||||
|
||||
scopeManService.updateApiScopeRelations(apiScopeList, scopeId);
|
||||
|
||||
CommonCommand.builder()
|
||||
.name(CommonCommand.RELOAD_API_SCOPE_COMMAND)
|
||||
.args(new String[] {ReloadApiScopeCommand.COMMAND_TYPE_SCOPE, "", scopeId})
|
||||
.build()
|
||||
.broadcast(agentUtilService);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.eactive.eai.rms.onl.manage.authserver.scope;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -21,17 +23,20 @@ public class ScopeManService extends OnlBaseService {
|
||||
private ScopeInfoService scopeInfoService;
|
||||
|
||||
private ScopeEntityService scopeEntityService;
|
||||
|
||||
|
||||
private ScopeUIMapper scopeUIMapper;
|
||||
|
||||
private ApiScopeUIMapper apiScopeUIMapper;
|
||||
|
||||
private LocaleMessage localeMessage;
|
||||
|
||||
|
||||
@Autowired
|
||||
public ScopeManService(ScopeInfoService scopeInfoService, ScopeEntityService scopeEntityService,
|
||||
ScopeUIMapper scopeUIMapper, LocaleMessage localeMessage ) {
|
||||
public ScopeManService(ScopeInfoService scopeInfoService, ScopeEntityService scopeEntityService,
|
||||
ScopeUIMapper scopeUIMapper, ApiScopeUIMapper apiScopeUIMapper, LocaleMessage localeMessage ) {
|
||||
this.scopeInfoService = scopeInfoService;
|
||||
this.scopeEntityService = scopeEntityService;
|
||||
this.scopeUIMapper = scopeUIMapper;
|
||||
this.apiScopeUIMapper = apiScopeUIMapper;
|
||||
this.localeMessage = localeMessage;
|
||||
}
|
||||
|
||||
@@ -65,5 +70,23 @@ public class ScopeManService extends OnlBaseService {
|
||||
public void deleteApiScopeRelationsByScopeId(String scopeId) {
|
||||
scopeEntityService.deleteByIdScopeId(scopeId);
|
||||
}
|
||||
|
||||
|
||||
public void updateApiScopeRelations(List<ApiScopeUI> apiScopeList, String scopeId) {
|
||||
if (scopeId == null || scopeId.isEmpty()) {
|
||||
throw new BizException("ScopeId 가 존재하지 않습니다.");
|
||||
}
|
||||
|
||||
// ScopeId 기준 전체 삭제 후 LIST 기준으로 재저장.
|
||||
scopeEntityService.deleteByIdScopeId(scopeId);
|
||||
|
||||
if (apiScopeList == null || apiScopeList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (ApiScopeUI ui : apiScopeList) {
|
||||
ui.setScopeId(scopeId);
|
||||
scopeEntityService.save(apiScopeUIMapper.toEntity(ui));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -352,7 +352,7 @@ public class LayoutManService extends OnlBaseService {
|
||||
}
|
||||
|
||||
if (max == 0 && min == 0) {
|
||||
if ("GRID".equalsIgnoreCase(loutItemType)) {
|
||||
if ("GRID".equalsIgnoreCase(loutItemType) || "ARRAY".equalsIgnoreCase(loutItemType)) {
|
||||
min = 1;
|
||||
max = -1;
|
||||
} else {
|
||||
@@ -371,7 +371,8 @@ public class LayoutManService extends OnlBaseService {
|
||||
}
|
||||
|
||||
private String determineOccurNoItem(LayoutItemUI layoutItemUI, String loutItemType) {
|
||||
if ("GRID".equalsIgnoreCase(loutItemType) && NumberUtils.toInt(layoutItemUI.getLoutItemOccCnt()) == 0) {
|
||||
if (("GRID".equalsIgnoreCase(loutItemType) || "ARRAY".equalsIgnoreCase(loutItemType))
|
||||
&& NumberUtils.toInt(layoutItemUI.getLoutItemOccCnt()) == 0) {
|
||||
return "*";
|
||||
}
|
||||
return String.valueOf(layoutItemUI.getLoutItemOccCnt());
|
||||
@@ -385,6 +386,8 @@ public class LayoutManService extends OnlBaseService {
|
||||
node = Item.NODE_GROUP;
|
||||
} else if ("ATTR".equalsIgnoreCase(el.getLoutItemType())) {
|
||||
node = Item.NODE_ATTR;
|
||||
} else if ("ARRAY".equalsIgnoreCase(el.getLoutItemType())) {
|
||||
node = Item.NODE_FIELD;
|
||||
} else {
|
||||
node = Item.NODE_FIELD;
|
||||
}
|
||||
|
||||
+26
-6
@@ -71,13 +71,33 @@ public interface LayoutItemUIMapper extends GenericMapper<LayoutItemUI, LayoutIt
|
||||
itemType = isGridCondition ? "GRID" : "GROUP";
|
||||
|
||||
// isGridCondition이 참이고, 참조 정보2가 비어 있는 경우, itemLoopCount 설정
|
||||
if (isGridCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())
|
||||
&& NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1 ) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
if (isGridCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())) {
|
||||
if ("*".equals(item.getLoutitemoccurptrndstcd())) {
|
||||
// 반복횟수로 '*'(무제한)이 저장된 경우, 화면 그리드에도 '*'을 그대로 표시
|
||||
itemLoopCount = "*";
|
||||
} else if (NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
}
|
||||
} else if (ItemNodeType.FIELD.getNumber() == item.getLoutitemnodeptrnidname()) {
|
||||
// 아이템 발생 포인터 명이 '*'이거나 숫자로 생성 가능한 경우
|
||||
boolean isArrayCondition = "*".equals(item.getLoutitemoccurptrndstcd()) || NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd());
|
||||
// itemType을 ARRAY 또는 FIELD 로 설정
|
||||
itemType = isArrayCondition ? "ARRAY" : "FIELD";
|
||||
|
||||
// isArrayCondition이 참이고, 참조 정보2가 비어 있는 경우, itemLoopCount 설정
|
||||
if (isArrayCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())) {
|
||||
if ("*".equals(item.getLoutitemoccurptrndstcd())) {
|
||||
// 반복횟수로 '*'(무제한)이 저장된 경우, 화면 그리드에도 '*'을 그대로 표시
|
||||
itemLoopCount = "*";
|
||||
} else if (NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 아이템 노드 타입이 GROUP이 아닌 경우, 해당 노드 타입으로 itemType 설정
|
||||
// 아이템 노드 타입이 GROUP/FIELD가 아닌 경우, 해당 노드 타입으로 itemType 설정
|
||||
itemType = ItemNodeType.fromNumber(item.getLoutitemnodeptrnidname()).toString();
|
||||
}
|
||||
|
||||
@@ -85,7 +105,7 @@ public interface LayoutItemUIMapper extends GenericMapper<LayoutItemUI, LayoutIt
|
||||
|
||||
itemUi.setLoutItemType(itemType);
|
||||
|
||||
if(NumberUtils.toInt(itemLoopCount) == 0){
|
||||
if (!"*".equals(itemLoopCount) && NumberUtils.toInt(itemLoopCount) == 0) {
|
||||
itemLoopCount = "";
|
||||
}
|
||||
itemUi.setLoutItemOccCnt(itemLoopCount);
|
||||
|
||||
+25
-5
@@ -71,10 +71,30 @@ public interface LayoutPopupUIMapper extends GenericMapper<LayoutPopupUI, Layout
|
||||
itemType = isGridCondition ? "GRID" : "GROUP";
|
||||
|
||||
// isGridCondition이 참이고, 참조 정보2가 비어 있는 경우, itemLoopCount 설정
|
||||
if (isGridCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())
|
||||
&& NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1 ) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
if (isGridCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())) {
|
||||
if ("*".equals(item.getLoutitemoccurptrndstcd())) {
|
||||
// 반복횟수로 '*'(무제한)이 저장된 경우, 화면 그리드에도 '*'을 그대로 표시
|
||||
itemLoopCount = "*";
|
||||
} else if (NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
}
|
||||
} else if (ItemNodeType.FIELD.getNumber() == item.getLoutitemnodeptrnidname()) {
|
||||
// 아이템 발생 포인터 명이 '*'이거나 숫자로 생성 가능한 경우
|
||||
boolean isArrayCondition = "*".equals(item.getLoutitemoccurptrndstcd()) || NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd());
|
||||
// itemType을 ARRAY 또는 FIELD 로 설정
|
||||
itemType = isArrayCondition ? "ARRAY" : "FIELD";
|
||||
|
||||
// isArrayCondition이 참이고, 참조 정보2가 비어 있는 경우, itemLoopCount 설정
|
||||
if (isArrayCondition && StringUtils.isBlank(item.getLoutitemrefinfo2())) {
|
||||
if ("*".equals(item.getLoutitemoccurptrndstcd())) {
|
||||
// 반복횟수로 '*'(무제한)이 저장된 경우, 화면 그리드에도 '*'을 그대로 표시
|
||||
itemLoopCount = "*";
|
||||
} else if (NumberUtils.isCreatable(item.getLoutitemoccurptrndstcd())
|
||||
&& Integer.parseInt(item.getLoutitemoccurptrndstcd()) > -1) {
|
||||
itemLoopCount = item.getLoutitemoccurptrndstcd();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 아이템 노드 타입이 GROUP이 아닌 경우, 해당 노드 타입으로 itemType 설정
|
||||
@@ -85,7 +105,7 @@ public interface LayoutPopupUIMapper extends GenericMapper<LayoutPopupUI, Layout
|
||||
|
||||
popupUI.setLoutItemType(itemType);
|
||||
|
||||
if(NumberUtils.toInt(itemLoopCount) == 0){
|
||||
if (!"*".equals(itemLoopCount) && NumberUtils.toInt(itemLoopCount) == 0) {
|
||||
itemLoopCount = "";
|
||||
}
|
||||
popupUI.setLoutItemOccCnt(itemLoopCount);
|
||||
|
||||
@@ -555,7 +555,7 @@ public class ApiInterfaceService extends OnlBaseService {
|
||||
restOption.setStandardCommonFields(standardCommonFields);
|
||||
return objectMapper.writeValueAsString(restOption);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to create standard common option", e);
|
||||
throw new RuntimeException("표준전문 공통부 생성을 실패했습니다", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2490,6 +2490,7 @@ deployResourceSearchMan.deleteBtn=delete
|
||||
|
||||
auditLogMan.command = Command
|
||||
auditLogMan.logMsg = Message
|
||||
auditLogMan.message = Reason
|
||||
auditLogMan.logSeqNo = Number
|
||||
auditLogMan.logSubMsg = Sub Message
|
||||
auditLogMan.logType.access = ACCESS
|
||||
|
||||
@@ -202,6 +202,7 @@ apiScpMan.title = API-SCOPE \uB9F5\uD551
|
||||
|
||||
auditLogMan.command = Command
|
||||
auditLogMan.logMsg = \uBA54\uC2DC\uC9C0
|
||||
auditLogMan.message = \uC0AC\uC720
|
||||
auditLogMan.logSeqNo = \uBC88\uD638
|
||||
auditLogMan.logSubMsg = \uC11C\uBE0C \uBA54\uC2DC\uC9C0
|
||||
auditLogMan.logType.access = \uC811\uC18D
|
||||
|
||||
Reference in New Issue
Block a user