7 Commits

Author SHA1 Message Date
eastargh d0cd8118f3 유량제어관련 메뉴 - 사용여부 검색조건 추가
eapim-admin CI / build (push) Waiting to run
2026-07-14 11:30:55 +09:00
Rinjae 07e65c055b - JSP: OpenAPI Spec 버튼 상태 수정 - NEW → DETAIL로 변경
eapim-admin CI / build (push) Waiting to run
- Service: BIGDECIMAL 매핑 추가 - 반환 유형 'number'
- Monitoring: Properties 초기화 및 null 체크 로직 추가
- JS: 샘플 응답 상태 시 안내 메시지 추가
2026-07-14 11:11:24 +09:00
eastargh af8a9cca51 프라퍼티 정리
eapim-admin CI / build (push) Waiting to run
2026-07-13 17:47:35 +09:00
eastargh 39a09d0f5d 유량제어 url 특수문자 escape 2026-07-13 17:47:08 +09:00
Rinjae 5b940717c4 Merge remote-tracking branch 'origin/master'
eapim-admin CI / build (push) Waiting to run
2026-07-13 15:30:13 +09:00
Rinjae 8ccf52fd66 - JSP: OpenAPI Spec 모달 처리 개선 - 동적 크기 조절 및 스타일 추가
- Service: GET/DELETE 요청 바디 항목→쿼리 파라미터 매핑 로직 추가
- JS: 요청 정보 진입 시 탭 자동 전환 로직(firstReqTabWithData) 구현
2026-07-13 15:30:08 +09:00
eastargh dedc58a07f 유량제어 추가임계치가 null or 단위선택 않하면 0으로 설정
eapim-admin CI / build (push) Waiting to run
2026-07-13 15:24:30 +09:00
20 changed files with 268 additions and 366 deletions
+17 -2
View File
@@ -301,7 +301,7 @@
function goStep(n) {
if (n < 1 || n > STEPS.length) return;
state.step = n;
if (n === 2) state.reqInfoTab = 'body'; // 요청/응답 정보: 진입 시 항상 Body 먼저
if (n === 2) state.reqInfoTab = firstReqTabWithData(); // 요청 정보: 값 있는 탭(Header→Parameter→Body 순) 먼저
if (n === 3) state.resInfoTab = 'body';
renderStepper();
renderForm();
@@ -439,6 +439,19 @@
+ '</div>';
}
// 요청 정보 진입 시 먼저 보일 서브탭 = 값이 든 첫 탭(Header→Parameter→Body 순).
// 보통 GET 은 Parameter(query), POST 는 Body 에만 값이 있음. 전부 비면 Body 로.
function firstReqTabWithData() {
var params = (state.data && state.data.parameters) || [];
var hasHeader = params.some(function (p) { return p.in === 'header'; });
var hasParam = params.some(function (p) { return p.in === 'query'; });
var hasBody = !!(state.data && state.data.requestBody && state.data.requestBody.schema && state.data.requestBody.schema.length);
if (hasHeader) return 'header';
if (hasParam) return 'param';
if (hasBody) return 'body';
return 'body';
}
// Step 2 — 요청 정보 (Header / Parameter / Body / API 설명(HTML))
function renderReqInfo(root) {
const tab = state.reqInfoTab || 'body';
@@ -991,7 +1004,9 @@
['sample', 'mock', 'gw'].map(v =>
`<label class="inline-flex items-center gap-1 text-sm mr-3"><input type="radio" name="portal-rt" data-portal-rt="${v}" ${rt === v ? 'checked' : ''}> ${v === 'gw' ? 'GW' : v}</label>`
).join('') +
`<div class="mt-2 text-xs text-slate-500">실제 호출 주소: <code id="resolved-call-url" class="font-mono text-slate-700 break-all">${escapeHtml(resolvedCallUrl())}</code></div>` +
(rt === 'sample'
? `<div class="mt-2 text-xs text-slate-500">응답 샘플을 바로 리턴합니다.</div>`
: `<div class="mt-2 text-xs text-slate-500">실제 호출 주소: <code id="resolved-call-url" class="font-mono text-slate-700 break-all">${escapeHtml(resolvedCallUrl())}</code></div>`) +
(rt === 'gw' ? `<div class="mt-1 text-xs text-slate-400">GW 주소는 포탈 설정(PTL_PROPERTY, 그룹 Portal)의 <code class="font-mono">djb.gateway.base-url</code> 값을 사용합니다.</div>` : '') +
'</div>') +
(rt === 'mock' ? fieldRow('Mock Server URL', input(p.mockUrl || '', 'data-portal="mockUrl"', { placeholder: 'https://mock.example.com' }), { hint: 'Mock 응답을 제공할 서버의 기본 URL. 응답 유형이 Mock 일 때 개발자포탈이 이 주소로 요청을 전달하고, Swagger 스펙의 서버 주소로도 사용됩니다.' }) : '')
+33 -268
View File
@@ -1,298 +1,63 @@
// 계좌이체 API 모의 데이터
// locked: true 인 필드는 게이트웨이가 자동 주입한 값(회색 + 자물쇠)
// locked: false / 미지정 인 필드는 사용자가 자유롭게 편집
// OpenAPI 에디터 초기 상태 골격(빈 껍데기).
// - specToData() 가 deepClone 하여 서버 spec 값으로 덮어쓰는 구조 기준값.
// - 실제 데모/샘플 값은 두지 않는다(팝업은 항상 서버 spec 로드 후 렌더).
// - docOptions 만 기능 기본값으로 유지(문서 미리보기 옵션).
// locked:true = 게이트웨이 자동 주입(회색+자물쇠) / locked:false = 사용자 편집.
window.SAMPLE_DATA = (function () {
function f() { return { value: '', locked: false }; }
return {
info: {
title: { value: '계좌이체 API', locked: false },
version: { value: '1.0.0', locked: false },
summary: { value: '', locked: false },
description: { value: '', locked: false },
termsOfService: { value: '', locked: false },
contact: {
name: { value: 'DJB API Team', locked: false },
email: { value: 'api@djb.co.kr', locked: false },
url: { value: '', locked: false }
},
license: {
name: { value: '', locked: false },
url: { value: '', locked: false }
}
title: f(),
version: f(),
summary: f(),
description: f(),
termsOfService: f(),
contact: { name: f(), email: f(), url: f() },
license: { name: f(), url: f() }
},
tags: [
{ name: 'transfer', description: '계좌이체 관련 API' }
],
tags: [],
externalDocs: {
description: { value: '', locked: false },
url: { value: '', locked: false }
},
externalDocs: { description: f(), url: f() },
servers: [
{
url: { value: 'https://api-dev.djb.co.kr', locked: true },
env: 'development',
description: { value: '개발 환경', locked: false }
},
{
url: { value: 'https://api-stg.djb.co.kr', locked: true },
env: 'staging',
description: { value: '스테이징 환경', locked: false }
},
{
url: { value: 'https://api.djb.co.kr', locked: true },
env: 'production',
description: { value: '운영 환경', locked: false }
}
],
servers: [],
serverVariables: [
{
name: { value: 'basePath', locked: true },
default: { value: '/v1', locked: false },
enumStr: { value: '/v1,/v2', locked: false },
description: { value: 'API 버전 경로', locked: false }
}
],
serverVariables: [],
operation: {
method: { value: 'POST', locked: true },
path: { value: '/v1/accounts/transfer', locked: true },
operationId: { value: 'transferAccount', locked: false },
summary: { value: '', locked: false },
description: { value: '', locked: false },
tags: { value: ['transfer'], locked: false },
deprecated: { value: false, locked: false }
method: f(),
path: f(),
operationId: f(),
summary: f(),
description: f(),
tags: { value: [], locked: false },
deprecated: { value: false, locked: false }
},
// 파라미터 (Path/Query/Header/Cookie)
parameters: [
{
in: 'header',
name: { value: 'X-Request-Id', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: 'uuid', locked: false },
maxLength: { value: '', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '', locked: false }
}
],
parameters: [],
// Request Body 스키마 (중첩 3단)
// Request Body 스키마
requestBody: {
mediaType: 'application/json',
required: { value: true, locked: true },
schema: [
{
name: { value: 'transactionId', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '40', locked: false },
pattern: { value: '^tx-[0-9a-zA-Z-]+$', locked: false },
description: { value: '', locked: false },
example: { value: 'tx-20260522-001', locked: false },
children: null
},
{
name: { value: 'sender', locked: true },
type: { value: 'object', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '', locked: false },
pattern: { value: '', locked: false },
description: { value: '송금인 정보', locked: false },
example: { value: '', locked: false },
children: [
{
name: { value: 'accountNumber', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '20', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '110-1234-567890', locked: false },
children: null
},
{
name: { value: 'bankCode', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '3', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '088', locked: false },
children: null
},
{
name: { value: 'holderName', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '60', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '김철수', locked: false },
children: null
}
]
},
{
name: { value: 'receiver', locked: true },
type: { value: 'object', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '', locked: false },
pattern: { value: '', locked: false },
description: { value: '수취인 정보', locked: false },
example: { value: '', locked: false },
children: [
{
name: { value: 'accountNumber', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '20', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '111-2345-678901', locked: false },
children: null
},
{
name: { value: 'bankCode', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '3', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '020', locked: false },
children: null
},
{
name: { value: 'holderName', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '60', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '이영희', locked: false },
children: null
}
]
},
{
name: { value: 'amount', locked: true },
type: { value: 'object', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '', locked: false },
pattern: { value: '', locked: false },
description: { value: '이체 금액', locked: false },
example: { value: '', locked: false },
children: [
{
name: { value: 'value', locked: true },
type: { value: 'integer', locked: true },
required: { value: true, locked: true },
format: { value: 'int64', locked: false },
maxLength: { value: '', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '50000', locked: false },
children: null
},
{
name: { value: 'currency', locked: true },
type: { value: 'string', locked: true },
required: { value: true, locked: true },
format: { value: '', locked: false },
maxLength: { value: '3', locked: false },
pattern: { value: '^[A-Z]{3}$', locked: false },
description: { value: 'ISO 4217 통화코드', locked: false },
example: { value: 'KRW', locked: false },
children: null
}
]
},
{
name: { value: 'memo', locked: true },
type: { value: 'string', locked: true },
required: { value: false, locked: true },
format: { value: '', locked: false },
maxLength: { value: '100', locked: false },
pattern: { value: '', locked: false },
description: { value: '', locked: false },
example: { value: '5월 회비', locked: false },
children: null
}
]
required: { value: false, locked: false },
schema: []
},
// 응답 스키마 (상태코드 별)
responses: {
'200': {
description: { value: '이체 성공', locked: false },
schema: [
{ name: { value: 'transactionId', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: 'tx-20260522-001', locked: false }, children: null },
{ name: { value: 'status', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: 'COMPLETED', locked: false }, children: null },
{ name: { value: 'completedAt', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: 'date-time', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '2026-05-22T10:00:00Z', locked: false }, children: null },
{
name: { value: 'balance', locked: true }, type: { value: 'object', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '잔액 정보', locked: false }, example: { value: '', locked: false },
children: [
{ name: { value: 'before', locked: true }, type: { value: 'integer', locked: true }, required: { value: true, locked: true }, format: { value: 'int64', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '1000000', locked: false }, children: null },
{ name: { value: 'after', locked: true }, type: { value: 'integer', locked: true }, required: { value: true, locked: true }, format: { value: 'int64', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '950000', locked: false }, children: null }
]
}
]
},
'400': {
description: { value: '잘못된 요청', locked: false },
schema: [
{
name: { value: 'error', locked: true }, type: { value: 'object', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '', locked: false },
children: [
{ name: { value: 'code', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: 'INVALID_AMOUNT', locked: false }, children: null },
{ name: { value: 'message', locked: true }, type: { value: 'string', locked: true }, required: { value: true, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '금액이 올바르지 않습니다', locked: false }, children: null },
{ name: { value: 'details', locked: true }, type: { value: 'array', locked: true }, required: { value: false, locked: true }, format: { value: '', locked: false }, maxLength: { value: '', locked: false }, pattern: { value: '', locked: false }, description: { value: '', locked: false }, example: { value: '', locked: false }, itemsType: { value: 'string', locked: false }, children: null }
]
}
]
},
'401': { description: { value: '인증 실패', locked: false }, schema: [] },
'500': { description: { value: '서버 오류', locked: false }, schema: [] }
'200': { description: f(), schema: [] }
},
// 보안 스킴
securitySchemes: [
{
key: 'ApiKeyAuth',
type: 'apiKey',
locked: true,
name: { value: 'X-API-Key', locked: true },
in: { value: 'header', locked: true },
description: { value: '', locked: false }
}
],
globalSecurity: ['ApiKeyAuth'],
securitySchemes: [],
globalSecurity: [],
// 예제
examples: {
request: {
'application/json': {
default: '{\n "transactionId": "tx-20260522-001",\n "sender": {\n "accountNumber": "110-1234-567890",\n "bankCode": "088",\n "holderName": "김철수"\n },\n "receiver": {\n "accountNumber": "111-2345-678901",\n "bankCode": "020",\n "holderName": "이영희"\n },\n "amount": {\n "value": 50000,\n "currency": "KRW"\n },\n "memo": "5월 회비"\n}'
}
},
response: {
'200': { body: '{\n "transactionId": "tx-20260522-001",\n "status": "COMPLETED"\n}', headers: [ { name: 'X-RateLimit-Remaining', type: 'integer', description: '남은 요청 횟수', example: '99' } ] }
}
request: {},
response: {}
},
// 문서 옵션
@@ -25,7 +25,7 @@ $(document).ready(function() {
datatype:"json",
mtype: 'POST',
url: url,
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val()},
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()},
colNames:['<%= localeMessage.getString("infAdpConMan.adaNm") %>',
'<%= localeMessage.getString("infAdpConMan.adaDes") %>',
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
@@ -62,6 +62,7 @@ $(document).ready(function() {
url2 += '&menuId='+'${param.menuId}';
//검색값
url2 += '&searchName='+$("input[name=searchName]").val();
url2 += '&searchUseYn='+$("select[name=searchUseYn]").val();
//key값
url2 += '&name='+name;
goNav(url2);
@@ -80,7 +81,7 @@ $(document).ready(function() {
resizeJqGridWidth('grid','content_middle','1000');
$("#btn_search").click(function(){
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val()}, page:1 }).trigger("reloadGrid");
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()}, page:1 }).trigger("reloadGrid");
});
$("#btn_new").click(function(){
var url2 = url_view;
@@ -126,6 +127,16 @@ $(document).ready(function() {
<tr>
<th style="width:180px;"><%= localeMessage.getString("infAdpConMan.adaNm") %></th>
<td><input type="text" name="searchName" value="${param.searchName}"></td>
<th style="width:180px;"><%= localeMessage.getString("infAdpConMan.useYn") %></th>
<td>
<div class="select-style">
<select name="searchUseYn">
<option value="">전체</option>
<option value="1">사용함</option>
<option value="0">사용안함</option>
</select>
</div>
</td>
</tr>
</tbody>
</table>
@@ -25,7 +25,7 @@ $(document).ready(function() {
datatype:"json",
mtype: 'POST',
url: url,
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val()},
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()},
colNames:['클라이언트 ID',
'클라이언트명',
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
@@ -62,6 +62,7 @@ $(document).ready(function() {
url2 += '&menuId='+'${param.menuId}';
//검색값
url2 += '&searchName='+$("input[name=searchName]").val();
url2 += '&searchUseYn='+$("select[name=searchUseYn]").val();
//key값
url2 += '&name='+name;
goNav(url2);
@@ -80,7 +81,7 @@ $(document).ready(function() {
resizeJqGridWidth('grid','content_middle','1000');
$("#btn_search").click(function(){
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val()}, page:1 }).trigger("reloadGrid");
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()}, page:1 }).trigger("reloadGrid");
});
$("#btn_new").click(function(){
var url2 = url_view;
@@ -90,7 +91,8 @@ $(document).ready(function() {
url2 += '&menuId='+'${param.menuId}';
//검색값
url2 += '&searchName=';
url2 += '&searchUseYn='+$('select[name=searchUseYn]').val();
goNav(url2);
});
@@ -124,6 +126,16 @@ $(document).ready(function() {
<tr>
<th style="width:180px;">클라이언트명</th>
<td><input type="text" name="searchName" value="${param.searchName}"></td>
<th style="width:180px;">사용여부</th>
<td>
<div class="select-style">
<select name="searchUseYn">
<option value="">전체</option>
<option value="1">사용함</option>
<option value="0">사용안함</option>
</select>
</div>
</td>
</tr>
</tbody>
</table>
@@ -298,6 +298,7 @@ $(document).ready(function() {
url: url,
data: postData,
success: function(args) {
console.log('mod', args);
showAlert("<%= localeMessage.getString("common.saveMsg") %>", {
type: 'success',
title: '저장 완료',
@@ -493,11 +494,6 @@ $(document).ready(function() {
<span class="bucket-summary-value" id="summaryThreshold">0<span class="unit">req</span></span>
<span class="bucket-summary-sub" id="summaryThresholdCalc"></span>
</div>
<div class="bucket-summary-item">
<span class="bucket-summary-label">적용 API</span>
<span class="bucket-summary-value" id="summaryActiveApi">0<span class="unit">개</span></span>
<span class="bucket-summary-sub" id="summaryActiveApiList"></span>
</div>
</div>
</div>
@@ -88,7 +88,7 @@ $(document).ready(function() {
datatype:"json",
mtype: 'POST',
url: url,
postData : { cmd : 'LIST', searchGroupName: $('input[name=searchGroupName]').val()},
postData : { cmd : 'LIST', searchGroupName: $('input[name=searchGroupName]').val(), searchUseYn: $('select[name=searchUseYn]').val()},
colNames:['그룹 ID',
'그룹명',
'초당 임계치',
@@ -125,6 +125,7 @@ $(document).ready(function() {
url2 += '&menuId='+'${param.menuId}';
//검색값
url2 += '&searchGroupName='+$("input[name=searchGroupName]").val();
url2 += '&searchUseYn='+$("select[name=searchUseYn]").val();
//key값
url2 += '&groupId='+groupId;
goNav(url2);
@@ -143,7 +144,7 @@ $(document).ready(function() {
resizeJqGridWidth('grid','content_middle','1000');
$("#btn_search").click(function(){
$("#grid").setGridParam({ postData: { searchGroupName: $('input[name=searchGroupName]').val()}, page:1 }).trigger("reloadGrid");
$("#grid").setGridParam({ postData: { searchGroupName: $('input[name=searchGroupName]').val(), searchUseYn: $('select[name=searchUseYn]').val()}, page:1 }).trigger("reloadGrid");
});
$("#btn_new").click(function(){
var url2 = url_view;
@@ -188,6 +189,16 @@ $(document).ready(function() {
<tr>
<th style="width:180px;">그룹명</th>
<td><input type="text" name="searchGroupName" value="${param.searchGroupName}"></td>
<th style="width:180px;">사용여부</th>
<td>
<div class="select-style">
<select name="searchUseYn">
<option value="">전체</option>
<option value="1">사용함</option>
<option value="0">사용안함</option>
</select>
</div>
</td>
</tr>
</tbody>
</table>
@@ -25,7 +25,7 @@ $(document).ready(function() {
datatype:"json",
mtype: 'POST',
url: url,
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val()},
postData : { cmd : 'LIST', searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()},
colNames:['<%= localeMessage.getString("infIfConMan.ifNm") %>',
'<%= localeMessage.getString("infIfConMan.ifDesc") %>',
'<%= localeMessage.getString("infAdpConMan.thrPerSecond") %>',
@@ -62,6 +62,7 @@ $(document).ready(function() {
url2 += '&menuId='+'${param.menuId}';
//검색값
url2 += '&searchName='+$("input[name=searchName]").val();
url2 += '&searchUseYn='+$("select[name=searchUseYn]").val();
//key값
url2 += '&name='+name;
goNav(url2);
@@ -80,7 +81,7 @@ $(document).ready(function() {
resizeJqGridWidth('grid','content_middle','1000');
$("#btn_search").click(function(){
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val()}, page:1 }).trigger("reloadGrid");
$("#grid").setGridParam({ postData: { searchName: $('input[name=searchName]').val(), searchUseYn: $('select[name=searchUseYn]').val()}, page:1 }).trigger("reloadGrid");
});
$("#btn_new").click(function(){
var url2 = url_view;
@@ -126,6 +127,16 @@ $(document).ready(function() {
<tr>
<th style="width:180px;"><%= localeMessage.getString("infIfConMan.ifNm") %></th>
<td><input type="text" name="searchName" value="${param.searchName}"></td>
<th style="width:180px;"><%= localeMessage.getString("infAdpConMan.useYn") %></th>
<td>
<div class="select-style">
<select name="searchUseYn">
<option value="">전체</option>
<option value="1">사용함</option>
<option value="0">사용안함</option>
</select>
</div>
</td>
</tr>
</tbody>
</table>
@@ -77,7 +77,10 @@
display: inline-block;
vertical-align: middle;
}
/* iframe 모달(showModal) 콘텐츠 패딩 제거 — iframe 이 다이얼로그 폭을 최대한 사용해 내부 가로스크롤 방지 */
.ui-dialog .ui-dialog-content { padding: 0 !important; }
</style>
<script language="javascript" >
var isDetail = false;
@@ -1012,7 +1015,12 @@
window.open(urlAddServiceType(baseUrl + '&menuId=' + encodeURIComponent(getMenuId())), '_blank');
} else {
// 기본: 모달 + iframe. showModal 이 serviceType/menuId/pop 을 자동 부착.
showModal(baseUrl, { title: 'OpenAPI Spec' }, 1600, 880);
// 콘텐츠 고정폭 1600 + 다이얼로그 chrome(패딩/보더 ~40px) 때문에 iframe 내부폭이 1600 미만이면 가로스크롤 발생.
// 뷰포트 내에서 최대한 크게 열어(캡 1720) iframe 내부폭이 1600 이상 확보되게 한다.
var vw = $(window).width(), vh = $(window).height();
var modalW = Math.min(vw - 12, 1720);
var modalH = Math.min(vh - 20, 900);
showModal(baseUrl, { title: 'OpenAPI Spec' }, modalW, modalH);
}
}
@@ -1537,9 +1545,9 @@
<button type="button" class="cssbtn" id="btn_delete" level="W" status="DETAIL"><i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %></button>
<button type="button" class="cssbtn" id="btn_modify" level="R" status="DETAIL,NEW"><i class="material-icons">save</i> <%= localeMessage.getString("button.modify") %></button>
<!-- v1: 기존 API 스펙 (모달) — 기능 비교용 복원 -->
<button type="button" class="cssbtn" id="btn_api_spec" level="R" status="DETAIL,NEW"><i class="material-icons">description</i> API 스펙</button>
<button type="button" class="cssbtn" id="btn_api_spec" level="R" status="DETAIL"><i class="material-icons">description</i> API 스펙(삭제예정)</button>
<!-- v2: 신규 OpenAPI Spec (새 탭) -->
<button type="button" class="cssbtn" id="btn_openapi_spec" level="R" status="DETAIL,NEW"><i class="material-icons">api</i> OpenAPI Spec</button>
<button type="button" class="cssbtn" id="btn_openapi_spec" level="R" status="DETAIL"><i class="material-icons">api</i> OpenAPI Spec</button>
<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" style="font-size:1.4em">${rmsMenuName}</div>
+5 -10
View File
@@ -4,7 +4,6 @@ plugins {
id 'eclipse-wtp'
id 'idea'
id 'war'
id 'com.diffplug.eclipse.apt' version '3.41.1'
}
group 'com.eactive'
@@ -49,10 +48,6 @@ compileJava {
options.encoding = 'UTF-8'
options.compilerArgs = ['-parameters']
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
aptOptions {
processorArgs = [ 'querydsl.generatedAnnotationClass' : 'com.querydsl.core.annotations.Generated' ]
}
}
war {
@@ -257,11 +252,11 @@ eclipse {
}
synchronizationTasks settingEclipseEncoding, initDirs
jdt {
apt {
// generated .setting/org.eclipse.jdt.apt.core.prefs org.eclipse.jdt.apt.genSrcDir에 .
// project > properties > Java Compiler > Annoation Processing .
genSrcDir = file(generatedJavaDir)
}
// apt {
// // generated .setting/org.eclipse.jdt.apt.core.prefs org.eclipse.jdt.apt.genSrcDir에 .
// // project > properties > Java Compiler > Annoation Processing .
// genSrcDir = file(generatedJavaDir)
// }
}
project {
if (!natures.contains('org.eclipse.buildship.core.gradleprojectnature')) {
@@ -36,7 +36,7 @@ class MonitoringContextImpl implements MonitoringContext {
@Autowired
private MonitoringContextDAO monitoringContextDAO;
private Properties properties = null;
private Properties properties = new Properties();
private String instancePropertyGroupName;
@@ -73,7 +73,10 @@ class MonitoringContextImpl implements MonitoringContext {
String hostIp = InetAddress.getLocalHost().getHostAddress();
this.instancePropertyGroupName = String
.format(MonitoringPropertyGroupService.MONITORING_PROPERTY_KEY_FORMAT, hostIp);
this.properties = monitoringContextDAO.getProperties(instancePropertyGroupName);
Properties loaded = monitoringContextDAO.getProperties(instancePropertyGroupName);
if (loaded != null) {
this.properties = loaded;
}
String eaiAgentId = System.getProperty(EAI_AGENTID);
if (StringUtils.isBlank(eaiAgentId)) {
@@ -27,6 +27,8 @@ import com.eactive.eai.rms.onl.manage.inflow.history.InflowControlHistoryManUISe
import com.eactive.eai.rms.onl.manage.inflow.inflow.InflowControlManMapper;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.StringPath;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
@@ -46,7 +48,12 @@ public class InflowControlService extends AbstractDataService<InflowControl, Inf
@Autowired
InflowControlManMapper mapper;
public Page<InflowControlServiceDto> findAllForAdapter(Pageable pageable, String searchName) {
// 유량제어 미설정(useyn null) "사용안함" 검색 함께 조회되도록 처리
private static BooleanExpression useYnCondition(StringPath useYnPath, String searchUseYn) {
return "0".equals(searchUseYn) ? useYnPath.eq(searchUseYn).or(useYnPath.isNull()) : useYnPath.eq(searchUseYn);
}
public Page<InflowControlServiceDto> findAllForAdapter(Pageable pageable, String searchName, String searchUseYn) {
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QAdapterGroup qAdapterGroup = QAdapterGroup.adapterGroup;
QInflowControl qInflowControl = QInflowControl.inflowControl;
@@ -54,6 +61,8 @@ public class InflowControlService extends AbstractDataService<InflowControl, Inf
BooleanBuilder boolBuilder = new BooleanBuilder();
if (!StringUtils.isEmpty(searchName))
boolBuilder.and(qAdapterGroup.adptrbzwkgroupname.contains(searchName));
if (!StringUtils.isEmpty(searchUseYn))
boolBuilder.and(useYnCondition(qInflowControl.useyn, searchUseYn));
BooleanBuilder adapterWherePredicate = new BooleanBuilder(qAdapterGroup.adptriodstcd
.eq("I")
@@ -84,6 +93,10 @@ public class InflowControlService extends AbstractDataService<InflowControl, Inf
long totalCount = jpaQueryFactory
.select(qAdapterGroup.adptrbzwkgroupname.count())
.from(qAdapterGroup)
.leftJoin(qInflowControl)
.on(qAdapterGroup.adptrbzwkgroupname
.eq(qInflowControl.id.name)
.and(qInflowControl.id.type.eq(ADAPTER_TYPE_INFLOW)))
.where(boolBuilder)
.fetchOne();
@@ -121,17 +134,22 @@ public class InflowControlService extends AbstractDataService<InflowControl, Inf
return toDto(qAdapterGroup, qInflowControl, tuple);
}
public Page<InflowControlServiceDto> findAllForInterface(Pageable pageable, String searchName) {
public Page<InflowControlServiceDto> findAllForInterface(Pageable pageable, String searchName, String searchUseYn) {
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QInflowControl qInflowControl = QInflowControl.inflowControl;
QEAIMessageEntity qEAIMessageEntity = QEAIMessageEntity.eAIMessageEntity;
BooleanBuilder boolBuilder = new BooleanBuilder();
boolBuilder.and(qEAIMessageEntity.eaisvcname.contains(searchName));
if (!StringUtils.isEmpty(searchUseYn))
boolBuilder.and(useYnCondition(qInflowControl.useyn, searchUseYn));
List<Tuple> tupleList = jpaQueryFactory
.select(qInflowControl, qEAIMessageEntity.eaisvcname, qEAIMessageEntity.eaisvcdesc)
.from(qEAIMessageEntity)
.leftJoin(qInflowControl)
.on(qInflowControl.id.type.eq(INTERFACE_TYPE_INFLOW).and(qInflowControl.id.name.eq(qEAIMessageEntity.eaisvcname)))
.where(qEAIMessageEntity.eaisvcname.contains(searchName))
.where(boolBuilder)
.orderBy(qEAIMessageEntity.eaisvcname.asc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
@@ -145,7 +163,9 @@ public class InflowControlService extends AbstractDataService<InflowControl, Inf
long totalCount = jpaQueryFactory
.select(qEAIMessageEntity.eaisvcname.count())
.from(qEAIMessageEntity)
.where(qEAIMessageEntity.eaisvcname.contains(searchName))
.leftJoin(qInflowControl)
.on(qInflowControl.id.type.eq(INTERFACE_TYPE_INFLOW).and(qInflowControl.id.name.eq(qEAIMessageEntity.eaisvcname)))
.where(boolBuilder)
.fetchOne();
return new PageImpl<>(dtoList, pageable, totalCount);
}
@@ -199,19 +219,24 @@ public class InflowControlService extends AbstractDataService<InflowControl, Inf
return toDto(qClientEntity, qInflowControl, tuple);
}
public Page<InflowControlServiceDto> findAllForClient(Pageable pageable, String searchName) {
public Page<InflowControlServiceDto> findAllForClient(Pageable pageable, String searchName, String searchUseYn) {
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QInflowControl qInflowControl = QInflowControl.inflowControl;
QClientEntity qClientEntity = QClientEntity.clientEntity;
BooleanBuilder boolBuilder = new BooleanBuilder();
boolBuilder.and(qClientEntity.clientname.contains(searchName));
if (!StringUtils.isEmpty(searchUseYn))
boolBuilder.and(useYnCondition(qInflowControl.useyn, searchUseYn));
List<Tuple> tupleList = jpaQueryFactory
.select(qInflowControl, qClientEntity.clientid, qClientEntity.clientname)
.from(qClientEntity)
.leftJoin(qInflowControl)
.on(qInflowControl.id.type.eq(CLIENT_TYPE_INFLOW)
.and(qInflowControl.id.name.eq(qClientEntity.clientid)))
.where(qClientEntity.clientname.contains(searchName))
.where(boolBuilder)
.orderBy(qClientEntity.clientname.asc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
@@ -225,7 +250,10 @@ public class InflowControlService extends AbstractDataService<InflowControl, Inf
long totalCount = jpaQueryFactory
.select(qClientEntity.clientname.count())
.from(qClientEntity)
.where(qClientEntity.clientname.contains(searchName))
.leftJoin(qInflowControl)
.on(qInflowControl.id.type.eq(CLIENT_TYPE_INFLOW)
.and(qInflowControl.id.name.eq(qClientEntity.clientid)))
.where(boolBuilder)
.fetchOne();
return new PageImpl<>(dtoList, pageable, totalCount);
}
@@ -43,12 +43,6 @@ public class DjbProperty {
)
private String apiAllowIpList = "10.15.106.*, 10.14.8.*, 10.15.8.*, 192.168.240.*, 127.0.0.1, 192.168.132.*, 192.168.131.*";
@DjbPropertyValue(
key = "djb.api_gw_metric.page_size",
description = "API GW Metric 조회시 페이지 크기 설정 (Integer, 0 = 무한, 기본값 10000)",
defaultValue = "10000"
)
private Integer apiGwMetricPageSize = 10000;
@@ -1,23 +1,5 @@
package com.eactive.eai.rms.onl.apim.obp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.eactive.apim.portal.apprequest.entity.AppRequest;
import com.eactive.apim.portal.apprequest.repository.AppRequestRepository;
import com.eactive.apim.portal.obp.entity.ObpGwMetric;
@@ -28,7 +10,18 @@ import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricJpaDAO;
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricService;
import com.eactive.eai.rms.data.entity.onl.apim.obp.ObpGwMetricVO;
import com.eactive.eai.rms.ext.djb.common.DjbPropertyHolder;
//import com.eactive.ext.kjb.common.KjbPropertyHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
/**
* ObpGwMetric Man Service - 비즈니스 로직
@@ -335,7 +328,7 @@ public class ObpGwMetricManService extends BaseService {
DataSourceTypeManager.getDataSourceType(DataSourceTypeManager.MONITORING));
// KjbProperty에서 pageSize 읽기
Integer pageSize = DjbPropertyHolder.get().getApiGwMetricPageSize();
Integer pageSize = null; //KjbPropertyHolder.get().getApiGwMetricPageSize();
if (pageSize == null) {
pageSize = 10000; // 기본값 (null 안전 처리)
}
@@ -59,8 +59,8 @@ public class InflowGroupControlManController extends OnlBaseAnnotationController
*/
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=LIST")
public ResponseEntity<GridResponse<InflowGroupControlManUI>> selectList(HttpServletRequest request,
Pageable pageVo, String searchGroupName) {
Page<InflowGroupControlManUI> uiPage = service.selectGroupList(pageVo, searchGroupName);
Pageable pageVo, String searchGroupName, String searchUseYn) {
Page<InflowGroupControlManUI> uiPage = service.selectGroupList(pageVo, searchGroupName, searchUseYn);
return ResponseEntity.ok(new GridResponse<>(uiPage));
}
@@ -61,7 +61,7 @@ public class InflowGroupControlManService extends BaseService {
/**
* 그룹 목록 조회
*/
public Page<InflowGroupControlManUI> selectGroupList(Pageable pageable, String searchGroupName) {
public Page<InflowGroupControlManUI> selectGroupList(Pageable pageable, String searchGroupName, String searchUseYn) {
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QInflowControlGroup qGroup = QInflowControlGroup.inflowControlGroup;
@@ -69,6 +69,10 @@ public class InflowGroupControlManService extends BaseService {
if (!StringUtils.isEmpty(searchGroupName)) {
boolBuilder.and(qGroup.groupName.contains(searchGroupName));
}
if (!StringUtils.isEmpty(searchUseYn)) {
// 유량제어 미설정(useYn null) "사용안함" 검색 함께 조회되도록 처리
boolBuilder.and("0".equals(searchUseYn) ? qGroup.useYn.eq(searchUseYn).or(qGroup.useYn.isNull()) : qGroup.useYn.eq(searchUseYn));
}
List<InflowControlGroup> groupList = jpaQueryFactory
.selectFrom(qGroup)
@@ -42,8 +42,8 @@ public class InflowAdapterControlManController extends OnlBaseAnnotationControll
@RequestMapping(value = "/onl/admin/inflow/inflowAdapterControlMan.json", params = "cmd=LIST")
public ResponseEntity<GridResponse<InflowControlManUI>> selectList(HttpServletRequest request, Pageable pageVo,
String searchName) {
Page<InflowControlManUI> uiPage = service.selectAdapterList(pageVo, searchName);
String searchName, String searchUseYn) {
Page<InflowControlManUI> uiPage = service.selectAdapterList(pageVo, searchName, searchUseYn);
return ResponseEntity.ok(new GridResponse<>(uiPage));
}
@@ -19,7 +19,9 @@ import com.eactive.eai.agent.command.CommonCommand;
import com.eactive.eai.rms.common.base.OnlBaseAnnotationController;
import com.eactive.eai.rms.common.combo.ComboService;
import com.eactive.eai.rms.common.combo.ComboVo;
import com.eactive.eai.rms.common.util.CommonUtil;
import com.eactive.eai.rms.common.vo.GridResponse;
import com.eactive.eai.rms.common.vo.SimpleResponse;
@Controller
public class InflowClientControlManController extends OnlBaseAnnotationController {
@@ -42,8 +44,8 @@ public class InflowClientControlManController extends OnlBaseAnnotationControlle
@RequestMapping(value = "/onl/admin/inflow/inflowClientControlMan.json", params = "cmd=LIST")
public ResponseEntity<GridResponse<InflowControlManUI>> selectList(HttpServletRequest request, Pageable pageVo,
String searchName) {
Page<InflowControlManUI> uiPage = service.selectClientList(pageVo, searchName);
String searchName, String searchUseYn) {
Page<InflowControlManUI> uiPage = service.selectClientList(pageVo, searchName, searchUseYn);
return ResponseEntity.ok(new GridResponse<>(uiPage));
}
@@ -55,22 +57,22 @@ public class InflowClientControlManController extends OnlBaseAnnotationControlle
}
@RequestMapping(value = "/onl/admin/inflow/inflowClientControlMan.json", params = "cmd=UPDATE")
public String save(HttpServletRequest request, HttpServletResponse response, InflowControlManUI ui)
public ResponseEntity<SimpleResponse> save(HttpServletRequest request, HttpServletResponse response, InflowControlManUI ui)
throws Exception {
service.mergeClient(ui);
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.ReloadInflowClientControlCommand",
ui.getName());
agentUtilService.broadcast(command);
return null;
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.ReloadInflowClientControlCommand", ui.getName());
HashMap<String, Object> returnMap = agentUtilService.broadcast(command);
SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
return ResponseEntity.ok(simpleResponse);
}
@RequestMapping(value = "/onl/admin/inflow/inflowClientControlMan.json", params = "cmd=DELETE")
public String delete(HttpServletRequest request, HttpServletResponse response, String name) throws Exception {
public ResponseEntity<SimpleResponse> delete(HttpServletRequest request, HttpServletResponse response, String name) throws Exception {
service.deleteClient(name);
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.RemoveInflowClientControlCommand",
name);
agentUtilService.broadcast(command);
return null;
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.RemoveInflowClientControlCommand", name);
HashMap<String, Object> returnMap = agentUtilService.broadcast(command);
SimpleResponse simpleResponse = SimpleResponse.of(CommonUtil.getMapString(returnMap, true));
return ResponseEntity.ok(simpleResponse);
}
@RequestMapping(value = "/onl/admin/inflow/inflowClientControlMan.json", params = "cmd=LIST_INIT_COMBO")
@@ -1,5 +1,6 @@
package com.eactive.eai.rms.onl.manage.inflow.inflow;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -16,6 +17,7 @@ import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;
import com.eactive.eai.data.entity.onl.inflow.InflowControl;
import com.eactive.eai.data.entity.onl.inflow.InflowControlId;
@@ -50,8 +52,8 @@ public class InflowControlManService extends BaseService {
private RestTemplate restTemplate = new RestTemplate();
// 어댑터 유량제어
public Page<InflowControlManUI> selectAdapterList(Pageable pageable, String searchName) {
Page<InflowControlServiceDto> dtoList = service.findAllForAdapter(pageable, searchName);
public Page<InflowControlManUI> selectAdapterList(Pageable pageable, String searchName, String searchUseYn) {
Page<InflowControlServiceDto> dtoList = service.findAllForAdapter(pageable, searchName, searchUseYn);
return dtoList.map(mapper::toVo);
}
@@ -72,6 +74,9 @@ public class InflowControlManService extends BaseService {
} else {
entity = mapper.toEntity(ui);
}
if (entity.getThreshold() == null || StringUtils.isEmpty(entity.getThresholdtimeunit())) {
entity.setThreshold(0);
}
service.save(entity);
}
@@ -81,8 +86,8 @@ public class InflowControlManService extends BaseService {
}
// 인터페이스 유량제어
public Page<InflowControlManUI> selectInterfaceList(Pageable pageable, String searchName) {
Page<InflowControlServiceDto> dtoList = service.findAllForInterface(pageable, searchName);
public Page<InflowControlManUI> selectInterfaceList(Pageable pageable, String searchName, String searchUseYn) {
Page<InflowControlServiceDto> dtoList = service.findAllForInterface(pageable, searchName, searchUseYn);
return dtoList.map(mapper::toVo);
}
@@ -102,6 +107,9 @@ public class InflowControlManService extends BaseService {
} else {
entity = mapper.toEntity(ui);
}
if (entity.getThreshold() == null || StringUtils.isEmpty(entity.getThresholdtimeunit())) {
entity.setThreshold(0);
}
service.save(entity);
}
@@ -112,8 +120,8 @@ public class InflowControlManService extends BaseService {
// 클라이언트 유량제어
public Page<InflowControlManUI> selectClientList(Pageable pageable, String searchName) {
Page<InflowControlServiceDto> dtoList = service.findAllForClient(pageable, searchName);
public Page<InflowControlManUI> selectClientList(Pageable pageable, String searchName, String searchUseYn) {
Page<InflowControlServiceDto> dtoList = service.findAllForClient(pageable, searchName, searchUseYn);
return dtoList.map(mapper::toVo);
}
@@ -133,6 +141,9 @@ public class InflowControlManService extends BaseService {
} else {
entity = mapper.toEntity(ui);
}
if (entity.getThreshold() == null || StringUtils.isEmpty(entity.getThresholdtimeunit())) {
entity.setThreshold(0);
}
service.save(entity);
}
@@ -172,9 +183,12 @@ public class InflowControlManService extends BaseService {
serverStatus.put("serverPort", serverPort);
try {
String url = String.format("http://%s:%s/manage/inflow/%s/%s/bucket-status",
serverIp, serverPort, target, targetId);
ResponseEntity<Map> response = restTemplate.getForEntity(url, Map.class);
URI uri = UriComponentsBuilder.fromHttpUrl(String.format("http://%s:%s/manage/inflow", serverIp, serverPort))
.pathSegment(target, targetId, "bucket-status")
.build()
.encode()
.toUri();
ResponseEntity<Map> response = restTemplate.getForEntity(uri, Map.class);
if (response.getBody() != null && Boolean.TRUE.equals(response.getBody().get("success"))) {
serverStatus.put("status", "online");
@@ -42,8 +42,8 @@ public class InflowInterfaceControlManController extends OnlBaseAnnotationContro
@RequestMapping(value = "/onl/admin/inflow/inflowInterfaceControlMan.json", params = "cmd=LIST")
public ResponseEntity<GridResponse<InflowControlManUI>> selectList(HttpServletRequest request, Pageable pageVo,
String searchName) {
Page<InflowControlManUI> uiPage = service.selectInterfaceList(pageVo, searchName);
String searchName, String searchUseYn) {
Page<InflowControlManUI> uiPage = service.selectInterfaceList(pageVo, searchName, searchUseYn);
return ResponseEntity.ok(new GridResponse<>(uiPage));
}
@@ -448,14 +448,24 @@ public class ApiSpecManService {
// 헤더/바디 분리
RequestComponents components = separateHeaderAndBody(requestLayout.getLayoutItems());
// 헤더 파라미터 처리
if (!components.headerItems.isEmpty()) {
boolean bodyRequired = isRequestBodyRequired(httpMethod);
// 헤더 파라미터 + (POST/PUT 아니면) 요청 바디 항목을 쿼리스트링 파라미터로 함께 담는다.
boolean hasHeader = !components.headerItems.isEmpty();
boolean queryFromBody = !bodyRequired && !components.bodyItems.isEmpty();
if (hasHeader || queryFromBody) {
ArrayNode parameters = operation.putArray("parameters");
generateHeaderParameters(parameters, components.headerItems);
if (hasHeader) {
generateHeaderParameters(parameters, components.headerItems);
}
// GET/DELETE 바디 미사용 메소드: 요청 레이아웃 바디 항목 쿼리 파라미터(in=query)
if (queryFromBody) {
generateQueryParameters(parameters, components.bodyItems);
}
}
// Body 처리 (POST, PUT 메소드인 경우)
if (isRequestBodyRequired(httpMethod)) {
if (bodyRequired) {
ObjectNode requestBody = operation.putObject("requestBody");
requestBody.put("required", true);
ObjectNode content = requestBody.putObject("content");
@@ -561,6 +571,35 @@ public class ApiSpecManService {
}
}
/**
* GET/DELETE 바디 미사용 메소드: 요청 레이아웃 바디 항목을 쿼리스트링 파라미터(in=query) 매핑.
* 스칼라 FIELD 대상(GROUP/GRID 중첩 객체·배열은 쿼리스트링에 부적합하여 제외), root(serno 0) 스킵.
*/
private void generateQueryParameters(ArrayNode parameters, List<LayoutItemUI> bodyItems) {
for (LayoutItemUI item : bodyItems) {
if (item.getLoutItemSerno() != null && item.getLoutItemSerno() == 0) {
continue;
}
if (!"FIELD".equalsIgnoreCase(item.getLoutItemType())) {
continue;
}
ObjectNode parameter = parameters.addObject();
parameter.put("name", item.getLoutItemName());
parameter.put("in", "query");
if (StringUtils.isNotEmpty(item.getLoutItemDesc())) {
parameter.put("description", item.getLoutItemDesc());
}
parameter.put("required", false); // 기본값 false, 필요시 사용자가 변경
ObjectNode schema = parameter.putObject("schema");
schema.put("type", mapSwaggerType(item.getLoutItemDataType()));
int length = item.getLoutItemLength();
if (length > 0) {
schema.put("maxLength", length);
}
}
}
private void generateResponseHeaders(ObjectNode headers, List<LayoutItemUI> headerItems) {
for (LayoutItemUI item : headerItems) {
if ("FIELD".equalsIgnoreCase(item.getLoutItemType())) {
@@ -637,6 +676,7 @@ public class ApiSpecManService {
return "integer";
case "DECIMAL":
case "DOUBLE":
case "BIGDECIMAL":
return "number";
case "BOOLEAN":
return "boolean";