Merge branch 'features/ui-improvements' into jenkins_with_weblogic

This commit is contained in:
daekuk
2025-12-22 15:11:50 +09:00
9 changed files with 291 additions and 24 deletions
@@ -18,6 +18,8 @@
<script language="javascript" >
var url = '<c:url value="/onl/admin/authserver/scopeMan.json" />';
var url_view = '<c:url value="/onl/admin/authserver/scopeMan.view" />';
var api_url_view = '<c:url value="/onl/apim/apigroup/apiGroupMan.view" />';
var mapping_url = '<c:url value="/onl/admin/authserver/apiScopeMan.json" />';
var isDetail = false;
function isValid(){
@@ -58,8 +60,106 @@ function detail(key){
});
}
function init(key,callback){
function mappingInfo(key){
if (!isDetail) return;
$.ajax({
type : "POST",
url: mapping_url,
dataType: "json",
data: {cmd: 'LIST', searchScopeId : key},
success: function(json){
var mappingData = json.rows;
if (mappingData && mappingData.length > 0) {
$.each(mappingData, function(idx, row) {
row.apiId = row.apiId;
row.apiDesc = row.apiDesc;
row.apiFullPath = row.APIFULLPATH;
row.bzwksvckeyname = row.BZWKSVCKEYNAME;
});
}
var $grid = $("#selectedApiGrid");
$grid.jqGrid('clearGridData');
$grid.jqGrid('setGridParam', {
datatype: 'local',
data: mappingData
}).trigger("reloadGrid");
},
error: function(e){
alert("데이터 조회 중 오류 발생: " + e.responseText);
}
});
}
function init(key, callback){
detail(key);
var selectedApiGrid = $("#selectedApiGrid");
selectedApiGrid.jqGrid({
datatype: "local",
colNames: ['API ID', 'API 명', 'SCOPE ID', 'SCOPE 명', 'API FULL PATH', 'API 정보'],
colModel: [
{name: 'apiId', index: 'apiId', width: 100, align: 'center'},
{name: 'apiDesc', index: 'apiDesc', width: 100, align: 'center'},
{name: 'SCOPEID', index: 'SCOPEID', width: 100, align: 'center'},
{name: 'SCOPENAME', index: 'SCOPENAME', width: 100, align: 'center'},
{name: 'APIFULLPATH', index: 'APIFULLPATH', width: 100, align: 'left'},
{name: 'BZWKSVCKEYNAME', index: 'BZWKSVCKEYNAME', width: 100, align: 'left'}
],
rowNum: 30,
rowList: [10, 20, 30],
pager: '#selectedApiGridPager',
sortname: 'apiId',
viewrecords: true,
sortorder: "asc",
caption: "선택된 API",
height: 200,
autowidth: true,
multiselect: true,
ondblClickRow: function (rowid, status, e) {
// selectedApiGrid.jqGrid('delRowData', rowid);
}
});
mappingInfo(key); // SCOPE ID의 매핑정보 (AJAX 호출)
// callback이 함수인지 확인 후 호출 (안전장치)
if (typeof callback === 'function') {
callback(key);
}
}
function saveApiGridData(scopeId, returnUrl) {
var postData = [];
var rows = $("#selectedApiGrid").jqGrid('getRowData');
$.each(rows, function(index, item) {
item.scopeId = scopeId;
});
postData.push({
name: "apiList",
value: JSON.stringify(rows)
});
postData.push({ name: "cmd" , value:"INSERT_APILIST" });
postData.push({ name: "scopeId" , value:scopeId });
$.ajax({
type : "POST",
url:mapping_url,
data: postData,
success:function(args){
alert("저장 되었습니다.");
goNav(returnUrl);//LIST로 이동
},
error:function(e){
alert(e.responseText);
}
});
}
$(document).ready(function() {
@@ -85,8 +185,10 @@ $(document).ready(function() {
url:url,
data:postData,
success:function(args){
alert("저장 되었습니다.");
goNav(returnUrl);//LIST로 이동
alert("SCOPE 정보가 저장 되었습니다. 이어서 API 리스트를 저장합니다.");
saveApiGridData(key, returnUrl); // API LIST 저장.
},
error:function(e){
alert(e.responseText);
@@ -121,8 +223,65 @@ $(document).ready(function() {
goNav(returnUrl);//LIST로 이동
});
$("#btn_popup_api").click(function () {
const args = {};
const url2 = api_url_view += "?cmd=POPUP";
showModal(url2, args, 1280, 860, function () {
const popupFrame = args.self.frames[0];
const returnValue = popupFrame.returnValue;
const frameElement = popupFrame.frameElement
const parentElement = frameElement.parentNode; // 부모 노드를 가져옴
if (parentElement) { // 부모 노드가 존재하는지 확인
parentElement.removeChild(frameElement);
}
var rows = $("#selectedApiGrid").jqGrid('getRowData');
var existingApiIds = new Set(rows.map(function(row) {
return String(row.apiId);
}));
var newItems = Array.isArray(returnValue) ? returnValue : [returnValue];
var ids = $("#selectedApiGrid").jqGrid('getDataIDs');
var currentIdSeq = ids.length > 0 ? Math.max(...ids.map(Number)) : 0;
$.each(newItems, function(index, item) {
var checkId = String(item.apiId);
if (!existingApiIds.has(checkId)) {
currentIdSeq++;
$("#selectedApiGrid").jqGrid('addRowData', currentIdSeq, item, "last");
existingApiIds.add(checkId);
} else {
//console.log("중복 제외됨: " + item.apiId);
}
});
alert("중복건 수를 제외한 API가 추가되었습니다.");
});
});
$("#btn_delete_api").click(function () {
var grid = $("#selectedApiGrid");
var selectedRowIds = grid.jqGrid('getGridParam', 'selarrrow'); // 선택된 행의 ID 배열을 가져옴
if (selectedRowIds.length > 0) {
// 선택된 행의 ID를 복사한 배열을 사용
var idsToDelete = selectedRowIds.slice();
for (var i = 0; i < idsToDelete.length; i++) {
grid.jqGrid('delRowData', idsToDelete[i]); // 선택된 각 행을 삭제
}
} else {
alert("Please select at least one row to delete.");
}
});
buttonControl(isDetail);
titleControl(isDetail);
});
</script>
@@ -161,7 +320,25 @@ $(document).ready(function() {
</tr>
</table>
</form>
<!-- API ID / API Full Path 추가 -->
<div style="font-size:0;">
<div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 5px ">
<div class="table_row_title" style="margin-bottom: 0px">API</div>
<div style="text-align: end;">
<button type="button" class="cssbtn" id="btn_delete_api" level="W" status="DETAIL,NEW">
<i class="material-icons">delete</i> <%= localeMessage.getString("button.delete") %>
</button>
<button type="button" class="cssbtn" id="btn_popup_api" level="W" status="DETAIL,NEW">
<i class="material-icons">add</i> API <%= localeMessage.getString("button.add") %>
</button>
</div>
</div>
<div style="display:inline-block; width:calc(100%); vertical-align:top;">
<div id="selectedApiList" style="margin-top:10px;">
<table id="selectedApiGrid"></table>
</div>
</div>
</div>
</div><!-- end content_middle -->
</div><!-- end right_box -->
</body>
@@ -27,9 +27,11 @@
for(var i = 0; i < selectedRowIds.length; i++) {
var rowData = grid.jqGrid('getRowData', selectedRowIds[i]);
selectedData.push({
bizCode: rowData.eaiBzwkDstcd,
bizCode: rowData.eaiBzwkDstcd, // CLINET
apiId: rowData.eaiSvcName,
apiDesc: rowData.eaiSvcDesc
apiDesc: rowData.eaiSvcDesc, // SCOPE-API
APIFULLPATH: rowData.apiFullPath,
BZWKSVCKEYNAME: rowData.bzwksvckeyname
});
}
@@ -108,6 +110,7 @@
'API ID',
'API 명',
'API FULL PATH',
'업무서비스명',
'요청',
'응답',
'작성자',
@@ -117,12 +120,13 @@
colModel : [ { name : 'eaiBzwkDstcd' , align : 'center' , width:'40', sortable:false},
{ name : 'eaiSvcName' , align : 'left' , width:'100'},
{ name : 'eaiSvcDesc' , align : 'left' },
{ name : 'apiFullPath' , align : 'left' , width:'180'},
{ name : 'apiFullPath' , align : 'left' , width:'100'},
{ name : 'bzwksvckeyname' , align : 'left' , width:'100', hidden: true},
{ name : 'fromAdapter' , align : 'center' , width:'40', formatter:adapterNameShortFormatter },
{ name : 'toAdapter' , align : 'center' , width:'40', formatter:adapterNameShortFormatter },
{ name : 'author' , align : 'center' , width:'60' },
{ name : 'simYn' , align : 'center' , width:'40' },
{ name : 'syncAsyncType' , align : 'center' , width:'40', hidden: true },
{ name : 'syncAsyncType' , align : 'center' , width:'40', hidden: true},
],
jsonReader : {
repeatitems : false
@@ -9,6 +9,9 @@ import lombok.Data;
@AllArgsConstructor
public class ApiScopeDto {
@JsonProperty("EAISVCNAME")
private String eaiSvcName;
@JsonProperty("EAISVCDESC")
private String eaiSvcDesc;
@@ -20,5 +23,8 @@ public class ApiScopeDto {
@JsonProperty("SCOPENAME")
private String scopeName;
@JsonProperty("APIFULLPATH")
private String apiFullPath;
}
@@ -59,6 +59,8 @@ public class EAIMessageService extends AbstractDataService<EAIMessageEntity, Str
, qServiceMessageEntity.psvsysadptrbzwkgroupname
, qRouting.nonmotivrouturiname
, qStdInfo.apifullpath
, qStdInfo.bzwksvckeyname
)
.limit(pageable.getPageSize())
.offset(pageable.getOffset())
@@ -111,6 +113,7 @@ public class EAIMessageService extends AbstractDataService<EAIMessageEntity, Str
, qServiceMessageEntity.psvintfacdsticname
, qRouting.nonmotivrouturiname
, qStdInfo.apifullpath
, qStdInfo.bzwksvckeyname
)
.from(qeaiMessageEntity)
.join(qRouting)
@@ -290,10 +293,14 @@ public class EAIMessageService extends AbstractDataService<EAIMessageEntity, Str
List<ApiScopeDto> result = getJPAQueryFactory()
.select(Projections.constructor(ApiScopeDto.class ,
qEaiMessageEntity.eaisvcname ,
qEaiMessageEntity.eaisvcdesc ,
qScopeEntity.id.scopeid ,
qScopeEntity.id.bzwksvckeyname ,
qScopeInfo.scopeName ))
qScopeInfo.scopeName ,
qStandardMessageInfo.apifullpath
)
)
.from(qEaiMessageEntity)
.join(qStandardMessageInfo)
.on(qEaiMessageEntity.eaisvcname.eq(qStandardMessageInfo.eaisvcname))
@@ -313,19 +320,20 @@ public class EAIMessageService extends AbstractDataService<EAIMessageEntity, Str
private BooleanExpression booleanPredicate(QEAIMessageEntity qEaiMessageEntity, QScopeEntity qScopeEntity,
QScopeInfo qScopeInfo, ApiScopeSearch apiScopeSearch) {
BooleanExpression predicate = qEaiMessageEntity.eaisvcdesc.containsIgnoreCase(apiScopeSearch.getSearchEaiSvcDesc());
BooleanExpression predicate = qScopeEntity.id.scopeid.containsIgnoreCase(apiScopeSearch.getSearchScopeId());
// BooleanExpression predicate = qEaiMessageEntity.eaisvcdesc.containsIgnoreCase(apiScopeSearch.getSearchEaiSvcDesc());
if(StringUtils.isNotBlank(apiScopeSearch.getSearchBzwkSvcKeyName())) {
predicate = predicate.and(qScopeEntity.id.bzwksvckeyname.containsIgnoreCase(apiScopeSearch.getSearchBzwkSvcKeyName()));
}
if(StringUtils.isNotBlank(apiScopeSearch.getSearchScopeId())) {
predicate = predicate.and(qScopeEntity.id.scopeid.containsIgnoreCase(apiScopeSearch.getSearchScopeId()));
}
if(StringUtils.isNotBlank(apiScopeSearch.getSearchScopeName())) {
predicate = predicate.and(qScopeInfo.scopeName.containsIgnoreCase(apiScopeSearch.getSearchScopeName()));
}
// if(StringUtils.isNotBlank(apiScopeSearch.getSearchBzwkSvcKeyName())) {
// predicate = predicate.and(qScopeEntity.id.bzwksvckeyname.containsIgnoreCase(apiScopeSearch.getSearchBzwkSvcKeyName()));
// }
//
// if(StringUtils.isNotBlank(apiScopeSearch.getSearchScopeId())) {
// predicate = predicate.and(qScopeEntity.id.scopeid.containsIgnoreCase(apiScopeSearch.getSearchScopeId()));
// }
//
// if(StringUtils.isNotBlank(apiScopeSearch.getSearchScopeName())) {
// predicate = predicate.and(qScopeInfo.scopeName.containsIgnoreCase(apiScopeSearch.getSearchScopeName()));
// }
return predicate;
}
@@ -4,6 +4,15 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.eactive.eai.agent.authserver.ReloadApiScopeCommand;
import com.eactive.eai.agent.command.CommonCommand;
import com.eactive.eai.rms.common.base.OnlBaseAnnotationController;
import com.eactive.eai.rms.common.vo.GridResponse;
import com.eactive.eai.rms.data.entity.onl.eaimsg.ApiScopeSearch;
import com.eactive.eai.rms.onl.common.exception.BizException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -11,6 +20,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import com.eactive.eai.agent.authserver.ReloadApiScopeCommand;
import com.eactive.eai.agent.command.CommonCommand;
@@ -53,6 +63,25 @@ public class ApiScopeController extends OnlBaseAnnotationController {
return ResponseEntity.ok().build();
}
@PostMapping(value = "/onl/admin/authserver/apiScopeMan.json", params = "cmd=INSERT_APILIST")
public ResponseEntity<Void> insertApiScopeList(@RequestParam("apiList") String apiListJson, @RequestParam("scopeId") String scopeId) {
ObjectMapper mapper = new ObjectMapper();
List<ApiScopeUI> apiScopeList = null;
try {
apiScopeList = mapper.readValue(apiListJson, new TypeReference<List<ApiScopeUI>>(){});
} catch (Exception e) {
throw new BizException("데이터 변환 중 오류가 발생했습니다.");
}
apiScopeManService.insertApiScopeRelationList(apiScopeList, scopeId);
return ResponseEntity.ok().build();
}
@PostMapping(value = "/onl/admin/authserver/apiScopeMan.json", params = "cmd=DELETE")
public ResponseEntity<Void> deleteApiScope(ApiScopeUI apiScopeUI) {
apiScopeManService.deleteApiScopeRelation(apiScopeUI);
@@ -11,6 +11,8 @@ import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.eactive.eai.agent.authserver.ReloadApiScopeCommand;
import com.eactive.eai.agent.command.CommonCommand;
import com.eactive.eai.rms.common.base.OnlBaseService;
import com.eactive.eai.rms.common.spring.LocaleMessage;
import com.eactive.eai.rms.data.entity.onl.authserver.ScopeEntityService;
@@ -56,10 +58,12 @@ public class ApiScopeManService extends OnlBaseService {
private ApiScopeUI convertToApiScopeUI(ApiScopeDto dto) {
ApiScopeUI apiScopeUI = new ApiScopeUI();
apiScopeUI.setEaiSvcDesc(dto.getEaiSvcDesc());
apiScopeUI.setApiDesc(dto.getEaiSvcDesc());
apiScopeUI.setScopeId(dto.getScopeId());
apiScopeUI.setBzwkSvcKeyName(dto.getBzwkSvcKeyName());
apiScopeUI.setScopeName(dto.getScopeName());
apiScopeUI.setApiFullPath(dto.getApiFullPath());
apiScopeUI.setApiId(dto.getEaiSvcName());
return apiScopeUI;
}
@@ -72,6 +76,32 @@ public class ApiScopeManService extends OnlBaseService {
scopeEntityService.save(apiScopeUIMapper.toEntity(apiScopeUI));
}
public void insertApiScopeRelationList(List<ApiScopeUI> apiScopeList, String scopeId) {
// ScopeId 기준 전체 삭제 후 LIST 기준으로 저장.
if(scopeId == null || scopeId.isEmpty()) {
throw new BizException("ScopeId 가 존재하지 않습니다.");
}
scopeEntityService.deleteByIdScopeId(scopeId);
if(apiScopeList == null || apiScopeList.isEmpty()) {
return;
}
for (ApiScopeUI ui : apiScopeList) {
ui.setScopeId(scopeId);
scopeEntityService.save(apiScopeUIMapper.toEntity(ui));
CommonCommand.builder()
.name(CommonCommand.RELOAD_API_SCOPE_COMMAND)
.args(new String[] {ReloadApiScopeCommand.COMMAND_TYPE_API_SCOPE,
ui.getBzwkSvcKeyName(), ui.getScopeId()})
.build()
.broadcast(agentUtilService);
}
}
public void deleteApiScopeRelation(ApiScopeUI apiScopeUI) {
scopeEntityService.deleteById(apiScopeUIMapper.toId(apiScopeUI));
}
@@ -1,10 +1,14 @@
package com.eactive.eai.rms.onl.manage.authserver.scope;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor // jackson 사용을 위해 추가.
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiScopeUI {
@JsonProperty("SCOPEID")
@@ -16,7 +20,13 @@ public class ApiScopeUI {
@JsonProperty("SCOPENAME")
private String scopeName;
@JsonProperty("EAISVCDESC")
private String eaiSvcDesc;
@JsonProperty("apiDesc")
private String apiDesc;
@JsonProperty("APIFULLPATH")
private String apiFullPath;
@JsonProperty("apiId")
private String apiId;
}
@@ -139,6 +139,7 @@ public class ApiInterfaceService extends OnlBaseService {
EAIMessageEntity eaiMessageEntity = tuple.get(QEAIMessageEntity.eAIMessageEntity);
String apiFullPath = tuple.get(QStandardMessageInfo.standardMessageInfo.apifullpath);
String bzwksvckeyname = tuple.get(QStandardMessageInfo.standardMessageInfo.bzwksvckeyname);
ApiInterfaceUI apiInterfaceUI;
if (eaiMessageEntity.getServiceMessages() != null && eaiMessageEntity.getServiceMessages().size() > 0) {
@@ -148,6 +149,7 @@ public class ApiInterfaceService extends OnlBaseService {
}
apiInterfaceUI.setApiFullPath(apiFullPath);
apiInterfaceUI.setBzwksvckeyname(bzwksvckeyname);
return apiInterfaceUI;
});
@@ -51,6 +51,7 @@ public class ApiInterfaceUI {
private List<StdMessageItemUI> inboundResponseStandardMessageItems ;
private String apiFullPath;
private String bzwksvckeyname;
//ASYNC-SYNC 용
private String inboundResponseHttpMethod;