diff --git a/WebContent/jsp/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.jsp b/WebContent/jsp/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.jsp new file mode 100644 index 0000000..8e3a824 --- /dev/null +++ b/WebContent/jsp/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.jsp @@ -0,0 +1,140 @@ +<%@ page language="java" contentType="text/html; charset=utf-8"%> +<%@ page import="java.io.*"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%> +<%@ include file="/jsp/common/include/localemessage.jsp" %> +<% + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Expires", "0"); + +%> + + + + + + + + + +
+
+ +
+
+
+ + +<%-- " alt="" id="btn_search" level="R" /> --%> +
+
API 별 서킷브레이커API 별 서킷브레이커
+ + + + + + + + +
API 명
+ +
+
+ +
+
+ + + diff --git a/WebContent/jsp/onl/admin/circuitbreaker/circuitBreakerInterfaceManDetail.jsp b/WebContent/jsp/onl/admin/circuitbreaker/circuitBreakerInterfaceManDetail.jsp new file mode 100644 index 0000000..338b23a --- /dev/null +++ b/WebContent/jsp/onl/admin/circuitbreaker/circuitBreakerInterfaceManDetail.jsp @@ -0,0 +1,211 @@ +<%@ page language="java" contentType="text/html; charset=utf-8"%> +<%@ page import="java.io.*"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> +<%@ taglib uri="http://www.springframework.org/tags" prefix="spring"%> +<%@ include file="/jsp/common/include/localemessage.jsp" %> +<% + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + response.setHeader("Expires", "0"); +%> + + + + + + + + + + + +
+
+ +
+
+
+ + + +<%-- " alt="" id="btn_delete" level="W" status="DETAIL"/> --%> +<%-- " alt="" id="btn_modify" level="W" status="DETAIL,NEW" /> --%> +<%-- " alt="" id="btn_previous" level="R" status="DETAIL,NEW"/> --%> +
+
API 별 서킷브레이커 수정API 별 서킷브레이커 수정
+ +
+
+ + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
API 명
설명
실패 비율 임계값(%)
슬라이딩 창의 크기
최소 호출 수
OPEN 상태 대기 시간(초)
HALF_OPEN 상태 허용 호출 수
느린 호출 비율 임계값(%)
느린 호출 지속 시간 임계값(ms)
사용여부 +
+
+
+ +
+
+ + + diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerRepository.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerRepository.java new file mode 100644 index 0000000..aa9230c --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerRepository.java @@ -0,0 +1,8 @@ +package com.eactive.eai.rms.data.entity.onl.circuitbreaker; + +import com.eactive.eai.data.entity.onl.circuitbreaker.CircuitBreakerConfig; +import com.eactive.eai.data.jpa.BaseRepository; + +public interface CircuitBreakerRepository extends BaseRepository { + +} diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerService.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerService.java new file mode 100644 index 0000000..17d020c --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerService.java @@ -0,0 +1,94 @@ +package com.eactive.eai.rms.data.entity.onl.circuitbreaker; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; + +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 com.eactive.eai.data.entity.onl.circuitbreaker.CircuitBreakerConfig; +import com.eactive.eai.data.entity.onl.circuitbreaker.QCircuitBreakerConfig; +import com.eactive.eai.data.entity.onl.message.QEAIMessageEntity; +import com.eactive.eai.data.jpa.AbstractDataService; +import com.eactive.eai.rms.onl.manage.circuitbreaker.CircuitBreakerManMapper; +import com.querydsl.core.Tuple; +import com.querydsl.jpa.impl.JPAQueryFactory; + +@Service +public class CircuitBreakerService extends AbstractDataService { + + public static final String APIID_TYPE = "01"; + + @PersistenceContext + EntityManager entityManager; + + @Autowired + CircuitBreakerManMapper mapper; + + public Page findAllForInterface(Pageable pageable, String searchName) { + JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager); + QCircuitBreakerConfig qCircuitBreakerConfig = QCircuitBreakerConfig.circuitBreakerConfig; + QEAIMessageEntity qEAIMessageEntity = QEAIMessageEntity.eAIMessageEntity; + + List tupleList = jpaQueryFactory + .select(qCircuitBreakerConfig, qEAIMessageEntity.eaisvcname, qEAIMessageEntity.eaisvcdesc) + .from(qEAIMessageEntity) + .leftJoin(qCircuitBreakerConfig) + .on(qCircuitBreakerConfig.cbreakerType.eq(APIID_TYPE).and(qCircuitBreakerConfig.cbreakerName.eq(qEAIMessageEntity.eaisvcname))) + .where(qEAIMessageEntity.eaisvcname.contains(searchName)) + .orderBy(qEAIMessageEntity.eaisvcname.asc()) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize()) + .fetch(); + + List dtoList = tupleList + .stream() + .map(tuple -> toDto(qEAIMessageEntity, qCircuitBreakerConfig, tuple)) + .collect(Collectors.toList()); + + long totalCount = jpaQueryFactory + .select(qEAIMessageEntity.eaisvcname.count()) + .from(qEAIMessageEntity) + .where(qEAIMessageEntity.eaisvcname.contains(searchName)) + .fetchOne(); + return new PageImpl<>(dtoList, pageable, totalCount); + } + + private CircuitBreakerServiceDto toDto(QEAIMessageEntity qEAIMessageEntity, QCircuitBreakerConfig qCircuitBreakerConfig, + Tuple tuple) { + CircuitBreakerServiceDto dto = null; + if (tuple.get(qCircuitBreakerConfig) != null) + dto = mapper.toDto(tuple.get(qCircuitBreakerConfig)); + else { + dto = new CircuitBreakerServiceDto(); + dto.setCbreakerName(tuple.get(qEAIMessageEntity.eaisvcname)); + dto.setCbreakerType(APIID_TYPE); + dto.setUseYn("0");//사용안함 + } + dto.setCbreakerDesc(tuple.get(qEAIMessageEntity.eaisvcdesc)); + return dto; + } + + public CircuitBreakerServiceDto findByIdForInterface(String eaisvcname) { + JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager); + QCircuitBreakerConfig qCircuitBreakerConfig = QCircuitBreakerConfig.circuitBreakerConfig; + QEAIMessageEntity qEAIMessageEntity = QEAIMessageEntity.eAIMessageEntity; + + Tuple tuple = jpaQueryFactory + .select(qCircuitBreakerConfig, qEAIMessageEntity.eaisvcname, qEAIMessageEntity.eaisvcdesc) + .from(qEAIMessageEntity) + .leftJoin(qCircuitBreakerConfig) + .on(qCircuitBreakerConfig.cbreakerType.eq(APIID_TYPE).and(qCircuitBreakerConfig.cbreakerName.eq(qEAIMessageEntity.eaisvcname))) + .where(qEAIMessageEntity.eaisvcname.eq(eaisvcname)) + .fetchOne(); + + return toDto(qEAIMessageEntity, qCircuitBreakerConfig, tuple); + } + +} diff --git a/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerServiceDto.java b/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerServiceDto.java new file mode 100644 index 0000000..d8189b5 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/data/entity/onl/circuitbreaker/CircuitBreakerServiceDto.java @@ -0,0 +1,32 @@ +package com.eactive.eai.rms.data.entity.onl.circuitbreaker; + +import lombok.Data; + +@Data +public class CircuitBreakerServiceDto { + + private String cbreakerId; + + String cbreakerType; + + String cbreakerName; + + String cbreakerDesc; + + int failureRateThreshold; + + int slidingWindowSize; + + int minimumNumberOfCalls; + + int waitDurationInOpenState; + + int permittedNumberOfCallsInHalfOpenState; + + int slowCallRateThreshold; + + int slowCallDurationThreshold; + + String useYn; + +} diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerInterfaceManController.java b/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerInterfaceManController.java new file mode 100644 index 0000000..9ae838f --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerInterfaceManController.java @@ -0,0 +1,95 @@ +package com.eactive.eai.rms.onl.manage.circuitbreaker; + +import java.time.LocalDateTime; +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.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; + +@Controller +public class CircuitBreakerInterfaceManController extends OnlBaseAnnotationController { + + @Autowired + private CircuitBreakerManService service; + + @Autowired + private ComboService comboService; + + @RequestMapping(value = "/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.view") + public String viewList() { + return "/onl/admin/circuitbreaker/circuitBreakerInterfaceMan"; + } + + @RequestMapping(value = "/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.view", params = "cmd=DETAIL") + public String viewDetail() { + return "/onl/admin/circuitbreaker/circuitBreakerInterfaceManDetail"; + } + + @RequestMapping(value = "/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.json", params = "cmd=LIST") + public ResponseEntity> selectList(HttpServletRequest request, Pageable pageVo, + String searchName) { + Page uiPage = service.selectList(pageVo, searchName); + return ResponseEntity.ok(new GridResponse<>(uiPage)); + } + + @RequestMapping(value = "/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.json", params = "cmd=DETAIL") + public ResponseEntity selectDetail(HttpServletRequest request, HttpServletResponse response, + String name) { + CircuitBreakerManUI ui = service.selectDetail(name); + return ResponseEntity.ok(ui); + } + + @RequestMapping(value = "/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.json", params = "cmd=UPDATE") + public String save(HttpServletRequest request, HttpServletResponse response, CircuitBreakerManUI ui) + throws Exception { + String modifiedBy = getSessionUserId(request); + ui.setModifiedBy(modifiedBy); + ui.setModifiedAt(LocalDateTime.now()); + service.merge(ui); + CommonCommand command = new CommonCommand("com.eactive.eai.agent.circuitBreaker.type.ReloadTypedCircuitBreakerCommand", + ui.getCbreakerId()); + agentUtilService.broadcast(command); + return null; + } + + @RequestMapping(value = "/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.json", params = "cmd=DELETE") + public String delete(HttpServletRequest request, HttpServletResponse response, CircuitBreakerManUI ui) throws Exception { + service.delete(ui.getCbreakerId()); + CommonCommand command = new CommonCommand("com.eactive.eai.agent.circuitBreaker.type.ReloadTypedCircuitBreakerCommand", + ui.getCbreakerId()); + agentUtilService.broadcast(command); + return null; + } + + @RequestMapping(value = "/onl/admin/circuitbreaker/circuitBreakerInterfaceMan.json", params = "cmd=LIST_INIT_COMBO") + public ModelAndView initCombo(HttpServletRequest request, HttpServletResponse response) { + List useYnRows = comboService.getFromCode("USE_YN"); + Map> resultMap = new HashMap<>(); + resultMap.put("useYnRows", useYnRows); + return new ModelAndView("jsonView", resultMap); + } + + /** + * 세션에서 사용자 ID 조회 + */ + private String getSessionUserId(HttpServletRequest request) { + Object userId = request.getSession().getAttribute("userId"); + return userId != null ? userId.toString() : "SYSTEM"; + } +} \ No newline at end of file diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManMapper.java b/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManMapper.java new file mode 100644 index 0000000..e65f007 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManMapper.java @@ -0,0 +1,31 @@ +package com.eactive.eai.rms.onl.manage.circuitbreaker; + +import org.mapstruct.BeanMapping; +import org.mapstruct.InheritInverseConfiguration; +import org.mapstruct.Mapper; +import org.mapstruct.MappingTarget; +import org.mapstruct.NullValuePropertyMappingStrategy; +import org.mapstruct.ReportingPolicy; + +import com.eactive.eai.data.entity.onl.circuitbreaker.CircuitBreakerConfig; +import com.eactive.eai.data.mapper.GenericMapper; +import com.eactive.eai.rms.data.entity.onl.circuitbreaker.CircuitBreakerServiceDto; + +@Mapper(componentModel = "spring", unmappedTargetPolicy = ReportingPolicy.IGNORE) +public interface CircuitBreakerManMapper extends GenericMapper { + @Override + CircuitBreakerManUI toVo(CircuitBreakerConfig entity); + + @Override + @InheritInverseConfiguration + CircuitBreakerConfig toEntity(CircuitBreakerManUI vo); + + @InheritInverseConfiguration + @BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE) + void updateToEntity(CircuitBreakerManUI vo, @MappingTarget CircuitBreakerConfig entity); + + CircuitBreakerServiceDto toDto(CircuitBreakerConfig entity); + + CircuitBreakerManUI toVo(CircuitBreakerServiceDto serviceDto); + +} diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManService.java b/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManService.java new file mode 100644 index 0000000..5ff4b2c --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManService.java @@ -0,0 +1,70 @@ +package com.eactive.eai.rms.onl.manage.circuitbreaker; + +import java.util.Optional; + +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.eactive.eai.data.entity.onl.circuitbreaker.CircuitBreakerConfig; +import com.eactive.eai.rms.common.base.BaseService; +import com.eactive.eai.rms.common.combo.ComboService; +import com.eactive.eai.rms.data.entity.onl.circuitbreaker.CircuitBreakerService; +import com.eactive.eai.rms.data.entity.onl.circuitbreaker.CircuitBreakerServiceDto; + +@Service +public class CircuitBreakerManService extends BaseService { + + @Autowired + @Qualifier("comboService") + public ComboService comboService; + + @Autowired + private CircuitBreakerService service; + + @Autowired + private CircuitBreakerManMapper mapper; + + // 어댑터 유량제어 + public Page selectList(Pageable pageable, String searchName) { + Page dtoList = service.findAllForInterface(pageable, searchName); + return dtoList.map(mapper::toVo); + } + + public CircuitBreakerManUI selectDetail(String id) { + CircuitBreakerServiceDto dto = service.findByIdForInterface(id); + return mapper.toVo(dto); + } + + @Transactional + public void merge(CircuitBreakerManUI ui) { + ui.setCbreakerType(CircuitBreakerService.APIID_TYPE); + Optional circuitBreakerConfigOptional; + if(StringUtils.isNotEmpty(ui.getCbreakerId())) + circuitBreakerConfigOptional = service.findById(ui.getCbreakerId()); + else + circuitBreakerConfigOptional = Optional.empty(); + + CircuitBreakerConfig entity = null; + if (circuitBreakerConfigOptional.isPresent()) { + entity = circuitBreakerConfigOptional.get(); + mapper.updateToEntity(ui, entity); + } else { + entity = mapper.toEntity(ui); + entity.setCbreakerId(null); + } + entity = service.save(entity); + ui.setCbreakerId(entity.getCbreakerId()); + + } + + public void delete(String id) { + service.deleteById(id); + } + + +} diff --git a/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManUI.java b/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManUI.java new file mode 100644 index 0000000..595be37 --- /dev/null +++ b/src/main/java/com/eactive/eai/rms/onl/manage/circuitbreaker/CircuitBreakerManUI.java @@ -0,0 +1,54 @@ +package com.eactive.eai.rms.onl.manage.circuitbreaker; + +import java.time.LocalDateTime; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + +import lombok.Data; + +@Data +public class CircuitBreakerManUI { + @JsonProperty("CBREAKERID") + private String cbreakerId; + + @JsonProperty("CBREAKERTYPE") + String cbreakerType; + + @JsonProperty("CBREAKERNAME") + String cbreakerName; + + @JsonProperty("CBREAKERDESC") + String cbreakerDesc; + + @JsonProperty("FAILURERATETHRESHOLD") + Integer failureRateThreshold; + + @JsonProperty("SLIDINGWINDOWSIZE") + Integer slidingWindowSize; + + @JsonProperty("MINIMUMNUMBEROFCALLS") + Integer minimumNumberOfCalls; + + @JsonProperty("WAITDURATIONINOPENSTATE") + Integer waitDurationInOpenState; + + @JsonProperty("PERMITTEDNUMBEROFCALLSINHALFOPENSTATE") + Integer permittedNumberOfCallsInHalfOpenState; + + @JsonProperty("SLOWCALLRATETHRESHOLD") + Integer slowCallRateThreshold; + + @JsonProperty("SLOWCALLDURATIONTHRESHOLD") + Integer slowCallDurationThreshold; + + @JsonProperty("USEYN") + String useYn; + + @JsonIgnore + String modifiedBy; + + @JsonIgnore + LocalDateTime modifiedAt; + +}