From 2422c7f01eaebb3ea3eb475e62f66311a25d80ef Mon Sep 17 00:00:00 2001 From: Rinjae Date: Wed, 29 Jul 2026 19:24:31 +0900 Subject: [PATCH] =?UTF-8?q?OpenAPI=20=EC=8A=A4=ED=8E=99=20=EB=82=B4?= =?UTF-8?q?=EB=B3=B4=EB=82=B4=EA=B8=B0(UI/DL)=20=EA=B8=B0=EB=8A=A5=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20-=20=EB=82=B4=EB=B3=B4=EB=82=B4=EA=B8=B0?= =?UTF-8?q?=20=ED=99=9C=EC=84=B1=ED=99=94=20=EC=97=AC=EB=B6=80=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=ED=82=A4=20=EC=B6=94=EA=B0=80(EXPORT=5FENABLED=5FK?= =?UTF-8?q?EY)=20-=20JSP/JS:=20=EB=82=B4=EB=B3=B4=EB=82=B4=EA=B8=B0=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EB=B0=8F=20=EB=8B=A4=EC=9A=B4=EB=A1=9C?= =?UTF-8?q?=EB=93=9C=20=EB=A1=9C=EC=A7=81=20=EC=97=B0=EB=8F=99=20-=20YAML/?= =?UTF-8?q?JSON=20=ED=8F=AC=EB=A7=B7=20=EC=A0=80=EC=9E=A5=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- WebContent/js/djb/apispec/app.js | 51 +++++++++++-------- .../transaction/apim/djbApiSpecManPopup.jsp | 4 ++ .../apim/DjbApiSpecController.java | 12 ++++- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/WebContent/js/djb/apispec/app.js b/WebContent/js/djb/apispec/app.js index 9bb7dca..649762e 100644 --- a/WebContent/js/djb/apispec/app.js +++ b/WebContent/js/djb/apispec/app.js @@ -349,8 +349,9 @@ } function fieldRow(label, controlHtml, opts) { opts = opts || {}; + const rowSpacing = opts.bordered ? 'px-3 py-3' : 'mb-3'; return ` -
+
`, { bordered: true }) + (showOrg ? fieldRow('๊ณต๊ฐœ ๋ฒ•์ธ', `
@@ -1048,7 +1050,7 @@
ํŠน์ • ๋ฒ•์ธ์—๊ฒŒ๋งŒ ๊ณต๊ฐœํ•˜๊ณ  ์‹ถ์„ ๋•Œ ๊ณต๊ฐœ ๋ฒ•์ธ์„ ์„ ํƒํ•˜์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.
-
`) : '') + +
`, { bordered: true }) : '') + fieldRow('์‘๋‹ต ์œ ํ˜•', '
' + ['sample', 'mock', 'gw'].map(v => @@ -1060,20 +1062,23 @@ + `
ํ˜ธ์ถœ ๋ฐฉ์‹: ${useProxyOn() ? 'ํฌํƒˆ ํ”„๋ก์‹œ ๊ฒฝ์œ ' : '์ง์ ‘ ํ˜ธ์ถœ'}` + (useProxyOn() ? ' (/api/call-api ๊ฒฝ์œ , ์ธ์ฆ ํ—ค๋” ์ž๋™ ์ฃผ์ž…)' : ' (๋ธŒ๋ผ์šฐ์ € โ†’ ๋Œ€์ƒ ์ง์ ‘ ํ˜ธ์ถœ, ๋Œ€์ƒ CORS ํ—ˆ์šฉ ํ•„์š”)') + `
`) + (rt === 'gw' ? `
GW ์ฃผ์†Œ๋Š” ํฌํƒˆ ์„ค์ •(PTL_PROPERTY, ๊ทธ๋ฃน Portal)์˜ djb.gateway.base-url ๊ฐ’์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
` : '') + - '
') + - (rt === 'mock' ? fieldRow('Mock Server URL', input(p.mockUrl || '', 'data-portal="mockUrl"', { placeholder: 'https://mock.example.com/api/v1/foo' }), { hint: 'Mock ์‘๋‹ต์„ ์ œ๊ณตํ•  ์ „์ฒด ํ˜ธ์ถœ URL(๊ฒฝ๋กœ ํฌํ•จ). ์‘๋‹ต ์œ ํ˜•์ด Mock ์ผ ๋•Œ ์ด ์ฃผ์†Œ๋กœ ๊ทธ๋Œ€๋กœ ํ˜ธ์ถœํ•˜๋ฉฐ, ์–ด๋Œ‘ํ„ฐ/์˜คํผ๋ ˆ์ด์…˜ ๊ฒฝ๋กœ๋ฅผ ๋’ค์— ๋ง๋ถ™์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.' }) : '') + '', { bordered: true }) + + (rt === 'mock' ? fieldRow('Mock Server URL', input(p.mockUrl || '', 'data-portal="mockUrl"', { placeholder: 'https://mock.example.com/api/v1/foo' }), { hint: 'Mock ์‘๋‹ต์„ ์ œ๊ณตํ•  ์ „์ฒด ํ˜ธ์ถœ URL(๊ฒฝ๋กœ ํฌํ•จ). ์‘๋‹ต ์œ ํ˜•์ด Mock ์ผ ๋•Œ ์ด ์ฃผ์†Œ๋กœ ๊ทธ๋Œ€๋กœ ํ˜ธ์ถœํ•˜๋ฉฐ, ์–ด๋Œ‘ํ„ฐ/์˜คํผ๋ ˆ์ด์…˜ ๊ฒฝ๋กœ๋ฅผ ๋’ค์— ๋ง๋ถ™์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.', bordered: true }) : '') + + '' ) + card( sectionTitle('์„ค๋ช… (API ์†Œ๊ฐœ ํŽ˜์ด์ง€)', 'API ์†Œ๊ฐœ ํŽ˜์ด์ง€์—๋งŒ ํ‘œ์‹œ๋ฉ๋‹ˆ๋‹ค. OpenAPI ์ŠคํŽ™ ํŒŒ์ผ์—๋Š” ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.') + '
' + (state.data.info.description.value || '') + '
' ) + + // ๋‚ด๋ณด๋‚ด๊ธฐ ์นด๋“œ๋Š” PTL_PROPERTY(djb.openapi.export.enabled=true) ์ผ ๋•Œ๋งŒ ๋…ธ์ถœ. ๊ธฐ๋ณธ ๋ฏธ๋…ธ์ถœ. + ((window.DJB_CTX && window.DJB_CTX.exportEnabled) ? card( sectionTitle('๋‚ด๋ณด๋‚ด๊ธฐ', 'OpenAPI ์ŠคํŽ™์„ ํŒŒ์ผ๋กœ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค.') + `
` - ); + ) : ''); initInfoDescEditor(); // ์„ค๋ช… ๋ฆฌ์น˜ ์—๋””ํ„ฐ (API ์†Œ๊ฐœ ํŽ˜์ด์ง€ ์ „์šฉ) } @@ -1653,7 +1658,7 @@ $('#btn-prev').addEventListener('click', () => goStep(state.step - 1)); $('#btn-next').addEventListener('click', () => { if (state.step < STEPS.length) goStep(state.step + 1); - else toast('๋ชจ๋“  ๋‹จ๊ณ„๋ฅผ ์™„๋ฃŒํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ์ธก ๋ฏธ๋ฆฌ๋ณด๊ธฐ ๋˜๋Š” ๋‚ด๋ณด๋‚ด๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜์„ธ์š”.'); + else saveSpec(false); // ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์˜ "์™„๋ฃŒ" โ†’ ์ €์žฅ ๋™์ž‘ }); $('#btn-toggle-preview').addEventListener('click', () => setPreviewVisibility(false)); @@ -1686,14 +1691,18 @@ toast('๋ณ€๊ฒฝ์„ ์ทจ์†Œํ–ˆ์Šต๋‹ˆ๋‹ค'); }); - $('#btn-export').addEventListener('click', () => $('#export-menu').classList.toggle('hidden')); - document.addEventListener('click', e => { - if (!e.target.closest('#btn-export') && !e.target.closest('#export-menu')) $('#export-menu').classList.add('hidden'); - }); - $('#export-menu').addEventListener('click', e => { - const b = e.target.closest('[data-export]'); - if (b) { downloadSpec(b.dataset.export); $('#export-menu').classList.add('hidden'); } - }); + // ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฒ„ํŠผ์€ djb.openapi.export.enabled=true ์ผ ๋•Œ๋งŒ DOM ์— ์กด์žฌ โ†’ ์—†์œผ๋ฉด ๋ฐ”์ธ๋”ฉ ์ƒ๋žต + var bExport = $('#btn-export'); + if (bExport) { + bExport.addEventListener('click', () => $('#export-menu').classList.toggle('hidden')); + document.addEventListener('click', e => { + if (!e.target.closest('#btn-export') && !e.target.closest('#export-menu')) $('#export-menu').classList.add('hidden'); + }); + $('#export-menu').addEventListener('click', e => { + const b = e.target.closest('[data-export]'); + if (b) { downloadSpec(b.dataset.export); $('#export-menu').classList.add('hidden'); } + }); + } var bSave = $('#btn-save'); if (bSave) bSave.addEventListener('click', () => saveSpec(false)); var bRegen = $('#btn-regen'); if (bRegen) bRegen.addEventListener('click', regenerate); @@ -2000,8 +2009,10 @@ state.data.msgSpec = state.data.msgSpec || { request: '', response: '' }; if (res.apiRequestSpec) state.data.msgSpec.request = decodeEntities(res.apiRequestSpec); if (res.apiResponseSpec) state.data.msgSpec.response = decodeEntities(res.apiResponseSpec); - // ์ €์žฅ๋ณธ์ด ์•„๋‹ˆ๋ฉด(์ž๋™์ƒ์„ฑ/์ตœ์ดˆ ์ƒ์„ฑ) ์ถ”๊ฐ€์ž๋ฃŒ(์˜ˆ์ œยท์„ค๋ช…์ž๋ฃŒ)๋ฅผ ํ”„๋ก ํŠธ์—์„œ ์Šคํ‚ค๋งˆ ๊ธฐ์ค€ ์ƒ์„ฑ - if ((res.source || '') !== 'saved') frontAutoGenerate(); + // ์ €์žฅ๋ณธ์ด ์•„๋‹ˆ๋ฉด(์ตœ์ดˆ ์ž‘์„ฑ) ์ž๋™์ƒ์„ฑ ์—ฌ๋ถ€๋ฅผ confirm ์œผ๋กœ ํ™•์ธ ํ›„ ์ง„ํ–‰ + if ((res.source || '') !== 'saved') { + if (window.confirm('์ €์žฅ๋œ ์ŠคํŽ™์ด ์—†์Šต๋‹ˆ๋‹ค. ๊ฒŒ์ดํŠธ์›จ์ด ๋ ˆ์ด์•„์›ƒ ๊ธฐ๋ฐ˜์œผ๋กœ ์˜ˆ์ œยท์„ค๋ช…์ž๋ฃŒ๋ฅผ ์ž๋™ ์ƒ์„ฑํ• ๊นŒ์š”?')) frontAutoGenerate(); + } }) .catch(e => console.error('loadInitialData', e)); } diff --git a/WebContent/jsp/onl/transaction/apim/djbApiSpecManPopup.jsp b/WebContent/jsp/onl/transaction/apim/djbApiSpecManPopup.jsp index 4338767..f13f631 100644 --- a/WebContent/jsp/onl/transaction/apim/djbApiSpecManPopup.jsp +++ b/WebContent/jsp/onl/transaction/apim/djbApiSpecManPopup.jsp @@ -69,6 +69,7 @@ gwAddress: "${gwAddress}", useProxy: ${useProxy}, tokenUseProxy: ${tokenUseProxy}, + exportEnabled: ${exportEnabled}, orgPopupUrl: "", groupPopupUrl: "?cmd=GROUP_POPUP", jsonUrl: "" @@ -93,6 +94,8 @@ + <%-- ๋‚ด๋ณด๋‚ด๊ธฐ ๋ฒ„ํŠผ์€ PTL_PROPERTY(djb.openapi.export.enabled=true) ์ผ ๋•Œ๋งŒ ๋…ธ์ถœ. ๊ธฐ๋ณธ ๋ฏธ๋…ธ์ถœ. --%> +
+
diff --git a/src/main/java/com/eactive/eai/rms/onl/transaction/apim/DjbApiSpecController.java b/src/main/java/com/eactive/eai/rms/onl/transaction/apim/DjbApiSpecController.java index 428bb0e..ac58f06 100644 --- a/src/main/java/com/eactive/eai/rms/onl/transaction/apim/DjbApiSpecController.java +++ b/src/main/java/com/eactive/eai/rms/onl/transaction/apim/DjbApiSpecController.java @@ -75,6 +75,8 @@ public class DjbApiSpecController extends OnlBaseAnnotationController { // ํ…Œ์ŠคํŠธ๋ฒ ๋“œ ํ”„๋ก์‹œ ์‚ฌ์šฉ ์—ฌ๋ถ€(ํฌํƒˆ DjbTestbedGatewayProperty ์™€ ๋™์ผ ํ‚ค). ๋งˆ๋ฒ•์‚ฌ์— ํ˜ธ์ถœ/์ธ์ฆ ํ”„๋ก์‹œ ๊ฒฝ์œ  ์•ˆ๋‚ด์šฉ. private static final String USE_PROXY_KEY = "djb.gateway.use-proxy"; private static final String TOKEN_USE_PROXY_KEY = "djb.gateway.token-use-proxy"; + // OpenAPI ์ŠคํŽ™ ๋‚ด๋ณด๋‚ด๊ธฐ(YAML/JSON ๋‹ค์šด๋กœ๋“œ) UI ๋…ธ์ถœ ์—ฌ๋ถ€. ๊ธฐ๋ณธ false(์‚ฌ์šฉ์•ˆํ•จ). + private static final String EXPORT_ENABLED_KEY = "djb.openapi.export.enabled"; // "PortalMock" ์€ ํฌํƒˆ์ด ์š”์ฒญ origin ์œผ๋กœ ์น˜ํ™˜ํ•˜๋Š” sentinel ์ด๋ผ admin ๋ฏธ๋ฆฌ๋ณด๊ธฐ์šฉ ์„œ๋ฒ„ ์ฃผ์†Œ๋กœ๋Š” ๋ถ€์ ํ•ฉ โ†’ ๋Œ€์ฒด๊ฐ’ ์‚ฌ์šฉ. private static final String GW_PREVIEW_FALLBACK = "http://127.0.0.1:39310"; @@ -91,14 +93,20 @@ public class DjbApiSpecController extends OnlBaseAnnotationController { // ํ…Œ์ŠคํŠธ๋ฒ ๋“œ ํ”„๋ก์‹œ(/api/call-api) ์‚ฌ์šฉ ์—ฌ๋ถ€ โ€” mock/gw ํ˜ธ์ถœยท์ธ์ฆ ํ”„๋ก์‹œ ๊ฒฝ์œ  ์•ˆ๋‚ด ํ‘œ๊ธฐ์šฉ model.addAttribute("useProxy", resolveBoolProperty(USE_PROXY_KEY, true)); model.addAttribute("tokenUseProxy", resolveBoolProperty(TOKEN_USE_PROXY_KEY, true)); + // ๋‚ด๋ณด๋‚ด๊ธฐ UI ๋…ธ์ถœ ์—ฌ๋ถ€(djb.openapi.export.enabled) โ€” ๋ฏธ์„ค์ • ์‹œ false(์‚ฌ์šฉ์•ˆํ•จ)๋กœ ์ƒ์„ฑ + model.addAttribute("exportEnabled", resolveBoolProperty( + EXPORT_ENABLED_KEY, false, "OpenAPI ์ŠคํŽ™ ๋‚ด๋ณด๋‚ด๊ธฐ(YAML/JSON) UI ๋…ธ์ถœ ์—ฌ๋ถ€(true/false)")); return "/onl/transaction/apim/djbApiSpecManPopup"; } /** ํฌํƒˆ ๊ทธ๋ฃน ํ”„๋กœํผํ‹ฐ(๋ถˆ๋ฆฌ์–ธ, ๋ ˆ๊ฑฐ์‹œ Y/N ํฌํ•จ)๋ฅผ ์ฝ์–ด boolean ์œผ๋กœ ํ•ด์„. ๋ฏธ์„ค์ •/ํŒŒ์‹ฑ๋ถˆ๊ฐ€ ์‹œ default. */ private boolean resolveBoolProperty(String key, boolean def) { + return resolveBoolProperty(key, def, "ํ…Œ์ŠคํŠธ๋ฒ ๋“œ ํ”„๋ก์‹œ(/api/call-api) ์‚ฌ์šฉ ์—ฌ๋ถ€(true/false)"); + } + + private boolean resolveBoolProperty(String key, boolean def, String description) { String v = portalPropertyService.getOrCreateProperty( - "Portal", key, def ? "true" : "false", - "ํ…Œ์ŠคํŠธ๋ฒ ๋“œ ํ”„๋ก์‹œ(/api/call-api) ์‚ฌ์šฉ ์—ฌ๋ถ€(true/false)"); + "Portal", key, def ? "true" : "false", description); if (v == null) { return def; }