API 그룹 팝업 JSP 추가 - Swagger Validator JS 등록 - Summernote CSS 추가
- API 그룹 팝업(djbApiGroupPopup.jsp) 화면 파일 추가 - Swagger Validator (djb-swagger-validator.js) 및 관련 리팩토링 - Summernote 콘텐츠 스타일 정의 (editor-content.css) 추가
This commit is contained in:
+564
-278
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,334 @@
|
|||||||
|
/**
|
||||||
|
* Editor Content Styles (editor-content.css)
|
||||||
|
*
|
||||||
|
* Summernote 에디터로 작성된 HTML 콘텐츠의 공통 스타일
|
||||||
|
* 관리자포탈/개발자포탈 양쪽에서 동일하게 사용
|
||||||
|
*
|
||||||
|
* 사용법:
|
||||||
|
* - 관리자포탈: Summernote .note-editable에 .editor-content 클래스 추가
|
||||||
|
* - 개발자포탈: 콘텐츠 wrapper에 .editor-content 클래스 추가
|
||||||
|
*
|
||||||
|
* @version 1.0.0
|
||||||
|
* @date 2025-12-30
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
CSS Reset + 기본 설정
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content {
|
||||||
|
all: revert;
|
||||||
|
font-family: 'Noto Sans KR', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
font-weight: 400 !important;
|
||||||
|
line-height: 1.8 !important;
|
||||||
|
color: #1A1A2E !important;
|
||||||
|
word-wrap: break-word;
|
||||||
|
text-align: left !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
헤딩 (Headings)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content h1 {
|
||||||
|
font-size: 20px !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
margin: 32px 0 16px !important;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
color: #1A1A2E !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content h1:first-child {
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content h2 {
|
||||||
|
font-size: 18px !important;
|
||||||
|
font-weight: 700 !important;
|
||||||
|
margin: 24px 0 8px !important;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
color: #1A1A2E !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content h3 {
|
||||||
|
font-size: 16px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
margin: 16px 0 8px !important;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
color: #1A1A2E !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content h4,
|
||||||
|
.editor-content h5,
|
||||||
|
.editor-content h6 {
|
||||||
|
font-size: 16px !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
margin: 16px 0 8px !important;
|
||||||
|
line-height: 1.4 !important;
|
||||||
|
color: #1A1A2E !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
단락 (Paragraphs)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content p {
|
||||||
|
margin-bottom: 16px !important;
|
||||||
|
line-height: 1.8 !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content p:last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
리스트 (Lists) - 글로벌 reset 대응
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content ul {
|
||||||
|
list-style-type: disc !important;
|
||||||
|
padding-left: 32px !important;
|
||||||
|
margin: 16px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content ol {
|
||||||
|
list-style-type: decimal !important;
|
||||||
|
padding-left: 32px !important;
|
||||||
|
margin: 16px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content li {
|
||||||
|
margin-bottom: 8px !important;
|
||||||
|
line-height: 1.8 !important;
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content li:last-child {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 중첩 리스트 */
|
||||||
|
.editor-content ul ul {
|
||||||
|
list-style-type: circle !important;
|
||||||
|
margin: 8px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content ul ul ul {
|
||||||
|
list-style-type: square !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content ol ol {
|
||||||
|
list-style-type: lower-alpha !important;
|
||||||
|
margin: 8px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content ol ol ol {
|
||||||
|
list-style-type: lower-roman !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
테이블 (Tables)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content table {
|
||||||
|
width: 100% !important;
|
||||||
|
border-collapse: collapse !important;
|
||||||
|
margin: 24px 0 !important;
|
||||||
|
border: 1px solid #E2E8F0 !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content th,
|
||||||
|
.editor-content td {
|
||||||
|
border: 1px solid #E2E8F0 !important;
|
||||||
|
padding: 8px 16px !important;
|
||||||
|
text-align: left !important;
|
||||||
|
vertical-align: top !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content th {
|
||||||
|
background: #EFF6FF !important;
|
||||||
|
font-weight: 600 !important;
|
||||||
|
color: #1A1A2E !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content tr:hover {
|
||||||
|
background: #F8FAFC !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
링크 (Links)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content a {
|
||||||
|
color: #0049b4 !important;
|
||||||
|
text-decoration: underline !important;
|
||||||
|
transition: color 0.3s ease !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content a:hover {
|
||||||
|
color: #003080 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
인용문 (Blockquote)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content blockquote {
|
||||||
|
border-left: 4px solid #0049b4 !important;
|
||||||
|
padding: 16px 24px !important;
|
||||||
|
margin: 24px 0 !important;
|
||||||
|
background: #F8FAFC !important;
|
||||||
|
font-style: italic !important;
|
||||||
|
color: #64748B !important;
|
||||||
|
border-radius: 0 8px 8px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content blockquote p {
|
||||||
|
margin-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
이미지 (Images)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content img {
|
||||||
|
max-width: 100% !important;
|
||||||
|
height: auto !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
margin: 16px 0 !important;
|
||||||
|
display: block !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
코드 (Code)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content code {
|
||||||
|
background: #F8FAFC !important;
|
||||||
|
padding: 2px 6px !important;
|
||||||
|
border-radius: 4px !important;
|
||||||
|
font-family: 'Fira Code', 'Courier New', monospace !important;
|
||||||
|
font-size: 0.9em !important;
|
||||||
|
color: #0049b4 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content pre {
|
||||||
|
background: #F8FAFC !important;
|
||||||
|
border: 1px solid #E2E8F0 !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
padding: 16px !important;
|
||||||
|
overflow-x: auto !important;
|
||||||
|
margin: 16px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content pre code {
|
||||||
|
background: transparent !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
color: #1A1A2E !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
구분선 (Horizontal Rule)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content hr {
|
||||||
|
border: none !important;
|
||||||
|
border-top: 1px solid #E2E8F0 !important;
|
||||||
|
margin: 32px 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
텍스트 강조 (Text Emphasis)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
.editor-content strong,
|
||||||
|
.editor-content b {
|
||||||
|
font-weight: 700 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content em,
|
||||||
|
.editor-content i {
|
||||||
|
font-style: italic !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content u {
|
||||||
|
text-decoration: underline !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content s,
|
||||||
|
.editor-content strike,
|
||||||
|
.editor-content del {
|
||||||
|
text-decoration: line-through !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content mark {
|
||||||
|
background-color: #FEF3C7 !important;
|
||||||
|
padding: 0 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content sub {
|
||||||
|
vertical-align: sub !important;
|
||||||
|
font-size: 0.8em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content sup {
|
||||||
|
vertical-align: super !important;
|
||||||
|
font-size: 0.8em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==========================================================================
|
||||||
|
반응형 (Responsive)
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.editor-content {
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content h1 {
|
||||||
|
font-size: 18px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content h2 {
|
||||||
|
font-size: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content h3,
|
||||||
|
.editor-content h4,
|
||||||
|
.editor-content h5,
|
||||||
|
.editor-content h6 {
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content p,
|
||||||
|
.editor-content li {
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content table {
|
||||||
|
font-size: 12px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content th,
|
||||||
|
.editor-content td {
|
||||||
|
padding: 4px 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content ul,
|
||||||
|
.editor-content ol {
|
||||||
|
padding-left: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content blockquote {
|
||||||
|
padding: 8px 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.editor-content pre {
|
||||||
|
padding: 8px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
<script language="javascript" >
|
<script language="javascript" >
|
||||||
var url = '<c:url value="/onl/apim/apigroup/apiGroupMan.json"/>';
|
var url = '<c:url value="/onl/apim/apigroup/apiGroupMan.json"/>';
|
||||||
var url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view"/>';
|
var url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view"/>';
|
||||||
var url_popup_view = '<c:url value="/onl/transaction/apim/apiSpecManPopup.view"/>';
|
var url_popup_view = '<c:url value="/onl/transaction/apim/apiSpecMan.view"/>';
|
||||||
|
|
||||||
var isDetail = false;
|
var isDetail = false;
|
||||||
let dialog;
|
let dialog;
|
||||||
|
|||||||
@@ -86,9 +86,11 @@
|
|||||||
editurl: "clientArray",
|
editurl: "clientArray",
|
||||||
colNames: ['<%= localeMessage.getString("propertyDetail.propertyKey") %>',
|
colNames: ['<%= localeMessage.getString("propertyDetail.propertyKey") %>',
|
||||||
'<%= localeMessage.getString("propertyDetail.propertyValue") %>',
|
'<%= localeMessage.getString("propertyDetail.propertyValue") %>',
|
||||||
|
'설명',
|
||||||
'<%= localeMessage.getString("propertyDetail.delYn") %>'],
|
'<%= localeMessage.getString("propertyDetail.delYn") %>'],
|
||||||
colModel: [{name: 'PRPTYNAME', width: 50, align: 'left', editable: true},
|
colModel: [{name: 'PRPTYNAME', width: 50, align: 'left', editable: true},
|
||||||
{name: 'PRPTY2VAL', width: 200, align: 'left', editable: true},
|
{name: 'PRPTY2VAL', width: 150, align: 'left', editable: true},
|
||||||
|
{name: 'PRPTYDESC', width: 200, align: 'left', editable: true, edittype: 'textarea', editoptions: {rows: 2}},
|
||||||
{
|
{
|
||||||
name: 'DELETEYN',
|
name: 'DELETEYN',
|
||||||
width: 20,
|
width: 20,
|
||||||
@@ -258,6 +260,7 @@
|
|||||||
var data = new Object();
|
var data = new Object();
|
||||||
data["PRPTYNAME"] = $("input[name=prptyName]").val();
|
data["PRPTYNAME"] = $("input[name=prptyName]").val();
|
||||||
data["PRPTY2VAL"] = $("input[name=prpty2Val]").val();
|
data["PRPTY2VAL"] = $("input[name=prpty2Val]").val();
|
||||||
|
data["PRPTYDESC"] = $("input[name=prptyDesc]").val();
|
||||||
|
|
||||||
var rows = $("#grid")[0].rows;
|
var rows = $("#grid")[0].rows;
|
||||||
var index = Number($(rows[rows.length - 1]).attr("id"));
|
var index = Number($(rows[rows.length - 1]).attr("id"));
|
||||||
@@ -340,6 +343,11 @@
|
|||||||
<td colspan="3"><input type="text" name="prpty2Val"/>
|
<td colspan="3"><input type="text" name="prpty2Val"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th>설명</th>
|
||||||
|
<td colspan="3"><input type="text" name="prptyDesc"/>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<!-- grid -->
|
<!-- grid -->
|
||||||
<table id="grid"></table>
|
<table id="grid"></table>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</style>
|
</style>
|
||||||
<script language="javascript">
|
<script language="javascript">
|
||||||
var url = '<c:url value="/onl/transaction/apim/apiSpecMan.json" />';
|
var url = '<c:url value="/onl/transaction/apim/apiSpecMan.json" />';
|
||||||
var url_org ='<c:url value="/onl/transaction/apim/apiSpecManPopup.view" />';
|
var url_org ='<c:url value="/onl/transaction/apim/apiSpecMan.view" />';
|
||||||
var isDetail = false;
|
var isDetail = false;
|
||||||
var sampleRequestEditor, sampleResponseEditor, testbedSpecEditor;
|
var sampleRequestEditor, sampleResponseEditor, testbedSpecEditor;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,132 @@
|
|||||||
|
<%@ page language="java" contentType="text/html; charset=utf-8"%>
|
||||||
|
<%@ page import="java.io.*"%>
|
||||||
|
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
|
||||||
|
<%@ 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>API 그룹 선택</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||||
|
<jsp:include page="/jsp/common/include/css_custom.jsp"/>
|
||||||
|
<jsp:include page="/jsp/common/include/css.jsp"/>
|
||||||
|
<jsp:include page="/jsp/common/include/script.jsp"/>
|
||||||
|
<script language="javascript">
|
||||||
|
var url = '<c:url value="/onl/apim/apigroup/apiGroupMan.json" />';
|
||||||
|
|
||||||
|
function search() {
|
||||||
|
var postData = getSearchForJqgrid("cmd", "LIST");
|
||||||
|
$("#grid").setGridParam({url: url, postData: postData, page: 1}).trigger("reloadGrid");
|
||||||
|
}
|
||||||
|
|
||||||
|
$(document).ready(function() {
|
||||||
|
var urlParams = new URLSearchParams(window.location.search);
|
||||||
|
var selectedGroupIds = urlParams.get("selectedGroupIds");
|
||||||
|
|
||||||
|
if (selectedGroupIds) {
|
||||||
|
selectedGroupIds = selectedGroupIds.split(','); // 콤마로 구분된 ID들을 배열로 변환
|
||||||
|
} else {
|
||||||
|
selectedGroupIds = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$('#grid').jqGrid({
|
||||||
|
datatype: "json",
|
||||||
|
mtype: 'POST',
|
||||||
|
url: url,
|
||||||
|
postData: getSearchForJqgrid("cmd", "LIST"),
|
||||||
|
colNames: ['API 그룹 ID', 'API 그룹 명', '설명'],
|
||||||
|
colModel: [
|
||||||
|
{name: 'id', hidden: true},
|
||||||
|
{name: 'groupName', align: 'center', width: "180"},
|
||||||
|
{name: 'groupDesc', align: 'left', width: "200"}
|
||||||
|
],
|
||||||
|
jsonReader: {
|
||||||
|
repeatitems: false
|
||||||
|
},
|
||||||
|
pager: $('#pager'),
|
||||||
|
page: '${param.page}',
|
||||||
|
rowNum: '${rmsDefaultRowNum}',
|
||||||
|
autoheight: true,
|
||||||
|
height: 'auto',
|
||||||
|
width: 410,
|
||||||
|
autowidth: false,
|
||||||
|
viewrecords: true,
|
||||||
|
shrinkToFit: false,
|
||||||
|
multiselect: true,
|
||||||
|
multiboxonly: false,
|
||||||
|
loadComplete: function(data) {
|
||||||
|
var $grid = $(this);
|
||||||
|
$.each($grid.getDataIDs(), function(_, id) {
|
||||||
|
var rowData = $grid.getRowData(id);
|
||||||
|
if ($.inArray(rowData.id, selectedGroupIds) !== -1) {
|
||||||
|
$grid.jqGrid('setSelection', id, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#btn_search").click(search);
|
||||||
|
|
||||||
|
$("#btn_save").click(function() {
|
||||||
|
var selectedRows = $('#grid').getGridParam('selarrrow');
|
||||||
|
|
||||||
|
var selectedGroups = [];
|
||||||
|
if (selectedRows.length > 0) {
|
||||||
|
selectedGroups = selectedRows.map(function(rowid) {
|
||||||
|
var rowData = $('#grid').getRowData(rowid);
|
||||||
|
return {
|
||||||
|
id: rowData.id,
|
||||||
|
groupName: rowData.groupName
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 부모 창의 selectApiGroup 함수 호출
|
||||||
|
if (window.parent && typeof window.parent.selectApiGroup === "function") {
|
||||||
|
window.parent.selectApiGroup(selectedGroups);
|
||||||
|
window.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#btn_close").click(function () {
|
||||||
|
window.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
// 검색어 입력 후 엔터 키 처리
|
||||||
|
$("input[name=searchGroupName]").keydown(function(key) {
|
||||||
|
if (key.keyCode == 13) {
|
||||||
|
search();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="popup_box">
|
||||||
|
<div class="search_wrap">
|
||||||
|
<button type="button" class="cssbtn" id="btn_save" level="W">
|
||||||
|
<i class="material-icons">save</i> <%= localeMessage.getString("button.save") %>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="cssbtn" id="btn_search" level="R">
|
||||||
|
<i class="material-icons">search</i> <%= localeMessage.getString("button.search") %>
|
||||||
|
</button>
|
||||||
|
<button type="button" class="cssbtn" id="btn_close" level="R" status="DETAIL"><i
|
||||||
|
class="material-icons">close</i> <%= localeMessage.getString("button.close") %>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="title"></div>
|
||||||
|
<table class="search_condition" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<th style="width:80px;">API 그룹 명</th>
|
||||||
|
<td>
|
||||||
|
<input type="text" name="searchGroupName" value="${param.searchGroupName}">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table id="grid"></table>
|
||||||
|
<div id="pager"></div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=1600" />
|
<meta name="viewport" content="width=1600" />
|
||||||
<title>DJB API 문서 에디터 — OpenAPI Editor</title>
|
<title>OpenAPI Spec 에디터</title>
|
||||||
|
|
||||||
<%-- Tailwind (벤더된 Play CDN JS, 오프라인) --%>
|
<%-- Tailwind (벤더된 Play CDN JS, 오프라인) --%>
|
||||||
<script src="<c:url value='/plugins/openapi/tailwind.js'/>"></script>
|
<script src="<c:url value='/plugins/openapi/tailwind.js'/>"></script>
|
||||||
@@ -33,9 +33,12 @@
|
|||||||
<link rel="stylesheet" href="<c:url value='/addon/codemirror/lib/codemirror.css'/>" />
|
<link rel="stylesheet" href="<c:url value='/addon/codemirror/lib/codemirror.css'/>" />
|
||||||
<script src="<c:url value='/addon/codemirror/lib/codemirror.js'/>"></script>
|
<script src="<c:url value='/addon/codemirror/lib/codemirror.js'/>"></script>
|
||||||
<script src="<c:url value='/addon/codemirror/mode/yaml/yaml.js'/>"></script>
|
<script src="<c:url value='/addon/codemirror/mode/yaml/yaml.js'/>"></script>
|
||||||
|
<script src="<c:url value='/addon/codemirror/mode/javascript/javascript.js'/>"></script>
|
||||||
|
|
||||||
<%-- jQuery + Summernote(lite, 무-Bootstrap) — 설명 리치 에디터 --%>
|
<%-- jQuery + Summernote(lite, 무-Bootstrap) — 설명 리치 에디터 --%>
|
||||||
<link rel="stylesheet" href="<c:url value='/addon/summernote/summernote-lite.css'/>" />
|
<link rel="stylesheet" href="<c:url value='/addon/summernote/summernote-lite.css'/>" />
|
||||||
|
<%-- 개발자포탈과 동일한 에디터 콘텐츠 스타일(.editor-content, Noto Sans KR 16px) --%>
|
||||||
|
<link rel="stylesheet" href="<c:url value='/js/djb/apispec/editor-content.css'/>" />
|
||||||
<script src="<c:url value='/js/jquery-1.12.1.min.js'/>"></script>
|
<script src="<c:url value='/js/jquery-1.12.1.min.js'/>"></script>
|
||||||
<script src="<c:url value='/addon/summernote/summernote-lite.min.js'/>"></script>
|
<script src="<c:url value='/addon/summernote/summernote-lite.min.js'/>"></script>
|
||||||
<script src="<c:url value='/addon/summernote/lang/summernote-ko-KR.js'/>"></script>
|
<script src="<c:url value='/addon/summernote/lang/summernote-ko-KR.js'/>"></script>
|
||||||
@@ -64,7 +67,8 @@
|
|||||||
saveUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.json'/>?cmd=SAVE&serviceType=APIGW",
|
saveUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.json'/>?cmd=SAVE&serviceType=APIGW",
|
||||||
swaggerBase: "<c:url value='/plugins/swaggerUI/'/>",
|
swaggerBase: "<c:url value='/plugins/swaggerUI/'/>",
|
||||||
gwAddress: "${gwAddress}",
|
gwAddress: "${gwAddress}",
|
||||||
orgPopupUrl: "<c:url value='/onl/transaction/apim/apiSpecManPopup.view'/>",
|
orgPopupUrl: "<c:url value='/onl/transaction/apim/apiSpecMan.view'/>",
|
||||||
|
groupPopupUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.view'/>?cmd=GROUP_POPUP",
|
||||||
jsonUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.json'/>"
|
jsonUrl: "<c:url value='/onl/transaction/apim/djbApiSpecMan.json'/>"
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
@@ -103,7 +107,7 @@
|
|||||||
<div class="h-1 bg-slate-100">
|
<div class="h-1 bg-slate-100">
|
||||||
<div id="stepper-progress" class="h-1 bg-brand-500 transition-all duration-300" style="width:16.66%"></div>
|
<div id="stepper-progress" class="h-1 bg-brand-500 transition-all duration-300" style="width:16.66%"></div>
|
||||||
</div>
|
</div>
|
||||||
<ol id="stepper" class="grid grid-cols-6 px-2"></ol>
|
<ol id="stepper" class="grid grid-cols-5 px-2"></ol>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<!-- ===== Body ===== -->
|
<!-- ===== Body ===== -->
|
||||||
@@ -111,7 +115,7 @@
|
|||||||
<section id="form-panel" class="bg-white border-r border-slate-200 transition-all duration-300" style="width:960px;">
|
<section id="form-panel" class="bg-white border-r border-slate-200 transition-all duration-300" style="width:960px;">
|
||||||
<div class="flex items-center justify-between px-6 py-3 border-b border-slate-100 sticky bg-white z-10" style="top:128px;">
|
<div class="flex items-center justify-between px-6 py-3 border-b border-slate-100 sticky bg-white z-10" style="top:128px;">
|
||||||
<div class="flex items-baseline gap-3">
|
<div class="flex items-baseline gap-3">
|
||||||
<span class="text-xs uppercase tracking-wide text-slate-400">Step <span id="form-step-num">1</span> / 6</span>
|
<span class="text-xs uppercase tracking-wide text-slate-400">Step <span id="form-step-num">1</span> / 5</span>
|
||||||
<h2 class="text-base font-semibold text-slate-800" id="form-step-title">기본정보</h2>
|
<h2 class="text-base font-semibold text-slate-800" id="form-step-title">기본정보</h2>
|
||||||
</div>
|
</div>
|
||||||
<button id="btn-toggle-preview-from-form" class="hidden text-xs px-2 py-1 rounded border border-slate-200 text-slate-600 hover:bg-slate-50">▶ 미리보기 다시 열기</button>
|
<button id="btn-toggle-preview-from-form" class="hidden text-xs px-2 py-1 rounded border border-slate-200 text-slate-600 hover:bg-slate-50">▶ 미리보기 다시 열기</button>
|
||||||
|
|||||||
+80
-85
@@ -1,10 +1,9 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id 'java-library'
|
id 'java-library'
|
||||||
id 'eclipse'
|
id 'eclipse'
|
||||||
id 'eclipse-wtp'
|
id 'eclipse-wtp'
|
||||||
id 'idea'
|
id 'idea'
|
||||||
id 'war'
|
id 'war'
|
||||||
id 'com.diffplug.eclipse.apt' version '3.41.1'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
group 'com.eactive'
|
group 'com.eactive'
|
||||||
@@ -32,11 +31,11 @@ allprojects {
|
|||||||
project.webAppDirName = 'WebContent'
|
project.webAppDirName = 'WebContent'
|
||||||
|
|
||||||
java {
|
java {
|
||||||
toolchain {
|
toolchain {
|
||||||
languageVersion = JavaLanguageVersion.of(8)
|
languageVersion = JavaLanguageVersion.of(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
main {
|
main {
|
||||||
java {
|
java {
|
||||||
@@ -46,56 +45,56 @@ sourceSets {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
options.compilerArgs = ['-parameters']
|
options.compilerArgs = ['-parameters']
|
||||||
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
|
options.generatedSourceOutputDirectory = project.file(generatedJavaDir)
|
||||||
|
|
||||||
aptOptions {
|
|
||||||
processorArgs = [ 'querydsl.generatedAnnotationClass' : 'com.querydsl.core.annotations.Generated' ]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
war {
|
war {
|
||||||
def profile = project.findProperty("profile") ?: "tomcat"
|
def profile = project.findProperty("profile") ?: "tomcat"
|
||||||
|
|
||||||
if (profile == "weblogic") {
|
if (profile == "weblogic") {
|
||||||
webXml = file("WebContent/WEB-INF/weblogic-web.xml")
|
webXml = file("WebContent/WEB-INF/weblogic-web.xml")ㅇ
|
||||||
exclude 'WEB-INF/web.xml'
|
exclude 'WEB-INF/web.xml'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// rootSpec.exclude '**/persistence.xml'
|
// rootSpec.exclude '**/persistence.xml'
|
||||||
exclude '**/context.xml'
|
exclude '**/context.xml'
|
||||||
exclude '**/context-*.xml'
|
exclude '**/context-*.xml'
|
||||||
archiveFileName = "eapim-admin.war"
|
archiveFileName = "eapim-admin.war"
|
||||||
duplicatesStrategy = DuplicatesStrategy.WARN
|
duplicatesStrategy = DuplicatesStrategy.WARN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
options.encoding = 'UTF-8'
|
options.encoding = 'UTF-8'
|
||||||
options.compilerArgs += ['-parameters', "-Xlint:unchecked", "-Xlint:deprecation"]
|
options.compilerArgs += ['-parameters', "-Xlint:unchecked", "-Xlint:deprecation"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
|
||||||
annotationProcessor "org.projectlombok:lombok:1.18.28", "org.projectlombok:lombok-mapstruct-binding:0.2.0", "org.mapstruct:mapstruct-processor:1.5.5.Final"
|
annotationProcessor "org.projectlombok:lombok:1.18.28",
|
||||||
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jpa", "jakarta.persistence:jakarta.persistence-api:2.2.3", "jakarta.annotation:jakarta.annotation-api:1.3.5"
|
"org.projectlombok:lombok-mapstruct-binding:0.2.0",
|
||||||
|
"org.mapstruct:mapstruct-processor:1.5.5.Final"
|
||||||
|
annotationProcessor "com.querydsl:querydsl-apt:${queryDslVersion}:jpa",
|
||||||
|
"jakarta.persistence:jakarta.persistence-api:2.2.3",
|
||||||
|
"jakarta.annotation:jakarta.annotation-api:1.3.5"
|
||||||
|
|
||||||
implementation project(':elink-online-core')
|
implementation project(':elink-online-core')
|
||||||
implementation project(':elink-online-transformer')
|
implementation project(':elink-online-transformer')
|
||||||
implementation project(':elink-online-common')
|
implementation project(':elink-online-common')
|
||||||
implementation project(':elink-online-emsclient')
|
implementation project(':elink-online-emsclient')
|
||||||
implementation project(':elink-portal-common')
|
implementation project(':elink-portal-common')
|
||||||
//implementation project(':kjb-safedb')
|
//implementation project(':kjb-safedb')
|
||||||
implementation project(":eapim-admin-djb")
|
implementation project(":eapim-admin-djb")
|
||||||
|
|
||||||
/* Custom Libs (damo-manager.jar 는 Tomcat lib 가 런타임 제공 → compileOnly, WAR 미포함) */
|
/* Custom Libs (damo-manager.jar 는 Tomcat lib 가 런타임 제공 → compileOnly, WAR 미포함) */
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'], exclude: ['damo-manager.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'], exclude: ['damo-manager.jar'])
|
||||||
compileOnly files('libs/damo-manager.jar')
|
compileOnly files('libs/damo-manager.jar')
|
||||||
|
|
||||||
//implementation "org.dom4j:dom4j:2.1.3"
|
//implementation "org.dom4j:dom4j:2.1.3"
|
||||||
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
||||||
|
|
||||||
implementation "commons-primitives:commons-primitives:1.0"
|
implementation "commons-primitives:commons-primitives:1.0"
|
||||||
@@ -117,10 +116,10 @@ dependencies {
|
|||||||
|
|
||||||
// https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api
|
// https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api
|
||||||
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
|
compileOnly group: 'javax.servlet', name: 'javax.servlet-api', version: '4.0.1'
|
||||||
|
|
||||||
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.1'
|
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.13.1'
|
||||||
//implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.13.1'
|
//implementation group: 'com.fasterxml.jackson.dataformat', name: 'jackson-dataformat-xml', version: '2.13.1'
|
||||||
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1'
|
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.1'
|
||||||
|
|
||||||
implementation "javax.jms:javax.jms-api:2.0"
|
implementation "javax.jms:javax.jms-api:2.0"
|
||||||
implementation "org.snmp4j:snmp4j:1.10.1"
|
implementation "org.snmp4j:snmp4j:1.10.1"
|
||||||
@@ -187,32 +186,32 @@ dependencies {
|
|||||||
implementation 'ch.qos.logback:logback-classic:1.2.10'
|
implementation 'ch.qos.logback:logback-classic:1.2.10'
|
||||||
implementation 'ch.qos.logback:logback-access:1.2.10'
|
implementation 'ch.qos.logback:logback-access:1.2.10'
|
||||||
implementation 'ch.qos.logback:logback-core:1.2.10'
|
implementation 'ch.qos.logback:logback-core:1.2.10'
|
||||||
|
|
||||||
implementation files("libs/eai-bap-client.jar")
|
|
||||||
|
|
||||||
compileOnly 'javax.xml.bind:jaxb-api:2.3.1'
|
|
||||||
|
|
||||||
//implementation 'org.postgresql:postgresql:42.2.23'
|
|
||||||
|
|
||||||
implementation 'backport-util-concurrent:backport-util-concurrent:3.0'
|
|
||||||
|
|
||||||
implementation ('software.amazon.awssdk:s3:2.20.142') {
|
|
||||||
exclude group: 'org.slf4j', module: 'slf4j-api'
|
|
||||||
exclude group: 'org.slf4j', module: 'logback-classic'
|
|
||||||
}
|
|
||||||
implementation 'software.amazon.awssdk:sso:2.20.142'
|
|
||||||
implementation 'software.amazon.awssdk:sts:2.20.142'
|
|
||||||
|
|
||||||
implementation group: 'commons-net', name: 'commons-net', version: '3.5'
|
implementation files("libs/eai-bap-client.jar")
|
||||||
|
|
||||||
// JDK 8 의 rt.jar 에는 org.w3c.dom.ElementTraversal 이 없어 xercesImpl 가 NCDFE 를 일으킴.
|
compileOnly 'javax.xml.bind:jaxb-api:2.3.1'
|
||||||
// xml-apis 1.4.01 에 그 클래스가 포함됨. 직접 의존성으로 묶어 WAR 에 패키징되도록 함.
|
|
||||||
implementation 'xml-apis:xml-apis:1.4.01'
|
|
||||||
|
|
||||||
testRuntimeOnly 'com.h2database:h2:2.1.214'
|
//implementation 'org.postgresql:postgresql:42.2.23'
|
||||||
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
|
||||||
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
implementation 'backport-util-concurrent:backport-util-concurrent:3.0'
|
||||||
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.15'
|
|
||||||
|
implementation ('software.amazon.awssdk:s3:2.20.142') {
|
||||||
|
exclude group: 'org.slf4j', module: 'slf4j-api'
|
||||||
|
exclude group: 'org.slf4j', module: 'logback-classic'
|
||||||
|
}
|
||||||
|
implementation 'software.amazon.awssdk:sso:2.20.142'
|
||||||
|
implementation 'software.amazon.awssdk:sts:2.20.142'
|
||||||
|
|
||||||
|
implementation group: 'commons-net', name: 'commons-net', version: '3.5'
|
||||||
|
|
||||||
|
// JDK 8 의 rt.jar 에는 org.w3c.dom.ElementTraversal 이 없어 xercesImpl 가 NCDFE 를 일으킴.
|
||||||
|
// xml-apis 1.4.01 에 그 클래스가 포함됨. 직접 의존성으로 묶어 WAR 에 패키징되도록 함.
|
||||||
|
implementation 'xml-apis:xml-apis:1.4.01'
|
||||||
|
|
||||||
|
testRuntimeOnly 'com.h2database:h2:2.1.214'
|
||||||
|
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
|
||||||
|
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
|
||||||
|
testImplementation 'org.springframework.boot:spring-boot-starter-test:2.6.15'
|
||||||
}
|
}
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@@ -220,9 +219,9 @@ test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
configurations.all {
|
configurations.all {
|
||||||
exclude group: 'log4j', module: 'log4j'
|
exclude group: 'log4j', module: 'log4j'
|
||||||
exclude group: 'org.apache.activemq'
|
exclude group: 'org.apache.activemq'
|
||||||
exclude group: 'org.codehaus.jackson'
|
exclude group: 'org.codehaus.jackson'
|
||||||
resolutionStrategy {
|
resolutionStrategy {
|
||||||
// 10 minute cache of dynamic version navigation
|
// 10 minute cache of dynamic version navigation
|
||||||
cacheDynamicVersionsFor 10, 'minutes'
|
cacheDynamicVersionsFor 10, 'minutes'
|
||||||
@@ -246,29 +245,25 @@ task settingEclipseEncoding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
task initDirs() {
|
task initDirs() {
|
||||||
file(generatedJavaDir).mkdirs()
|
file(generatedJavaDir).mkdirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
eclipse {
|
eclipse {
|
||||||
wtp {
|
wtp {
|
||||||
component {
|
component {
|
||||||
contextPath = 'monitoring'
|
contextPath = 'monitoring'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
synchronizationTasks settingEclipseEncoding, initDirs
|
synchronizationTasks settingEclipseEncoding, initDirs
|
||||||
jdt {
|
jdt {
|
||||||
apt {
|
|
||||||
// generated 된 패스 경로를 .setting/org.eclipse.jdt.apt.core.prefs 의 org.eclipse.jdt.apt.genSrcDir에 적용한다.
|
}
|
||||||
// project > properties > Java Compiler > Annoation Processing 화면에서 확인 가능하다.
|
project {
|
||||||
genSrcDir = file(generatedJavaDir)
|
if (!natures.contains('org.eclipse.buildship.core.gradleprojectnature')) {
|
||||||
}
|
natures.add('org.eclipse.buildship.core.gradleprojectnature')
|
||||||
}
|
buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
|
||||||
project {
|
}
|
||||||
if (!natures.contains('org.eclipse.buildship.core.gradleprojectnature')) {
|
}
|
||||||
natures.add('org.eclipse.buildship.core.gradleprojectnature')
|
|
||||||
buildCommand 'org.eclipse.buildship.core.gradleprojectbuilder'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType(JavaCompile) {
|
tasks.withType(JavaCompile) {
|
||||||
|
|||||||
@@ -87,8 +87,8 @@ dependencies {
|
|||||||
implementation project(":eapim-admin-djb")
|
implementation project(":eapim-admin-djb")
|
||||||
|
|
||||||
/* Custom Libs (damo-manager.jar 는 Tomcat lib 가 런타임 제공 → compileOnly, WAR 미포함) */
|
/* Custom Libs (damo-manager.jar 는 Tomcat lib 가 런타임 제공 → compileOnly, WAR 미포함) */
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar'], exclude: ['damo-manager.jar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar'], exclude: ['damo-manager.jar'])
|
||||||
compileOnly files('libs/damo-manager.jar')
|
compileOnly files('libs/damo-manager.jar')
|
||||||
|
|
||||||
//implementation "org.dom4j:dom4j:2.1.3"
|
//implementation "org.dom4j:dom4j:2.1.3"
|
||||||
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
//implementation "com.rabbitmq:amqp-client:3.6.6"
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.eactive.eai.rms.data.entity.onl.apim.apigroup;
|
|||||||
|
|
||||||
import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroup;
|
import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroup;
|
||||||
import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroupApi;
|
import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroupApi;
|
||||||
|
import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroupApiId;
|
||||||
import com.eactive.eai.data.entity.onl.apim.apigroup.QApiGroup;
|
import com.eactive.eai.data.entity.onl.apim.apigroup.QApiGroup;
|
||||||
import com.eactive.eai.data.entity.onl.apim.apigroup.QApiGroupApi;
|
import com.eactive.eai.data.entity.onl.apim.apigroup.QApiGroupApi;
|
||||||
import com.eactive.eai.data.jpa.AbstractDataService;
|
import com.eactive.eai.data.jpa.AbstractDataService;
|
||||||
@@ -75,4 +76,37 @@ public class ApiGroupService extends AbstractDataService<ApiGroup, String, ApiGr
|
|||||||
.where(qApiGroup.id.in(apiGroupIds))
|
.where(qApiGroup.id.in(apiGroupIds))
|
||||||
.fetch();
|
.fetch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** API 를 지정한 그룹 목록에만 소속시킨다(기존 소속 제거 후 재설정). */
|
||||||
|
public void setApiGroupsForApi(String apiId, List<String> groupIds) {
|
||||||
|
deleteApiGroupApiByApiId(apiId);
|
||||||
|
if (groupIds == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (String gid : groupIds) {
|
||||||
|
if (StringUtils.isBlank(gid)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
ApiGroup group = repository.findById(gid).orElse(null);
|
||||||
|
if (group == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Hibernate.initialize(group.getApiGroupApiList());
|
||||||
|
List<ApiGroupApi> list = group.getApiGroupApiList();
|
||||||
|
boolean exists = false;
|
||||||
|
for (ApiGroupApi a : list) {
|
||||||
|
if (a.getId() != null && apiId.equals(a.getId().getApiId())) {
|
||||||
|
exists = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!exists) {
|
||||||
|
ApiGroupApi a = new ApiGroupApi();
|
||||||
|
a.setId(new ApiGroupApiId(gid, apiId));
|
||||||
|
a.setDisplayOrder(list.size() + 1);
|
||||||
|
list.add(a);
|
||||||
|
repository.save(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ public interface PortalPropertyMapper extends GenericMapper<PropertyUI, PortalPr
|
|||||||
@Mapping(source = "prptyGroupName", target = "id.propertyGroupName")
|
@Mapping(source = "prptyGroupName", target = "id.propertyGroupName")
|
||||||
@Mapping(source = "prptyName", target = "id.propertyName")
|
@Mapping(source = "prptyName", target = "id.propertyName")
|
||||||
@Mapping(source = "prpty2Val", target = "propertyValue")
|
@Mapping(source = "prpty2Val", target = "propertyValue")
|
||||||
|
@Mapping(source = "prptyDesc", target = "propertyDesc")
|
||||||
@Override
|
@Override
|
||||||
PortalProperty toEntity(PropertyUI vo);
|
PortalProperty toEntity(PropertyUI vo);
|
||||||
|
|
||||||
@@ -21,6 +22,7 @@ public interface PortalPropertyMapper extends GenericMapper<PropertyUI, PortalPr
|
|||||||
@Mapping(source ="id.propertyGroupName", target = "prptyGroupName")
|
@Mapping(source ="id.propertyGroupName", target = "prptyGroupName")
|
||||||
@Mapping(source ="id.propertyName", target = "prptyName")
|
@Mapping(source ="id.propertyName", target = "prptyName")
|
||||||
@Mapping(source ="propertyValue", target = "prpty2Val")
|
@Mapping(source ="propertyValue", target = "prpty2Val")
|
||||||
|
@Mapping(source ="propertyDesc", target = "prptyDesc")
|
||||||
@InheritInverseConfiguration
|
@InheritInverseConfiguration
|
||||||
@Override
|
@Override
|
||||||
PropertyUI toVo(PortalProperty entity);
|
PropertyUI toVo(PortalProperty entity);
|
||||||
|
|||||||
@@ -15,4 +15,7 @@ public class PropertyUI {
|
|||||||
|
|
||||||
@JsonProperty("PRPTY2VAL")
|
@JsonProperty("PRPTY2VAL")
|
||||||
private String prpty2Val;
|
private String prpty2Val;
|
||||||
|
|
||||||
|
@JsonProperty("PRPTYDESC")
|
||||||
|
private String prptyDesc;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ public class ApiSpecController extends OnlBaseAnnotationController {
|
|||||||
return "/onl/transaction/apim/apiSpecManPopup";
|
return "/onl/transaction/apim/apiSpecManPopup";
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping(value = "/onl/transaction/apim/apiSpecManPopup.view", params = "cmd=POPUP_LIST")
|
@GetMapping(value = "/onl/transaction/apim/apiSpecMan.view", params = "cmd=POPUP_LIST")
|
||||||
public String detailOrgPopupView() {
|
public String detailOrgPopupView() {
|
||||||
return "/onl/transaction/apim/apiSpecManDisplayOrgPopup";
|
return "/onl/transaction/apim/apiSpecManDisplayOrgPopup";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,6 +29,8 @@ import com.eactive.eai.rms.onl.manage.rule.layout.ui.LayoutUI;
|
|||||||
import com.eactive.eai.rms.onl.transaction.apim.ui.ApiInterfaceUI;
|
import com.eactive.eai.rms.onl.transaction.apim.ui.ApiInterfaceUI;
|
||||||
import com.eactive.eai.rms.onl.transaction.apim.ui.ApiSpecInfoUI;
|
import com.eactive.eai.rms.onl.transaction.apim.ui.ApiSpecInfoUI;
|
||||||
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
import com.eactive.apim.portal.portalproperty.service.PortalPropertyService;
|
||||||
|
import com.eactive.eai.rms.data.entity.onl.apim.apigroup.ApiGroupService;
|
||||||
|
import com.eactive.eai.data.entity.onl.apim.apigroup.ApiGroup;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -61,19 +63,37 @@ public class DjbApiSpecController extends OnlBaseAnnotationController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PortalPropertyService portalPropertyService;
|
private PortalPropertyService portalPropertyService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ApiGroupService apiGroupService;
|
||||||
|
|
||||||
private final ObjectMapper objectMapper = new ObjectMapper();
|
private final ObjectMapper objectMapper = new ObjectMapper();
|
||||||
|
|
||||||
private static final String SWAGGER_GW_ADDRESS_DEFAULT = "http://127.0.0.1:39310";
|
// GW base URL 단일 기준 = 포탈 DjbTestbedGatewayProperty 의 djb.gateway.base-url (PTL_PROPERTY 그룹 'Portal').
|
||||||
|
// 별도 swagger.gw.address 프로퍼티는 두지 않는다.
|
||||||
|
private static final String GW_BASE_URL_KEY = "djb.gateway.base-url";
|
||||||
|
private static final String GW_BASE_URL_DEFAULT = "PortalMock";
|
||||||
|
// "PortalMock" 은 포탈이 요청 origin 으로 치환하는 sentinel 이라 admin 미리보기용 서버 주소로는 부적합 → 대체값 사용.
|
||||||
|
private static final String GW_PREVIEW_FALLBACK = "http://127.0.0.1:39310";
|
||||||
|
|
||||||
// ── 진입 ────────────────────────────────────────────────
|
// ── 진입 ────────────────────────────────────────────────
|
||||||
@GetMapping(value = "/onl/transaction/apim/djbApiSpecMan.view", params = "cmd=DETAIL")
|
@GetMapping(value = "/onl/transaction/apim/djbApiSpecMan.view", params = "cmd=DETAIL")
|
||||||
public String viewDetail(Model model) {
|
public String viewDetail(Model model) {
|
||||||
// GW 주소(swagger.gw.address, PTL_PROPERTY 그룹 'Portal') — 없으면 기본값으로 생성
|
// GW base URL (djb.gateway.base-url, 그룹 'Portal') — 없으면 기본값으로 생성. DjbTestbedGatewayProperty 와 동일 키.
|
||||||
model.addAttribute("gwAddress",
|
String gw = portalPropertyService.getOrCreateProperty(
|
||||||
portalPropertyService.getOrCreateProperty("Portal", "swagger.gw.address", SWAGGER_GW_ADDRESS_DEFAULT, "Swagger GW 주소"));
|
"Portal", GW_BASE_URL_KEY, GW_BASE_URL_DEFAULT, "GW base URL (테스트베드 공통)");
|
||||||
|
if (StringUtils.isBlank(gw) || GW_BASE_URL_DEFAULT.equalsIgnoreCase(gw.trim())) {
|
||||||
|
gw = GW_PREVIEW_FALLBACK; // PortalMock → admin 미리보기용 구체 주소로 대체
|
||||||
|
}
|
||||||
|
model.addAttribute("gwAddress", gw.trim());
|
||||||
return "/onl/transaction/apim/djbApiSpecManPopup";
|
return "/onl/transaction/apim/djbApiSpecManPopup";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// API 그룹 선택 팝업(iframe 모달 대상). 그룹 목록 그리드는 apiGroupMan.json?cmd=LIST 재사용.
|
||||||
|
@GetMapping(value = "/onl/transaction/apim/djbApiSpecMan.view", params = "cmd=GROUP_POPUP")
|
||||||
|
public String viewGroupPopup() {
|
||||||
|
return "/onl/transaction/apim/djbApiGroupPopup";
|
||||||
|
}
|
||||||
|
|
||||||
// ── 조회: 저장 spec 우선 + authtype securityScheme 주입 ──
|
// ── 조회: 저장 spec 우선 + authtype securityScheme 주입 ──
|
||||||
@PostMapping(value = "/onl/transaction/apim/djbApiSpecMan.json", params = "cmd=DETAIL_SPEC")
|
@PostMapping(value = "/onl/transaction/apim/djbApiSpecMan.json", params = "cmd=DETAIL_SPEC")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
@@ -106,6 +126,19 @@ public class DjbApiSpecController extends OnlBaseAnnotationController {
|
|||||||
result.put("testbedSpec", enriched);
|
result.put("testbedSpec", enriched);
|
||||||
result.put("source", source);
|
result.put("source", source);
|
||||||
result.put("authType", authtype == null ? "" : authtype);
|
result.put("authType", authtype == null ? "" : authtype);
|
||||||
|
// API 그룹 소속(조인테이블 ApiGroupApi) — 저장 여부와 무관하게 현재 소속 반환
|
||||||
|
try {
|
||||||
|
ArrayNode groups = objectMapper.createArrayNode();
|
||||||
|
for (ApiGroup g : apiGroupService.findByApiId(eaiSvcName)) {
|
||||||
|
ObjectNode gn = objectMapper.createObjectNode();
|
||||||
|
gn.put("id", g.getId());
|
||||||
|
gn.put("groupName", g.getGroupName());
|
||||||
|
groups.add(gn);
|
||||||
|
}
|
||||||
|
result.put("apiGroups", objectMapper.writeValueAsString(groups));
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("API 그룹 조회 실패: " + eaiSvcName, e);
|
||||||
|
}
|
||||||
// 저장본이면 폼 복원용 기본정보/공개설정도 함께 반환
|
// 저장본이면 폼 복원용 기본정보/공개설정도 함께 반환
|
||||||
if (saved != null) {
|
if (saved != null) {
|
||||||
putIfNotNull(result, "apiName", saved.getApiName());
|
putIfNotNull(result, "apiName", saved.getApiName());
|
||||||
@@ -124,13 +157,15 @@ public class DjbApiSpecController extends OnlBaseAnnotationController {
|
|||||||
putIfNotNull(result, "displayRoleCode", saved.getDisplayRoleCode());
|
putIfNotNull(result, "displayRoleCode", saved.getDisplayRoleCode());
|
||||||
putIfNotNull(result, "displayOrg", saved.getDisplayOrg());
|
putIfNotNull(result, "displayOrg", saved.getDisplayOrg());
|
||||||
}
|
}
|
||||||
|
// 예제/설명자료(요청·응답 메시지 스펙 HTML)는 프론트에서 스키마 기준으로 생성 → 자동생성/재생성 결과 일치.
|
||||||
|
// 저장본이면 위 saved 블록에서 저장값을 이미 반환.
|
||||||
return ResponseEntity.ok(result);
|
return ResponseEntity.ok(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── 저장: 마법사 폼 → ApiSpecInfoUI → apiSpecManService.save (기존 재사용) ──
|
// ── 저장: 마법사 폼 → ApiSpecInfoUI → apiSpecManService.save (기존 재사용) ──
|
||||||
@PostMapping(value = "/onl/transaction/apim/djbApiSpecMan.json", params = "cmd=SAVE")
|
@PostMapping(value = "/onl/transaction/apim/djbApiSpecMan.json", params = "cmd=SAVE")
|
||||||
@ResponseBody
|
@ResponseBody
|
||||||
public ResponseEntity<Map<String, String>> save(ApiSpecInfoUI apiSpecInfoUI) {
|
public ResponseEntity<Map<String, String>> save(ApiSpecInfoUI apiSpecInfoUI, String apiGroupIds) {
|
||||||
Map<String, String> result = new HashMap<>();
|
Map<String, String> result = new HashMap<>();
|
||||||
if (apiSpecInfoUI == null || StringUtils.isBlank(apiSpecInfoUI.getApiId())) {
|
if (apiSpecInfoUI == null || StringUtils.isBlank(apiSpecInfoUI.getApiId())) {
|
||||||
result.put("status", "fail");
|
result.put("status", "fail");
|
||||||
@@ -153,6 +188,21 @@ public class DjbApiSpecController extends OnlBaseAnnotationController {
|
|||||||
|
|
||||||
apiSpecManService.save(apiSpecInfoUI);
|
apiSpecManService.save(apiSpecInfoUI);
|
||||||
|
|
||||||
|
// API 그룹 소속(조인테이블) 동기화 — apiGroupIds(CSV) 로 재설정
|
||||||
|
try {
|
||||||
|
java.util.List<String> gids = new ArrayList<>();
|
||||||
|
if (StringUtils.isNotBlank(apiGroupIds)) {
|
||||||
|
for (String g : apiGroupIds.split(",")) {
|
||||||
|
if (StringUtils.isNotBlank(g)) {
|
||||||
|
gids.add(g.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
apiGroupService.setApiGroupsForApi(apiSpecInfoUI.getApiId(), gids);
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.warn("API 그룹 동기화 실패: " + apiSpecInfoUI.getApiId(), e);
|
||||||
|
}
|
||||||
|
|
||||||
result.put("status", "success");
|
result.put("status", "success");
|
||||||
result.put("apiId", apiSpecInfoUI.getApiId());
|
result.put("apiId", apiSpecInfoUI.getApiId());
|
||||||
return ResponseEntity.ok(result);
|
return ResponseEntity.ok(result);
|
||||||
@@ -272,7 +322,15 @@ public class DjbApiSpecController extends OnlBaseAnnotationController {
|
|||||||
tags.add(tag);
|
tags.add(tag);
|
||||||
root.set("tags", tags);
|
root.set("tags", tags);
|
||||||
|
|
||||||
// servers 는 유지(상대 path). 최종 서버 base 는 프론트에서 응답유형(gw/mock/기본)에 따라 선택.
|
// 어댑터경로(servers[0].url = getHttpAdapterInfo urlPath)를 path 앞에 baking 하고 servers 제거.
|
||||||
|
// 호스트(gw=djb.gateway.base-url / mock=Mock URL / sample=없음)는 프론트가 응답유형에 따라 서버로 붙인다.
|
||||||
|
String adapterPath = "";
|
||||||
|
JsonNode serversNode = root.get("servers");
|
||||||
|
if (serversNode != null && serversNode.isArray() && serversNode.size() > 0 && serversNode.get(0).get("url") != null) {
|
||||||
|
adapterPath = serversNode.get(0).get("url").asText("");
|
||||||
|
}
|
||||||
|
root.remove("servers");
|
||||||
|
|
||||||
JsonNode pathsNode = root.get("paths");
|
JsonNode pathsNode = root.get("paths");
|
||||||
if (pathsNode != null && pathsNode.isObject()) {
|
if (pathsNode != null && pathsNode.isObject()) {
|
||||||
ObjectNode paths = (ObjectNode) pathsNode;
|
ObjectNode paths = (ObjectNode) pathsNode;
|
||||||
@@ -298,13 +356,18 @@ public class DjbApiSpecController extends OnlBaseAnnotationController {
|
|||||||
ArrayNode opTags = objectMapper.createArrayNode();
|
ArrayNode opTags = objectMapper.createArrayNode();
|
||||||
opTags.add(tagName);
|
opTags.add(tagName);
|
||||||
op.set("tags", opTags);
|
op.set("tags", opTags);
|
||||||
setContentExample(op, reqSample);
|
// 예제(요청/응답 본문)는 프론트에서 스키마 기준으로 생성 → 자동생성/재생성 결과 일치. 여기선 임베드하지 않음.
|
||||||
setResponseExample(op, "200", resSample);
|
|
||||||
markGwOnOperation(op);
|
markGwOnOperation(op);
|
||||||
addResponseHeader(op, "200", "Content-Type", contentType);
|
addResponseHeader(op, "200", "Content-Type", contentType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
String newKey = adapterPath.isEmpty() ? pk
|
||||||
|
: (adapterPath.replaceAll("/+$", "") + (pk.startsWith("/") ? "" : "/") + pk);
|
||||||
|
if (!newKey.equals(pk)) {
|
||||||
|
paths.set(newKey, pathItem);
|
||||||
|
paths.remove(pk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return objectMapper.writeValueAsString(root);
|
return objectMapper.writeValueAsString(root);
|
||||||
|
|||||||
Reference in New Issue
Block a user