inflow group 추가

This commit is contained in:
daekuk
2025-12-11 10:04:25 +09:00
parent 22fca42329
commit 27fac38c44
10 changed files with 1862 additions and 0 deletions
@@ -0,0 +1,25 @@
package com.eactive.eai.rms.data.entity.onl.inflow;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import com.eactive.eai.data.entity.onl.inflow.InflowControlGroupMapping;
import com.eactive.eai.data.jpa.BaseRepository;
public interface InflowControlGroupMappingRepository extends BaseRepository<InflowControlGroupMapping, String> {
List<InflowControlGroupMapping> findByGroupId(String groupId);
@Modifying
@Query("DELETE FROM InflowControlGroupMapping m WHERE m.groupId = :groupId")
void deleteByGroupId(@Param("groupId") String groupId);
/**
* 인터페이스 ID로 매핑 조회 (중복 체크용)
*/
Optional<InflowControlGroupMapping> findByInterfaceId(String interfaceId);
}
@@ -0,0 +1,8 @@
package com.eactive.eai.rms.data.entity.onl.inflow;
import com.eactive.eai.data.entity.onl.inflow.InflowControlGroup;
import com.eactive.eai.data.jpa.BaseRepository;
public interface InflowControlGroupRepository extends BaseRepository<InflowControlGroup, String> {
}
@@ -0,0 +1,185 @@
package com.eactive.eai.rms.onl.manage.inflow.group;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
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.vo.GridResponse;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
@Controller
public class InflowGroupControlManController extends OnlBaseAnnotationController {
@Autowired
private InflowGroupControlManService service;
@Autowired
private ComboService comboService;
private ObjectMapper objectMapper = new ObjectMapper();
// ========== View Mappings ==========
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.view")
public String viewList() {
return "/onl/admin/inflow/inflowGroupControlMan";
}
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.view", params = "cmd=DETAIL")
public String viewDetail() {
return "/onl/admin/inflow/inflowGroupControlManDetail";
}
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.view", params = "cmd=INTERFACE_POPUP")
public String viewInterfacePopup() {
return "/onl/admin/inflow/inflowGroupInterfacePopup";
}
// ========== JSON API Mappings ==========
/**
* 그룹 목록 조회
*/
@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);
return ResponseEntity.ok(new GridResponse<>(uiPage));
}
/**
* 그룹 상세 조회
*/
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=DETAIL")
public ResponseEntity<InflowGroupControlManUI> selectDetail(HttpServletRequest request,
HttpServletResponse response, String groupId) {
InflowGroupControlManUI ui = service.selectGroupDetail(groupId);
return ResponseEntity.ok(ui);
}
/**
* 그룹 저장 (INSERT)
*/
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=INSERT")
public String insert(HttpServletRequest request, HttpServletResponse response, InflowGroupControlManUI ui,
@RequestParam(value = "interfaceListJson", required = false) String interfaceListJson) throws Exception {
parseInterfaceList(ui, interfaceListJson);
String modifiedBy = getSessionUserId(request);
service.mergeGroup(ui, modifiedBy);
// Agent Command 전송
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.ReloadInflowGroupControlCommand",
ui.getGroupId());
agentUtilService.broadcast(command);
return null;
}
/**
* 그룹 저장 (UPDATE)
*/
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=UPDATE")
public String update(HttpServletRequest request, HttpServletResponse response, InflowGroupControlManUI ui,
@RequestParam(value = "interfaceListJson", required = false) String interfaceListJson) throws Exception {
parseInterfaceList(ui, interfaceListJson);
String modifiedBy = getSessionUserId(request);
service.mergeGroup(ui, modifiedBy);
// Agent Command 전송
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.ReloadInflowGroupControlCommand",
ui.getGroupId());
agentUtilService.broadcast(command);
return null;
}
/**
* 그룹 삭제
*/
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=DELETE")
public String delete(HttpServletRequest request, HttpServletResponse response, String groupId) throws Exception {
service.deleteGroup(groupId);
// Agent Command 전송
CommonCommand command = new CommonCommand("com.eactive.eai.agent.inflow.RemoveInflowGroupControlCommand",
groupId);
agentUtilService.broadcast(command);
return null;
}
/**
* 콤보박스 초기화 데이터
*/
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=LIST_INIT_COMBO")
public ModelAndView initCombo(HttpServletRequest request, HttpServletResponse response) {
List<ComboVo> useYnRows = comboService.getFromCode("USE_YN");
List<ComboVo> timeUnitRows = comboService.getFromCode("INFLOW_CTRL_TIME_UNIT");
Map<String, List<ComboVo>> resultMap = new HashMap<>();
resultMap.put("useYnRows", useYnRows);
resultMap.put("timeUnitRows", timeUnitRows);
return new ModelAndView("jsonView", resultMap);
}
/**
* 인터페이스 목록 조회 (팝업용)
*/
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=INTERFACE_LIST")
public ResponseEntity<GridResponse<InflowGroupMappingUI>> selectInterfaceList(HttpServletRequest request,
Pageable pageVo, String searchName) {
Page<InflowGroupMappingUI> uiPage = service.selectInterfaceListForPopup(pageVo, searchName);
return ResponseEntity.ok(new GridResponse<>(uiPage));
}
/**
* 인터페이스 중복 등록 체크
*/
@RequestMapping(value = "/onl/admin/inflow/inflowGroupControlMan.json", params = "cmd=LIST_CHECK_DUPLICATE")
public ModelAndView checkDuplicate(HttpServletRequest request, HttpServletResponse response,
@RequestParam("interfaceId") String interfaceId,
@RequestParam(value = "groupId", required = false) String groupId) {
String existingGroupName = service.checkInterfaceDuplicate(interfaceId, groupId);
Map<String, Object> resultMap = new HashMap<>();
resultMap.put("duplicate", existingGroupName != null);
resultMap.put("groupName", existingGroupName);
return new ModelAndView("jsonView", resultMap);
}
/**
* JSON 문자열을 인터페이스 목록으로 변환
*/
private void parseInterfaceList(InflowGroupControlManUI ui, String interfaceListJson) throws Exception {
if (interfaceListJson != null && !interfaceListJson.isEmpty()) {
List<InflowGroupMappingUI> interfaceList = objectMapper.readValue(interfaceListJson,
new TypeReference<List<InflowGroupMappingUI>>() {
});
ui.setInterfaceList(interfaceList);
}
}
/**
* 세션에서 사용자 ID 조회
*/
private String getSessionUserId(HttpServletRequest request) {
Object userId = request.getSession().getAttribute("userId");
return userId != null ? userId.toString() : "SYSTEM";
}
}
@@ -0,0 +1,29 @@
package com.eactive.eai.rms.onl.manage.inflow.group;
import org.mapstruct.BeanMapping;
import org.mapstruct.Mapper;
import org.mapstruct.MappingTarget;
import org.mapstruct.NullValuePropertyMappingStrategy;
import org.mapstruct.ReportingPolicy;
import com.eactive.eai.data.entity.onl.inflow.InflowControlGroup;
import com.eactive.eai.data.entity.onl.inflow.InflowControlGroupMapping;
@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface InflowGroupControlManMapper {
InflowGroupControlManUI toVo(InflowControlGroup entity);
InflowControlGroup toEntity(InflowGroupControlManUI vo);
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateToEntity(InflowGroupControlManUI vo, @MappingTarget InflowControlGroup entity);
// Mapping Entity <-> UI
InflowGroupMappingUI toMappingVo(InflowControlGroupMapping entity);
InflowControlGroupMapping toMappingEntity(InflowGroupMappingUI vo);
@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
void updateToMappingEntity(InflowGroupMappingUI vo, @MappingTarget InflowControlGroupMapping entity);
}
@@ -0,0 +1,253 @@
package com.eactive.eai.rms.onl.manage.inflow.group;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.eactive.eai.data.entity.onl.inflow.InflowControlGroup;
import com.eactive.eai.data.entity.onl.inflow.InflowControlGroupMapping;
import com.eactive.eai.data.entity.onl.inflow.QInflowControlGroup;
import com.eactive.eai.data.entity.onl.inflow.QInflowControlGroupMapping;
import com.eactive.eai.data.entity.onl.message.QEAIMessageEntity;
import com.eactive.eai.rms.common.base.BaseService;
import com.eactive.eai.rms.data.entity.onl.inflow.InflowControlGroupMappingRepository;
import com.eactive.eai.rms.data.entity.onl.inflow.InflowControlGroupRepository;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQueryFactory;
@Service
public class InflowGroupControlManService extends BaseService {
@PersistenceContext
EntityManager entityManager;
@Autowired
private InflowControlGroupRepository groupRepository;
@Autowired
private InflowControlGroupMappingRepository mappingRepository;
@Autowired
private InflowGroupControlManMapper mapper;
/**
* 그룹 목록 조회
*/
public Page<InflowGroupControlManUI> selectGroupList(Pageable pageable, String searchGroupName) {
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QInflowControlGroup qGroup = QInflowControlGroup.inflowControlGroup;
BooleanBuilder boolBuilder = new BooleanBuilder();
if (!StringUtils.isEmpty(searchGroupName)) {
boolBuilder.and(qGroup.groupName.contains(searchGroupName));
}
List<InflowControlGroup> groupList = jpaQueryFactory
.selectFrom(qGroup)
.where(boolBuilder)
.orderBy(qGroup.groupId.asc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
List<InflowGroupControlManUI> uiList = groupList.stream()
.map(mapper::toVo)
.collect(Collectors.toList());
long totalCount = jpaQueryFactory
.select(qGroup.groupId.count())
.from(qGroup)
.where(boolBuilder)
.fetchOne();
return new PageImpl<>(uiList, pageable, totalCount);
}
/**
* 그룹 상세 조회 (매핑된 인터페이스 포함)
*/
public InflowGroupControlManUI selectGroupDetail(String groupId) {
Optional<InflowControlGroup> groupOpt = groupRepository.findById(groupId);
if (!groupOpt.isPresent()) {
return null;
}
InflowGroupControlManUI ui = mapper.toVo(groupOpt.get());
// 매핑된 인터페이스 목록 조회 (인터페이스 설명 포함)
List<InflowGroupMappingUI> mappingList = selectMappingListWithDesc(groupId);
ui.setInterfaceList(mappingList);
return ui;
}
/**
* 그룹에 매핑된 인터페이스 목록 조회 (인터페이스 설명 포함)
*/
private List<InflowGroupMappingUI> selectMappingListWithDesc(String groupId) {
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QInflowControlGroupMapping qMapping = QInflowControlGroupMapping.inflowControlGroupMapping;
QEAIMessageEntity qMessage = QEAIMessageEntity.eAIMessageEntity;
List<Tuple> tupleList = jpaQueryFactory
.select(qMapping, qMessage.eaisvcdesc)
.from(qMapping)
.leftJoin(qMessage).on(qMapping.interfaceId.eq(qMessage.eaisvcname))
.where(qMapping.groupId.eq(groupId))
.orderBy(qMapping.interfaceId.asc())
.fetch();
return tupleList.stream()
.map(tuple -> {
InflowGroupMappingUI mappingUI = mapper.toMappingVo(tuple.get(qMapping));
mappingUI.setInterfaceDesc(tuple.get(qMessage.eaisvcdesc));
return mappingUI;
})
.collect(Collectors.toList());
}
/**
* 그룹 저장 (INSERT/UPDATE)
*/
@Transactional
public void mergeGroup(InflowGroupControlManUI ui, String modifiedBy) {
String groupId = ui.getGroupId();
boolean isNew = StringUtils.isEmpty(groupId);
InflowControlGroup entity;
if (!isNew) {
Optional<InflowControlGroup> groupOpt = groupRepository.findById(groupId);
if (groupOpt.isPresent()) {
entity = groupOpt.get();
mapper.updateToEntity(ui, entity);
} else {
entity = mapper.toEntity(ui);
}
} else {
entity = mapper.toEntity(ui);
}
entity.setModifiedBy(modifiedBy);
entity.setModifiedAt(LocalDateTime.now());
InflowControlGroup savedEntity = groupRepository.saveAndFlush(entity);
// 저장된 엔티티의 groupId 사용 (신규 생성 시 시퀀스에서 생성된 ID)
String savedGroupId = savedEntity.getGroupId();
// 매핑 정보 저장
saveMappings(savedGroupId, ui.getInterfaceList(), modifiedBy);
}
/**
* 그룹-인터페이스 매핑 저장
*/
@Transactional
public void saveMappings(String groupId, List<InflowGroupMappingUI> interfaceList, String modifiedBy) {
// 기존 매핑 삭제
mappingRepository.deleteByGroupId(groupId);
// 새로운 매핑 저장
if (interfaceList != null && !interfaceList.isEmpty()) {
for (InflowGroupMappingUI mappingUI : interfaceList) {
InflowControlGroupMapping mapping = new InflowControlGroupMapping();
mapping.setInterfaceId(mappingUI.getInterfaceId());
mapping.setGroupId(groupId);
mapping.setUseYn("1");
mapping.setModifiedBy(modifiedBy);
mapping.setModifiedAt(LocalDateTime.now());
mappingRepository.save(mapping);
}
}
}
/**
* 그룹 삭제
*/
@Transactional
public void deleteGroup(String groupId) {
// 매핑 먼저 삭제
mappingRepository.deleteByGroupId(groupId);
// 그룹 삭제
groupRepository.deleteById(groupId);
}
/**
* 인터페이스 중복 등록 체크 (다른 그룹에 등록 여부)
* @param interfaceId 체크할 인터페이스 ID
* @param currentGroupId 현재 그룹 ID (수정 시 자기 그룹 제외, 신규 시 null)
* @return 등록된 그룹명 (미등록 시 null)
*/
public String checkInterfaceDuplicate(String interfaceId, String currentGroupId) {
Optional<InflowControlGroupMapping> mappingOpt = mappingRepository.findByInterfaceId(interfaceId);
if (!mappingOpt.isPresent()) {
return null;
}
InflowControlGroupMapping mapping = mappingOpt.get();
String existingGroupId = mapping.getGroupId();
// 현재 그룹과 동일하면 중복 아님 (수정 시)
if (existingGroupId.equals(currentGroupId)) {
return null;
}
// 그룹명 조회
Optional<InflowControlGroup> groupOpt = groupRepository.findById(existingGroupId);
if (groupOpt.isPresent()) {
return groupOpt.get().getGroupName();
}
return existingGroupId; // 그룹명 없으면 ID 반환
}
/**
* 인터페이스 목록 조회 (팝업용)
*/
public Page<InflowGroupMappingUI> selectInterfaceListForPopup(Pageable pageable, String searchName) {
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QEAIMessageEntity qMessage = QEAIMessageEntity.eAIMessageEntity;
BooleanBuilder boolBuilder = new BooleanBuilder();
if (!StringUtils.isEmpty(searchName)) {
boolBuilder.and(qMessage.eaisvcname.containsIgnoreCase(searchName)
.or(qMessage.eaisvcdesc.containsIgnoreCase(searchName)));
}
List<Tuple> tupleList = jpaQueryFactory
.select(qMessage.eaisvcname, qMessage.eaisvcdesc)
.from(qMessage)
.where(boolBuilder)
.orderBy(qMessage.eaisvcname.asc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
List<InflowGroupMappingUI> uiList = tupleList.stream()
.map(tuple -> {
InflowGroupMappingUI ui = new InflowGroupMappingUI();
ui.setInterfaceId(tuple.get(qMessage.eaisvcname));
ui.setInterfaceDesc(tuple.get(qMessage.eaisvcdesc));
return ui;
})
.collect(Collectors.toList());
long totalCount = jpaQueryFactory
.select(qMessage.eaisvcname.count())
.from(qMessage)
.where(boolBuilder)
.fetchOne();
return new PageImpl<>(uiList, pageable, totalCount);
}
}
@@ -0,0 +1,60 @@
package com.eactive.eai.rms.onl.manage.inflow.group;
import java.time.LocalDateTime;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class InflowGroupControlManUI {
/**
* 그룹 ID
*/
@JsonProperty("GROUPID")
private String groupId;
/**
* 그룹명
*/
@JsonProperty("GROUPNAME")
private String groupName;
/**
* 임계치
*/
@JsonProperty("THRESHOLD")
private Integer threshold;
/**
* 초당 임계치
*/
@JsonProperty("THRESHOLDPERSECOND")
private Integer thresholdPerSecond;
/**
* 임계치 TimeUnit
*/
@JsonProperty("THRESHOLDTIMEUNIT")
private String thresholdTimeUnit;
/**
* 사용여부
*/
@JsonProperty("USEYN")
private String useYn;
/**
* 수정일시
*/
@JsonProperty("MODIFIEDAT")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime modifiedAt;
/**
* 매핑된 인터페이스 목록 (저장용)
*/
private List<InflowGroupMappingUI> interfaceList;
}
@@ -0,0 +1,37 @@
package com.eactive.eai.rms.onl.manage.inflow.group;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
@Data
public class InflowGroupMappingUI {
/**
* 인터페이스 ID
*/
@JsonProperty("INTERFACEID")
@JsonAlias("interfaceId")
private String interfaceId;
/**
* 인터페이스 설명 (조회용)
*/
@JsonProperty("INTERFACEDESC")
@JsonAlias("interfaceDesc")
private String interfaceDesc;
/**
* 그룹 ID
*/
@JsonProperty("GROUPID")
@JsonAlias("groupId")
private String groupId;
/**
* 사용여부
*/
@JsonProperty("USEYN")
@JsonAlias("useYn")
private String useYn;
}