Kaynağa Gözat

万达运行诊断1.0.0

shaohongbo 3 yıl önce
ebeveyn
işleme
14afa90a9e
38 değiştirilmiş dosya ile 4163 ekleme ve 1 silme
  1. 185 0
      src/main/java/com/persagy/apm/diagnose/config/RedisConfig.java
  2. 83 0
      src/main/java/com/persagy/apm/diagnose/config/ThreadPoolExecutorConfig.java
  3. 42 0
      src/main/java/com/persagy/apm/diagnose/constant/EnumDataTimeType.java
  4. 45 0
      src/main/java/com/persagy/apm/diagnose/constant/EnumTimeType.java
  5. 62 0
      src/main/java/com/persagy/apm/diagnose/executor/ThreadPoolExecutorExtend.java
  6. 26 0
      src/main/java/com/persagy/apm/diagnose/feign/AlarmResult.java
  7. 22 0
      src/main/java/com/persagy/apm/diagnose/feign/client/AlarmServiceClient.java
  8. 30 0
      src/main/java/com/persagy/apm/diagnose/feign/client/CenterMiddlewareClient.java
  9. 27 0
      src/main/java/com/persagy/apm/diagnose/feign/client/SaasWebClient.java
  10. 46 0
      src/main/java/com/persagy/apm/diagnose/indicatorrecord/model/dto/CalculateVariableDTO.java
  11. 37 0
      src/main/java/com/persagy/apm/diagnose/indicatorrecord/model/dto/ComputeCalculateDTO.java
  12. 33 0
      src/main/java/com/persagy/apm/diagnose/indicatorrecord/model/dto/ConfigItemDataSendTimeDTO.java
  13. 1 1
      src/main/java/com/persagy/apm/diagnose/indicatorrecord/service/impl/MonitorIndicatorRecordServiceImpl.java
  14. 214 0
      src/main/java/com/persagy/apm/diagnose/service/CenterDataService.java
  15. 100 0
      src/main/java/com/persagy/apm/diagnose/service/ComputeIndicatorDataService.java
  16. 64 0
      src/main/java/com/persagy/apm/diagnose/service/EnergyAlarmServiceImpl.java
  17. 68 0
      src/main/java/com/persagy/apm/diagnose/service/NettyAlarmServiceImpl.java
  18. 68 0
      src/main/java/com/persagy/apm/diagnose/service/SaasWebServiceImpl.java
  19. 26 0
      src/main/java/com/persagy/apm/diagnose/service/dto/CalculateMethodDTO.java
  20. 27 0
      src/main/java/com/persagy/apm/diagnose/service/dto/MonitorIndicatorConfigDTO.java
  21. 56 0
      src/main/java/com/persagy/apm/diagnose/service/dto/ObjRelationDataDTO.java
  22. 24 0
      src/main/java/com/persagy/apm/diagnose/service/dto/ProjectDTO.java
  23. 33 0
      src/main/java/com/persagy/apm/diagnose/service/dto/TimeDataDTO.java
  24. 33 0
      src/main/java/com/persagy/apm/diagnose/service/schedule/ComputeIndicatorData.java
  25. 33 0
      src/main/java/com/persagy/apm/diagnose/service/schedule/SendIndicatorData.java
  26. 31 0
      src/main/java/com/persagy/apm/diagnose/utils/AlarmResultUtil.java
  27. 95 0
      src/main/java/com/persagy/apm/diagnose/utils/CalculateUtil.java
  28. 35 0
      src/main/java/com/persagy/apm/diagnose/utils/CenterDataUtil.java
  29. 52 0
      src/main/java/com/persagy/apm/diagnose/utils/CollectDataUtil.java
  30. 63 0
      src/main/java/com/persagy/apm/diagnose/utils/CommonUtils.java
  31. 111 0
      src/main/java/com/persagy/apm/diagnose/utils/ComputeFormulaUtil.java
  32. 295 0
      src/main/java/com/persagy/apm/diagnose/utils/DataUtils.java
  33. 1136 0
      src/main/java/com/persagy/apm/diagnose/utils/DateUtils.java
  34. 26 0
      src/main/java/com/persagy/apm/diagnose/utils/DmpResultUtil.java
  35. 59 0
      src/main/java/com/persagy/apm/diagnose/utils/RedisLock.java
  36. 818 0
      src/main/java/com/persagy/apm/diagnose/utils/RedisUtil.java
  37. 53 0
      src/main/java/com/persagy/apm/diagnose/utils/TimeDataUtil.java
  38. 4 0
      src/main/resources/bootstrap.yml

+ 185 - 0
src/main/java/com/persagy/apm/diagnose/config/RedisConfig.java

@@ -0,0 +1,185 @@
+package com.persagy.apm.diagnose.config;
+
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisNode;
+import org.springframework.data.redis.connection.RedisPassword;
+import org.springframework.data.redis.connection.RedisSentinelConfiguration;
+import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
+import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
+import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.util.StringUtils;
+import redis.clients.jedis.JedisPoolConfig;
+
+import java.util.HashSet;
+import java.util.Set;
+
+
+//被@RefreshScope修饰的Bean都是延迟加载的,只有在第一次访问时才会被初始化,刷新Bean也是同理,下次访问时会创建一个信息的对象
+@RefreshScope //这里不能省略  不然不能手动触发
+@Configuration
+public class RedisConfig {
+
+
+	@Bean
+	@ConfigurationProperties(prefix = "spring.redis.pool")
+	public JedisPoolConfig getRedisConfig(){
+		return new JedisPoolConfig();
+	}
+	
+	/**
+	 * 主机地址
+	 */
+	@Value("${spring.redis.host}")
+	private String springRedisHost;
+	
+	/**
+	 * 端口号
+	 */
+	@Value("${spring.redis.port}")
+	private Integer springRedisPort;
+	
+
+
+	/**
+	 * 密码(如果有的话)
+	 */
+	@Value("${spring.redis.password.sentinel}")
+	private String springRedisPassword;
+
+	/**
+	 * 单机密码
+	 */
+	@Value("${spring.redis.password.standalone}")
+	private String springRedisPasswordStandalone;
+
+
+	@Value("${spring.redis.database.ten}")
+	private Integer springRedisDatabaseTen;
+	
+	/**
+	 * 哨兵集群名称
+	 */
+	@Value("${spring.redis.sentinel.master}")
+	private String springRedisSentinelMaster;
+	
+	/**
+	 * 哨兵集群节点地址
+	 */
+	@Value("${spring.redis.sentinel.nodes}")
+	private String springRedisSentinelNodes;
+
+	
+	@Value("${spring.redis.use.cluster}")
+	private Boolean redisUseCluster;
+
+
+
+	
+	/**
+	 * 
+	 *<p>Description: saas:使用索引为10的Redis库 .</p>
+	 *<p>@return RedisTemplate<String,Object>
+	 *@since 2019年5月10日: 下午5:18:27
+	 *@author gezhanbin
+	 */
+	@Bean
+	public RedisTemplate<String, Object> redisTemplate() {
+		RedisTemplate<String, Object> template = new RedisTemplate<>();
+		template.setConnectionFactory(redisConnectionFactory(springRedisDatabaseTen));
+		template.setDefaultSerializer(new StringRedisSerializer());
+		return template;
+	}
+	
+	
+	/**
+	 * 
+	 *<p>Description:  redis连接工厂 .</p> 
+	 *<p>@param index redis库的索引
+	 *<p>@return RedisConnectionFactory
+	 *@since 2019年5月10日: 下午4:49:24
+	 *@author gezhanbin
+	 */
+	private LettuceConnectionFactory redisConnectionFactory(int index) {
+		LettuceConnectionFactory redisConnectionFactory;
+		if(redisUseCluster) {
+			redisConnectionFactory = new LettuceConnectionFactory(redisSentinelConfiguration(index), jedisClientConfiguration());
+		} else {
+			redisConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration(index), jedisClientConfiguration());
+		}
+		redisConnectionFactory.afterPropertiesSet();
+		return redisConnectionFactory;
+	}
+	
+	
+	/**
+	 * 
+	 *<p>Description:  jedis 客户端 连接池配置.</p> 
+	 *<p>@return JedisClientConfiguration
+	 *@since 2019年5月10日: 下午4:47:59
+	 *@author gezhanbin
+	 */
+	private LettucePoolingClientConfiguration  jedisClientConfiguration() {
+		return LettucePoolingClientConfiguration.builder().poolConfig(getRedisConfig()).build();
+	}
+
+	
+	
+	/**
+	 * 
+	 *<p>Description:  哨兵模式的redis配置.</p> 
+	 *<p>@param index
+	 *<p>@return RedisSentinelConfiguration
+	 *@since 2019年5月10日: 下午4:20:43
+	 *@author gezhanbin
+	 */
+	private RedisSentinelConfiguration redisSentinelConfiguration(int index) {
+		RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
+		redisSentinelConfiguration.setDatabase(index);
+		redisSentinelConfiguration.setMaster(springRedisSentinelMaster);
+		//配置redis的哨兵sentinel
+		String[] hosts = StringUtils.delimitedListToStringArray(springRedisSentinelNodes,",");
+		Set<RedisNode> redisNodeSet = new HashSet<>();
+        for(String redisHost : hosts){
+            String[] item = redisHost.split(":");
+            String ip = item[0];
+            String port = item[1];
+            redisNodeSet.add(new RedisNode(ip, Integer.parseInt(port)));
+        }
+        redisSentinelConfiguration.setSentinels(redisNodeSet);
+		if(!StringUtils.isEmpty(springRedisPassword)) {
+			redisSentinelConfiguration.setPassword(redisPassword(springRedisPassword));
+		}
+		return redisSentinelConfiguration;
+	}
+	
+	
+	/**
+	 * 
+	 *<p>Description:  单机模式的redis配置 .</p> 
+	 *<p>@param index  redis库的索引
+	 *<p>@return RedisStandaloneConfiguration
+	 *@since 2019年5月10日: 下午4:05:20
+	 *@author gezhanbin
+	 */
+	private RedisStandaloneConfiguration redisStandaloneConfiguration(int index) {
+		RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
+		redisStandaloneConfiguration.setDatabase(index);
+		redisStandaloneConfiguration.setHostName(springRedisHost);
+		redisStandaloneConfiguration.setPort(springRedisPort);
+		if(!StringUtils.isEmpty(springRedisPasswordStandalone)) {
+			redisStandaloneConfiguration.setPassword(redisPassword(springRedisPasswordStandalone));
+		}
+		return redisStandaloneConfiguration;
+	}
+
+	private RedisPassword redisPassword(String password) {
+		return RedisPassword.of(password);
+	}
+}

+ 83 - 0
src/main/java/com/persagy/apm/diagnose/config/ThreadPoolExecutorConfig.java

@@ -0,0 +1,83 @@
+package com.persagy.apm.diagnose.config;
+
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import com.persagy.apm.diagnose.executor.ThreadPoolExecutorExtend;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+import java.util.concurrent.*;
+
+/**
+ * @author leifeng
+ * @version 1.0.0
+ * @ClassName ThreadPoolExecutorConfig
+ * @Description xia
+ * @createTime 2021/9/20 20:58
+ */
+@Configuration
+@EnableAsync
+@Slf4j
+public class ThreadPoolExecutorConfig {
+    /**
+     * 获得Java可用的处理器个数 + 1
+     */
+    private static final int THREADS = Runtime.getRuntime().availableProcessors() + 1;
+
+    @Value("${async.executor.thread.core_pool_size}")
+    private int corePoolSize = THREADS;
+
+    @Value("${async.executor.thread.max_pool_size}")
+    private int maxPoolSize = 2 * THREADS;
+
+    @Value("${async.executor.thread.queue_capacity}")
+    private int queueCapacity = 1024;
+
+    @Value("${async.executor.thread.name.prefix}")
+    private String namePrefix = "async-service-";
+
+    final ThreadFactory threadFactory = new ThreadFactoryBuilder()
+            // -%d不要少
+            .setNameFormat(namePrefix + "%d")
+            .setDaemon(true)
+            .build();
+
+    /**
+     * @throws
+     * @title asyncExecutor
+     * @description 计算指标线程池
+     * @author leifeng
+     * @updateTime 2021/9/20 21:26
+     * @return: java.util.concurrent.Executor
+     */
+    @Bean("asyncComputeDataExecutor")
+    public Executor asyncExecutor() {
+        return new ThreadPoolExecutorExtend(corePoolSize, maxPoolSize,
+                5, TimeUnit.SECONDS,
+                new LinkedBlockingQueue<>(queueCapacity),
+                threadFactory, (r, executor) -> {
+            log.info("asyncComputeDataTask is rejected");
+        });
+    }
+
+    /**
+     * @throws
+     * @title asyncExecutor
+     * @description 计算指标线程池
+     * @author leifeng
+     * @updateTime 2021/9/20 21:26
+     * @return: java.util.concurrent.Executor
+     */
+    @Bean("asyncSendDataExecutor")
+    public Executor asyncSendExecutor() {
+        return new ThreadPoolExecutorExtend(corePoolSize, maxPoolSize,
+                5, TimeUnit.SECONDS,
+                new LinkedBlockingQueue<>(queueCapacity),
+                threadFactory, (r, executor) -> {
+            log.info("asyncSendDataTask is rejected");
+        });
+    }
+}

+ 42 - 0
src/main/java/com/persagy/apm/diagnose/constant/EnumDataTimeType.java

@@ -0,0 +1,42 @@
+package com.persagy.apm.diagnose.constant;
+
+import com.alibaba.druid.util.StringUtils;
+
+/**
+ * @ClassName EnumDataTimeType
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 中台数据时间类型
+ * @createTime 2021/9/24 15:21
+ */
+public enum  EnumDataTimeType {
+	
+    MIN1("1min"),MIN5("5min"),MIN15("15min"),HOUR("1h"),Day("1d");
+   
+    private String code;
+    
+    EnumDataTimeType(String code){
+        this.code = code;
+    }
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+	
+	public static EnumDataTimeType getEnumDataTimeType(String code) {
+		if(StringUtils.isEmpty(code)) {
+			return null;
+		}
+		for(EnumDataTimeType item : EnumDataTimeType.values()) {
+			if(item.getCode().equals(code)) {
+				return item;
+			}
+		}
+		return null;
+	}
+	
+}

+ 45 - 0
src/main/java/com/persagy/apm/diagnose/constant/EnumTimeType.java

@@ -0,0 +1,45 @@
+package com.persagy.apm.diagnose.constant;
+
+/**
+ * Description: 能耗分表支持的几种时间粒度常量  
+ * Company: Persagy 
+ * @author cuixubin 
+ * @version 1.0
+ * @since: 2018年8月27日: 下午7:01:08
+ * Update By cuixubin 2018年8月27日: 下午7:01:08
+ */
+public enum EnumTimeType {
+	MIN15(0, "15分钟"), HOUR(1, "1h"), DAY(2, "1d"), MONTH(3, "1month"), YEAR(4, "1year");
+	
+	private int code;
+	private String name;
+	
+	public int getCode() {
+		return code;
+	}
+	public String getName() {
+		return name;
+	}
+
+	EnumTimeType(int code, String name) {
+		this.code = code;
+		this.name = name;
+	}
+	
+	/**
+	 * Description: 根据编码获取TimeDimension枚举值
+	 * @param code
+	 * @return TimeDimension
+	 * @author JiShaoJun
+	 * @since 2018年8月30日: 下午2:57:17
+	 * Update By JiShaoJun 2018年8月30日: 下午2:57:17
+	 */
+	public static EnumTimeType getTimeDimension(int code) {
+		for(EnumTimeType item : EnumTimeType.values()) {
+			if(item.getCode() == code) {
+				return item;
+			}
+		}
+		return null;
+	}
+}

+ 62 - 0
src/main/java/com/persagy/apm/diagnose/executor/ThreadPoolExecutorExtend.java

@@ -0,0 +1,62 @@
+package com.persagy.apm.diagnose.executor;
+
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * @author admin
+ * @version 1.0.0
+ * @ClassName ThreadPoolExecutorExtend.java
+ * @Description 自定义线程池,实现监控线程池方法
+ * @createTime 2021年09月20日 21:23:00
+ */
+public class ThreadPoolExecutorExtend extends ThreadPoolExecutor {
+    private final ThreadLocal startTime = new ThreadLocal();
+    private final AtomicLong numTasks = new AtomicLong();
+    private final AtomicLong totalTime = new AtomicLong();
+
+    public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
+    }
+
+    public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
+    }
+
+    public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
+    }
+
+    public ThreadPoolExecutorExtend(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
+        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
+    }
+
+    @Override
+    protected void afterExecute(Runnable r, Throwable t) {
+        try{
+            long endTime = System.currentTimeMillis();
+            long useTime = endTime - (long)startTime.get();
+            numTasks.incrementAndGet();
+            totalTime.addAndGet(useTime);
+            System.out.println("afterExecute " + r);
+        }finally{
+            super.afterExecute(r, t);
+        }
+    }
+
+    @Override
+    protected void beforeExecute(Thread t, Runnable r) {
+        super.beforeExecute(t, r);
+        System.out.println("beforeExecute " + r);
+        startTime.set(System.currentTimeMillis());
+    }
+
+    @Override
+    protected void terminated() {
+        try{
+            System.out.println("terminated avg time " + totalTime.get()  + " " + numTasks.get());
+        }finally{
+            super.terminated();
+        }
+    }
+}

+ 26 - 0
src/main/java/com/persagy/apm/diagnose/feign/AlarmResult.java

@@ -0,0 +1,26 @@
+package com.persagy.apm.diagnose.feign;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @ClassName AlarmResult
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 报警服务返回类封装
+ * @createTime 2021/9/23 12:02
+ */
+@Data
+public class AlarmResult<T> implements Serializable {
+
+
+    public final static String SUCCESS_CODE = "200";
+
+    private String result;
+
+    private T content;
+
+    private String message;
+
+}

+ 22 - 0
src/main/java/com/persagy/apm/diagnose/feign/client/AlarmServiceClient.java

@@ -0,0 +1,22 @@
+package com.persagy.apm.diagnose.feign.client;
+
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.apm.diagnose.feign.AlarmResult;
+import com.persagy.apm.diagnose.service.dto.CalculateMethodDTO;
+import com.persagy.apm.diagnose.service.dto.MonitorIndicatorConfigDTO;
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+
+@FeignClient(name = "energy-alarm-service")
+public interface AlarmServiceClient {
+
+    @PostMapping("/projectAlarmRuleObjRels/query")
+    AlarmResult<JSONObject> query(@RequestBody MonitorIndicatorConfigDTO queryMonitorIndicatorConfigDTO) throws Exception;
+
+
+    @PostMapping("/calculateMethods/query")
+    AlarmResult<JSONObject> queryCalculateMethods(@RequestBody CalculateMethodDTO calculateMethodDTO) throws Exception;
+
+}

+ 30 - 0
src/main/java/com/persagy/apm/diagnose/feign/client/CenterMiddlewareClient.java

@@ -0,0 +1,30 @@
+package com.persagy.apm.diagnose.feign.client;
+
+import java.util.Map;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * @ClassName CenterMiddlewareClient
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 中间件
+ * @createTime 2021/9/24 15:12
+ */
+//@FeignClient(name = "CENTER-MIDDLEWARE",url="http://develop2.persagy.com/center-middleware")
+@FeignClient(name = "CENTER-MIDDLEWARE")
+public interface CenterMiddlewareClient {
+
+    @PostMapping(value = "/object/query")
+    public String queryObject(@RequestBody Map<String, Object> requestMap);
+
+    @PostMapping(value = "/hisdata/queryPeriodData")
+    public String queryPeriodData(@RequestBody Map<String, Object> requestMap);
+
+
+    
+}

+ 27 - 0
src/main/java/com/persagy/apm/diagnose/feign/client/SaasWebClient.java

@@ -0,0 +1,27 @@
+package com.persagy.apm.diagnose.feign.client;
+
+import org.springframework.cloud.openfeign.FeignClient;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+
+import feign.Headers;
+
+/**
+ * 运维系统
+ */
+@FeignClient(name = "EMS-SAAS-WEB")
+public interface SaasWebClient {
+
+	/**
+	 *
+	 * Description:根据项目id查询项目信息
+	 * 
+	 * @param jsonString
+	 * @return String
+	 * @author shaohongbo
+	 * @since 2021年02月6日: 下午2:30:19 Update By shaohongbo 2021年02月6日: 下午2:30:19
+	 */
+	@PostMapping("/Spring/MVC/entrance/unifier/queryInUseProjectsByIds")
+	@Headers({ "Content-Type: application/x-www-form-urlencoded" })
+	String queryInUseProjectsByIds(@RequestParam("jsonString") String jsonString);
+}

+ 46 - 0
src/main/java/com/persagy/apm/diagnose/indicatorrecord/model/dto/CalculateVariableDTO.java

@@ -0,0 +1,46 @@
+package com.persagy.apm.diagnose.indicatorrecord.model.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @ClassName CalculateVariableDTO
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 公式变量实体
+ * @createTime 2021/9/23 20:54
+ */
+@Data
+@Builder(toBuilder=true)
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class CalculateVariableDTO {
+
+	private String computeObjType;
+
+	private String time;
+
+	private String timeType;
+
+	private String computeType;
+
+	private String computeCode;
+
+
+
+	public static CalculateVariableDTO buildCalculateVariableDTO(String v) {
+		String[] split = v.split(";");
+		CalculateVariableDTO CalculateVariableDTO = new CalculateVariableDTO();
+		CalculateVariableDTO.setComputeObjType(split[0]);
+		CalculateVariableDTO.setTime(split[1]);
+		CalculateVariableDTO.setTimeType(split[2]);
+		CalculateVariableDTO.setComputeType(split[3]);
+		CalculateVariableDTO.setComputeCode(split[4]);
+		return CalculateVariableDTO;
+	}
+
+}

+ 37 - 0
src/main/java/com/persagy/apm/diagnose/indicatorrecord/model/dto/ComputeCalculateDTO.java

@@ -0,0 +1,37 @@
+package com.persagy.apm.diagnose.indicatorrecord.model.dto;
+
+import java.util.Date;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author leifeng
+ * @version 1.0.0
+ * @ClassName ComputeCalculateDTO
+ * @Description 计算公式实体
+ * @createTime 2021/9/23 20:53
+ */
+@Data
+@Builder(toBuilder = true)
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ComputeCalculateDTO {
+
+    private String projectId;
+
+    private JSONObject obj;
+
+    private String targetId;
+
+    private CalculateVariableDTO calculateVariableDTO;
+
+    private Date dataTime;
+
+
+}

+ 33 - 0
src/main/java/com/persagy/apm/diagnose/indicatorrecord/model/dto/ConfigItemDataSendTimeDTO.java

@@ -0,0 +1,33 @@
+package com.persagy.apm.diagnose.indicatorrecord.model.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+
+/**
+ * @ClassName CalculateVariableDTO
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 对象指标发送时间
+ * @createTime 2021/9/23 20:54
+ */
+@Data
+@Builder(toBuilder=true)
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ConfigItemDataSendTimeDTO {
+
+	private String objId;
+
+	private String configItemid;
+
+	private Date lastSendTime;
+
+	private Date updateTime;
+
+}

+ 1 - 1
src/main/java/com/persagy/apm/diagnose/indicatorrecord/service/impl/MonitorIndicatorRecordServiceImpl.java

@@ -611,7 +611,7 @@ public class MonitorIndicatorRecordServiceImpl extends ServiceImpl<MonitorIndica
     private Double computeObjTargetDataByCalculate(ComputeCalculateDTO computeCalculateDTO, String calculateStr)
             throws Exception {
         List<String> variables = CalculateUtil.getVariablesFromFormula(calculateStr);
-        Map<String, Double> variableAndData = new HashMap<>();
+        Map<String, Double> variableAndData = new HashMap<>(16);
         for (String variable : variables) {
             String v = variable.substring(2, variable.length() - 1);// 获取${}中变量
             // 解析变量

+ 214 - 0
src/main/java/com/persagy/apm/diagnose/service/CenterDataService.java

@@ -0,0 +1,214 @@
+package com.persagy.apm.diagnose.service;
+
+import java.util.*;
+
+import com.alibaba.excel.util.CollectionUtils;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.apm.diagnose.constant.EnumDataTimeType;
+import com.persagy.apm.diagnose.feign.client.CenterMiddlewareClient;
+import com.persagy.apm.diagnose.service.dto.ObjRelationDataDTO;
+import com.persagy.apm.diagnose.service.dto.TimeDataDTO;
+import com.persagy.apm.diagnose.utils.DataUtils;
+import com.persagy.apm.diagnose.utils.DateUtils;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+@Service
+@Slf4j
+public class CenterDataService{
+
+
+	@Value(value = "${energy.eq.run.system.code}")
+	private String systemCode;
+
+	private static String SUCCESS = "success";
+
+	@Autowired
+	private CenterMiddlewareClient centerMiddlewareClient;
+
+
+	public JSONArray queryObjListByObjType(String projectId, List<String> classCodeList) throws Exception {
+		JSONArray resultArray = new JSONArray();
+		Map<String, Object> requestMap = new HashMap<>();
+		try {
+			requestMap.put("projectId", projectId);
+			requestMap.put("groupCode", systemCode);
+			Map<String, Object> criteria = new HashMap<>();
+			criteria.put("classCode", classCodeList);
+			criteria.put("valid", 1);
+			requestMap.put("criteria", criteria);
+			String result = centerMiddlewareClient.queryObject(requestMap);
+			resultArray = handleDataResult(result);
+		} catch (Exception e) {
+			log.error("获取类型对象列表数据错误,错误原因:" + e);
+			log.error("查询数据中台queryObject参数:" + requestMap);
+			throw e;
+		}
+		return resultArray;
+	}
+
+	private JSONArray handleDataResult(String result) throws Exception {
+		if (org.springframework.util.StringUtils.isEmpty(result)) {
+			throw new Exception("查询数据中台报错,无返回值");
+		}
+
+		JSONObject parseJsonObject = JSONObject.parseObject(result);
+		if (null != parseJsonObject && !parseJsonObject.isEmpty()
+				&& SUCCESS.equals(parseJsonObject.getString("result"))) {
+			if (parseJsonObject.getJSONArray("data") != null) {
+				return parseJsonObject.getJSONArray("data");
+			} else {
+				return new JSONArray();
+			}
+		} else {
+			throw new Exception("查询数据中台报错:");
+		}
+	}
+
+
+	public List<JSONObject> queryObjListByObjId(String projectId, List<String> objIdList) throws Exception {
+		List<JSONObject> list = new ArrayList<>();
+		Map<String, Object> requestMap = new HashMap<>();
+		try {
+			requestMap.put("projectId", projectId);
+			Map<String, Object> criteria = new HashMap<>();
+			criteria.put("id", objIdList);
+			criteria.put("valid", 1);
+			requestMap.put("criteria", criteria);
+			requestMap.put("groupCode", systemCode);
+			String result = centerMiddlewareClient.queryObject(requestMap);
+			JSONArray jsonArray = handleDataResult(result);
+
+			List<JSONObject> jsonToList = JSON.parseArray(jsonArray.toJSONString(), JSONObject.class);
+			if (!CollectionUtils.isEmpty(jsonToList)) {
+				list.addAll(jsonToList);
+			}
+		} catch (Exception e) {
+			log.error("获取对象列表数据错误,错误原因:" + e);
+			log.error("查询数据中台queryObject参数:" + requestMap);
+			throw e;
+		}
+		return list;
+	}
+
+
+	public List<TimeDataDTO> queryObjTimeDataList(String projectId, String objId, String infoCode, Date startTime,
+												  Date endTime, EnumDataTimeType dataTimeType) throws Exception {
+		List<TimeDataDTO> list = new ArrayList<>();
+		Map<String, Object> requestMap = new HashMap<>();
+		try {
+			requestMap.put("projectId", projectId);
+			requestMap.put("groupCode", systemCode);
+			Map<String, Object> criteria = new HashMap<>();
+			criteria.put("period", dataTimeType.getCode());
+			criteria.put("interpolation", false);
+			criteria.put("code", infoCode);
+			criteria.put("id", objId);
+			Map<String, Object> receivetimeMap = new HashMap<>();
+			receivetimeMap.put("$gte", DateUtils.date2Str(startTime, DateUtils.SDFSECOND));
+			receivetimeMap.put("$lt", DateUtils.date2Str(endTime, DateUtils.SDFSECOND));
+			criteria.put("receivetime", receivetimeMap);
+			requestMap.put("criteria", criteria);
+			String result = centerMiddlewareClient.queryPeriodData(requestMap);
+
+			if (null != result) {
+				JSONObject responseMap = JSONObject.parseObject(result);
+				if (null != responseMap && !responseMap.isEmpty() && SUCCESS.equals(responseMap.get("Result"))) {
+					List<Map> contentList = (List<Map>) responseMap.get("Content");
+					if (CollectionUtils.isEmpty(contentList)) {
+						return list;
+					}
+					for (Map map : contentList) {
+						String data_time = (String) map.get("data_time");
+						if (null == data_time || "".equals(data_time)) {
+							continue;
+						}
+						TimeDataDTO dto = new TimeDataDTO();
+						dto.setTime(data_time);
+						dto.setData(DataUtils.parseDouble(map.get("data_value")));
+						list.add(dto);
+					}
+				}
+			}
+		} catch (Exception e) {
+			log.error("获取分精度数据错误,错误原因:" + e);
+			log.error("查询数据中台queryObject参数:" + requestMap);
+			throw e;
+		}
+		return list;
+	}
+
+
+	public List<JSONObject> queryObjRelationList(ObjRelationDataDTO dto) throws Exception {
+		List<JSONObject> list = new ArrayList<>();
+		if (null == dto || StringUtils.isEmpty(dto.getGraphCode()) || StringUtils.isEmpty(dto.getRelCode())
+				|| (StringUtils.isEmpty(dto.getObjFrom()) && StringUtils.isEmpty(dto.getObjTo()))) {
+			return list;
+		}
+		Map<String, Object> requestMap = new HashMap<>();
+		try {
+
+			requestMap.put("projectId", dto.getProjectId());
+			requestMap.put("groupCode", systemCode);
+			Map<String, Object> criteria = new HashMap<>();
+			Map<String, Object> relation = new HashMap<>();
+			relation.put("graphCode", dto.getGraphCode());
+			relation.put("relCode", dto.getRelCode());
+			if (!StringUtils.isEmpty(dto.getObjFrom())) {
+				relation.put("objFrom", dto.getObjFrom());
+				criteria.put("relationTo", relation);
+			} else {
+				relation.put("objTo", dto.getObjTo());
+				criteria.put("relationFrom", relation);
+			}
+			if (!StringUtils.isEmpty(dto.getClassCode())) {
+				criteria.put("classCode", dto.getClassCode());
+			}
+			requestMap.put("criteria", criteria);
+
+			String result = centerMiddlewareClient.queryObject(requestMap);
+			JSONArray jsonArray = handleDataResult(result);
+			List<JSONObject> jsonToList = JSON.parseArray(jsonArray.toJSONString(), JSONObject.class);
+			if (!CollectionUtils.isEmpty(jsonToList)) {
+				list.addAll(jsonToList);
+			}
+		} catch (Exception e) {
+			log.error("获取关系对象数据错误,错误原因:" + e);
+			log.error("查询数据中台queryObject参数:" + requestMap);
+			throw e;
+		}
+		return list;
+	}
+
+
+	public JSONArray queryObjListByObjTypeAndName(String projectId, List<String> classCodeList, String keyWords)
+			throws Exception {
+		JSONArray resultArray = new JSONArray();
+		Map<String, Object> requestMap = new HashMap<>();
+		try {
+			requestMap.put("projectId", projectId);
+			requestMap.put("groupCode", systemCode);
+			Map<String, Object> criteria = new HashMap<>();
+			criteria.put("classCode", classCodeList);
+			Map<String, Object> like = new HashMap<>();
+			like.put("$like", "%" + keyWords + "%");
+			criteria.put("localName", like);
+			criteria.put("valid", 1);
+			requestMap.put("criteria", criteria);
+
+			String result = centerMiddlewareClient.queryObject(requestMap);
+			resultArray = handleDataResult(result);
+		} catch (Exception e) {
+			log.error("获取类型对象列表数据错误,错误原因:" + e);
+			log.error("查询数据中台queryObject参数:" + requestMap);
+			throw e;
+		}
+		return resultArray;
+	}
+}

+ 100 - 0
src/main/java/com/persagy/apm/diagnose/service/ComputeIndicatorDataService.java

@@ -0,0 +1,100 @@
+package com.persagy.apm.diagnose.service;
+
+import com.persagy.apm.diagnose.indicatorcompute.model.ProjectIndicatorCompute;
+import com.persagy.apm.diagnose.indicatorcompute.model.dto.QueryProjectIndicatorComputeDTO;
+import com.persagy.apm.diagnose.indicatorcompute.service.IProjectIndicatorComputeService;
+import com.persagy.apm.diagnose.indicatorrecord.service.IMonitorIndicatorRecordService;
+import com.persagy.apm.diagnose.service.dto.ProjectDTO;
+import com.persagy.apm.diagnose.timerecord.model.CalculateTimeRecord;
+import com.persagy.apm.diagnose.timerecord.model.dto.QueryCalculateTimeRecordDTO;
+import com.persagy.apm.diagnose.timerecord.service.ICalculateTimeRecordService;
+import com.persagy.apm.diagnose.utils.CommonUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Future;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * @author leifeng
+ * @version 1.0.0
+ * @ClassName ComputeIndicatorDataService
+ * @Description 计算指标数据
+ * @createTime 2021/9/20 20:51
+ */
+@Slf4j
+@Service
+public class ComputeIndicatorDataService {
+
+    @Autowired
+    private SaasWebServiceImpl saasWebServiceImpl;
+
+    @Autowired
+    private IMonitorIndicatorRecordService monitorIndicatorRecordService;
+
+    @Autowired
+    private ICalculateTimeRecordService calculateTimeRecordService;
+    @Autowired
+    private IProjectIndicatorComputeService projectIndicatorComputeService;
+
+
+    /**
+     * @throws
+     * @title computeIndicatorData
+     * @description 计算指标数据
+     * @author leifeng
+     * @updateTime 2021/9/20 21:26
+     */
+    public void computeIndicatorData() throws Exception {
+        //查询项目列表
+        List<ProjectDTO> projectDTOList = saasWebServiceImpl.queryProjectDTOList(null);
+        if(CollectionUtils.isEmpty(projectDTOList)){
+            return;
+        }
+        Map<String,ProjectIndicatorCompute> projectIdAndProjectCompute =  projectIndicatorComputeService.getProjectIdAndProjectCompute();
+
+        List<Future<String>> futureList = new ArrayList<>();
+        CountDownLatch latch = new CountDownLatch(projectDTOList.size());
+        for (ProjectDTO projectDTO : projectDTOList) {
+            futureList.add(monitorIndicatorRecordService.computeIndicatorData(projectDTO,projectIdAndProjectCompute.get(projectDTO.getProjectId()),latch));
+        }
+        //等待所有任务执行完
+        latch.await();
+        futureList.forEach(future -> {
+            try {
+                log.info(future.get());
+            } catch (Exception e) {
+                log.error("计算项目指标数据错误:" + CommonUtils.getExceptionStackTrace(e));
+            }
+        });
+    }
+
+    public void sendIndicatorData() throws Exception {
+        //查询项目列表
+        List<ProjectDTO> projectDTOList = saasWebServiceImpl.queryProjectDTOList(null);
+        if(CollectionUtils.isEmpty(projectDTOList)){
+            return;
+        }
+        List<Future<String>> futureList = new ArrayList<>();
+        CountDownLatch latch = new CountDownLatch(projectDTOList.size());
+        for (ProjectDTO projectDTO : projectDTOList) {
+            futureList.add(monitorIndicatorRecordService.sendIndicatorData(projectDTO,latch));
+        }
+        //等待所有任务执行完
+        latch.await();
+        futureList.forEach(future -> {
+            try {
+                log.info(future.get());
+            } catch (Exception e) {
+                log.error("发送指标数据错误:" + CommonUtils.getExceptionStackTrace(e));
+            }
+        });
+    }
+}

+ 64 - 0
src/main/java/com/persagy/apm/diagnose/service/EnergyAlarmServiceImpl.java

@@ -0,0 +1,64 @@
+package com.persagy.apm.diagnose.service;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.apm.diagnose.feign.AlarmResult;
+import com.persagy.apm.diagnose.feign.client.AlarmServiceClient;
+import com.persagy.apm.diagnose.service.dto.CalculateMethodDTO;
+import com.persagy.apm.diagnose.service.dto.MonitorIndicatorConfigDTO;
+import com.persagy.apm.diagnose.utils.AlarmResultUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * OriginalPresent采集当前数据查询
+ *
+ * @author strootman
+ * @version 1.0
+ * @date 2018年8月17日
+ */
+@Service
+public class EnergyAlarmServiceImpl {
+
+    @Autowired
+    AlarmServiceClient alarmServiceClient;
+
+    /**
+     * @title queryMonitorIndicatorConfigDTOList
+     * @description 查询监控指标配置
+     * @author leifeng
+     * @param: projectId
+     * @updateTime 2021/9/23 20:29
+     * @return: java.util.List<com.persagy.apm.diagnose.service.dto.MonitorIndicatorConfigDTO>
+     * @throws
+     */
+    public List<MonitorIndicatorConfigDTO> queryMonitorIndicatorConfigDTOList(String projectId) throws Exception {
+        MonitorIndicatorConfigDTO monitorIndicatorConfigDTO = MonitorIndicatorConfigDTO.builder().build();
+        monitorIndicatorConfigDTO.setProjectId(projectId);
+        AlarmResult<JSONObject> result = alarmServiceClient.query(monitorIndicatorConfigDTO);
+        return AlarmResultUtil.getRecords(result,MonitorIndicatorConfigDTO.class);
+    }
+
+
+    /**
+     * @title queryCalculateMethods
+     * @description 查询所有计算公式,key为公式id
+     * @author leifeng
+     * @updateTime 2021/9/23 20:29
+     * @return: java.util.Map<java.lang.String,com.persagy.apm.diagnose.service.dto.CalculateMethodDTO>
+     * @throws
+     */
+    public Map<String, CalculateMethodDTO> queryCalculateMethods() throws Exception {
+        AlarmResult<JSONObject> result = alarmServiceClient.queryCalculateMethods(CalculateMethodDTO.builder().build());
+        List<CalculateMethodDTO> records = AlarmResultUtil.getRecords(result, CalculateMethodDTO.class);
+        return records.stream().collect(Collectors.toMap(CalculateMethodDTO::getId, Function.identity(), (key1, key2) -> key2));
+    }
+
+
+}

+ 68 - 0
src/main/java/com/persagy/apm/diagnose/service/NettyAlarmServiceImpl.java

@@ -0,0 +1,68 @@
+package com.persagy.apm.diagnose.service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.apm.energyalarmstarter.alarmdata.feign.AlarmUrlParam;
+import com.persagy.apm.energyalarmstarter.alarmengine.service.NettyAlarmService;
+import lombok.SneakyThrows;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Arrays;
+import java.util.List;
+
+@Service
+public class NettyAlarmServiceImpl extends NettyAlarmService {
+
+
+    @Autowired
+    private CenterDataService centerDataService;
+
+    @Override
+    public String getMeterId(String infoCode, String classCode) throws Exception {
+        String separator = "_";
+        if (!infoCode.contains(separator)) {
+            throw new Exception("infoCode格式不正确,应包含'" + separator +
+                    "',classCode=" + classCode + "; infoCode=" + infoCode);
+        }
+        String[] tmp = infoCode.split(separator);
+        return tmp[0];
+    }
+
+    @Override
+    public String getFuncId(String infoCode, String classCode) throws Exception {
+        String separator = "_";
+        if (!infoCode.contains(separator)) {
+            throw new Exception("infoCode格式不正确,应包含'" + separator +
+                    "',classCode=" + classCode + "; infoCode=" + infoCode);
+        }
+        String[] tmp = infoCode.split(separator);
+        return tmp[1];
+    }
+
+    @Override
+    public String getAlarmName(String projectId, String objId, String category) {
+        return null;
+    }
+
+    @SneakyThrows
+    @Override
+    public JSONObject getAlarmSupplement(AlarmUrlParam alarmUrlParam, JSONObject alarmRecord) {
+//        "supplement": {
+//            "alarm_obj_name": "yy1中文名"
+//        }
+        String objId = alarmRecord.getString("objId");
+        List<JSONObject> objectList = centerDataService.queryObjListByObjId(alarmRecord.getString("projectId"), Arrays.asList(objId));
+        JSONObject supplement = new JSONObject();
+        if (!CollectionUtils.isEmpty(objectList)) {
+            supplement.put("alarm_obj_name", objectList.get(0).get("localName"));
+        }
+        return supplement;
+    }
+
+    @Override
+    public String getAlarmRemark(AlarmUrlParam data, String objId, String itemCode) {
+        return null;
+    }
+
+}

+ 68 - 0
src/main/java/com/persagy/apm/diagnose/service/SaasWebServiceImpl.java

@@ -0,0 +1,68 @@
+package com.persagy.apm.diagnose.service;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.apm.diagnose.feign.client.SaasWebClient;
+import com.persagy.apm.diagnose.service.dto.ProjectDTO;
+import org.apache.commons.collections.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * OriginalPresent采集当前数据查询
+ *
+ * @author strootman
+ * @version 1.0
+ * @date 2018年8月17日
+ */
+@Service
+public class SaasWebServiceImpl {
+
+    private final static String USERID = "systemId";
+    private final static String LOGINDEVICE = "PC";
+    public static final String DEFAULT_PD = "123456";
+
+    @Autowired
+    SaasWebClient saasWebClient;
+
+    /**
+     * @throws
+     * @title queryProjectDTOList
+     * @description 通过运维平台查询有效状态项目list, projectIdList可以为空, 为空时查询全部
+     * @author leifeng
+     * @param: projectIdList
+     * @updateTime 2021/9/20 20:07
+     * @return: java.util.List<com.persagy.apm.diagnose.service.dto.ProjectDTO>
+     */
+    public List<ProjectDTO> queryProjectDTOList(List<String> projectIdList) throws Exception {
+        JSONObject param = new JSONObject();
+        JSONObject puser = new JSONObject();
+        puser.put("userId", USERID);
+        puser.put("loginDevice", LOGINDEVICE);
+        param.put("puser", puser);
+        if (!CollectionUtils.isEmpty(projectIdList)) {
+            param.put("projectIds", projectIdList);
+        }
+        String resultStr = saasWebClient.queryInUseProjectsByIds(param.toJSONString());
+        JSONObject parseObject = JSONObject.parseObject(resultStr);
+        if ("failure".equals(parseObject.getString("result"))) {
+            throw new Exception("查询分区失败:" + parseObject.getString("reson"));
+        }
+        List<ProjectDTO> result = new ArrayList<>();
+        JSONArray jsonArray = parseObject.getJSONArray("content");
+        if (jsonArray == null || jsonArray.isEmpty()) {
+            return result;
+        }
+
+        for (Object object : jsonArray) {
+            JSONObject obj = (JSONObject) object;
+            ProjectDTO projectDTO = ProjectDTO.builder().projectId(obj.getString("projectId")).projectLocalId(obj.getString("projectLocalID")).build();
+            result.add(projectDTO);
+        }
+        return result;
+    }
+
+}

+ 26 - 0
src/main/java/com/persagy/apm/diagnose/service/dto/CalculateMethodDTO.java

@@ -0,0 +1,26 @@
+package com.persagy.apm.diagnose.service.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @ClassName CalculateMethodDTO
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 计算公式实体
+ * @createTime 2021/9/23 15:12
+ */
+@Data
+@Builder(toBuilder=true)
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class CalculateMethodDTO {
+	private String id;
+	private String monitorIndicatorId;
+	private String name;
+	private String formula;
+}

+ 27 - 0
src/main/java/com/persagy/apm/diagnose/service/dto/MonitorIndicatorConfigDTO.java

@@ -0,0 +1,27 @@
+package com.persagy.apm.diagnose.service.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @ClassName AlarmRuleObjRelDTO
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 监控指标配置
+ * @createTime 2021/9/23 15:12
+ */
+@Data
+@Builder(toBuilder=true)
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class MonitorIndicatorConfigDTO {
+	private String projectId;
+	private String caculateMethodId;
+	private String id;
+	private String monitorIndicatorId;
+	private String objId;
+}

+ 56 - 0
src/main/java/com/persagy/apm/diagnose/service/dto/ObjRelationDataDTO.java

@@ -0,0 +1,56 @@
+package com.persagy.apm.diagnose.service.dto;
+
+
+
+public class ObjRelationDataDTO {
+    // 项目id
+    private String projectId;
+    // 图类型编码
+	private String graphCode;
+	// 边类型编码
+	private String relCode;
+	// 对象id
+	private String objFrom;
+	// 对象id
+	private String objTo;
+	// 类型
+	private String classCode;
+	public String getProjectId() {
+		return projectId;
+	}
+	public void setProjectId(String projectId) {
+		this.projectId = projectId;
+	}
+	public String getGraphCode() {
+		return graphCode;
+	}
+	public void setGraphCode(String graphCode) {
+		this.graphCode = graphCode;
+	}
+	public String getRelCode() {
+		return relCode;
+	}
+	public void setRelCode(String relCode) {
+		this.relCode = relCode;
+	}
+	public String getObjFrom() {
+		return objFrom;
+	}
+	public void setObjFrom(String objFrom) {
+		this.objFrom = objFrom;
+	}
+	public String getObjTo() {
+		return objTo;
+	}
+	public void setObjTo(String objTo) {
+		this.objTo = objTo;
+	}
+	public String getClassCode() {
+		return classCode;
+	}
+	public void setClassCode(String classCode) {
+		this.classCode = classCode;
+	}
+	
+	
+}

+ 24 - 0
src/main/java/com/persagy/apm/diagnose/service/dto/ProjectDTO.java

@@ -0,0 +1,24 @@
+package com.persagy.apm.diagnose.service.dto;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @ClassName ProjectDTO
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 运维平台项目封装实体
+ * @createTime 2021/9/20 19:27
+ */
+@Data
+@Builder(toBuilder=true)
+@NoArgsConstructor
+@AllArgsConstructor
+@JsonInclude(JsonInclude.Include.NON_NULL)
+public class ProjectDTO {
+	private String projectId;
+	private String projectLocalId;
+}

+ 33 - 0
src/main/java/com/persagy/apm/diagnose/service/dto/TimeDataDTO.java

@@ -0,0 +1,33 @@
+package com.persagy.apm.diagnose.service.dto;
+
+
+/**
+ * 
+ * Description: 报警类型对象  
+ * Company: Persagy 
+ * @author jishaojun 
+ * @version 1.0
+ * @since: 2018年12月11日: 下午2:25:54
+ * Update By jishaojun 2018年12月11日: 下午2:25:54
+ */
+/**
+ * @author king
+ *
+ */
+public class TimeDataDTO {
+	/** 报警id */
+	private String time;
+	private Double data;//对象类型
+	public String getTime() {
+		return time;
+	}
+	public void setTime(String time) {
+		this.time = time;
+	}
+	public Double getData() {
+		return data;
+	}
+	public void setData(Double data) {
+		this.data = data;
+	}
+}

+ 33 - 0
src/main/java/com/persagy/apm/diagnose/service/schedule/ComputeIndicatorData.java

@@ -0,0 +1,33 @@
+package com.persagy.apm.diagnose.service.schedule;
+
+import com.persagy.apm.diagnose.service.ComputeIndicatorDataService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * @author king
+ */
+@Slf4j
+@Service
+public class ComputeIndicatorData {
+
+    @Value("${eyd.compute.indicator.data.enabel:false}")
+    private boolean enable;
+
+
+    @Autowired
+    private ComputeIndicatorDataService computeIndicatorDataService;
+
+    @Scheduled(cron="${eyd.compute.indicator.data.cron:0 0 0 * * ?}")
+    public void computeIndicatorData() throws Exception {
+    	if (!enable) {
+    	    //指标计算未开启
+    	    return;
+		}
+        log.info("【监测指标数据计算线程】计算指标数据开始.........");
+        computeIndicatorDataService.computeIndicatorData();
+    }
+}

+ 33 - 0
src/main/java/com/persagy/apm/diagnose/service/schedule/SendIndicatorData.java

@@ -0,0 +1,33 @@
+package com.persagy.apm.diagnose.service.schedule;
+
+import com.persagy.apm.diagnose.service.ComputeIndicatorDataService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author king
+ */
+@Slf4j
+@Service
+public class SendIndicatorData {
+
+    @Value("${eyd.send.indicator.data.enabel:false}")
+    private boolean enable;
+
+
+    @Autowired
+    private ComputeIndicatorDataService computeIndicatorDataService;
+
+    @Scheduled(cron="${eyd.send.indicator.data.cron:0 0 0 * * ?}")
+    public void computeIndicatorData() throws Exception {
+    	if (!enable) {
+    	    //指标计算未开启
+    	    return;
+		}
+        log.info("【发送监测指标数据线程】:发送指标数据开始.......");
+        computeIndicatorDataService.sendIndicatorData();
+    }
+}

+ 31 - 0
src/main/java/com/persagy/apm/diagnose/utils/AlarmResultUtil.java

@@ -0,0 +1,31 @@
+package com.persagy.apm.diagnose.utils;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.persagy.apm.diagnose.feign.AlarmResult;
+import com.persagy.apm.diagnose.service.dto.CalculateMethodDTO;
+import com.persagy.apm.diagnose.service.dto.MonitorIndicatorConfigDTO;
+import com.persagy.apm.energyalarmstarter.alarmdata.feign.DmpResult;
+import com.persagy.common.utils.StringUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author admin
+ * @version 1.0.0
+ * @ClassName DmpResultUtil.java
+ * @Description TODO
+ * @createTime 2021年09月23日 10:38:00
+ */
+public class AlarmResultUtil {
+
+    public static <T> List<T> getRecords(AlarmResult<JSONObject> result, Class<T> clazz) {
+        JSONObject content = result.getContent();
+        if (content == null || content.isEmpty()) {
+            return new ArrayList<T>();
+        }
+        JSONArray records = (JSONArray) content.getOrDefault("records", new JSONArray());
+        return records.toJavaList(clazz);
+    }
+}

+ 95 - 0
src/main/java/com/persagy/apm/diagnose/utils/CalculateUtil.java

@@ -0,0 +1,95 @@
+package com.persagy.apm.diagnose.utils;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+
+
+public class CalculateUtil {
+
+	public static Pattern pattern = Pattern.compile("\\$\\{(.*?)}");
+
+	public static final String SUM = "sum";
+	public static final String MIN = "min";
+	public static final String OBJTYPE = "obj";
+	public static final String InfoCode = "InfoCode";
+
+
+	public static final String CurrentTime = "CurrentTime";
+	public static final String Last1hTime = "Last1hTime";
+	public static final String Last15MinTime = "Last15MinTime";
+	public static final String Last30MinTime = "Last30MinTime";
+	public static final String Last45MinTime = "Last45MinTime";
+	
+	
+	public static final String After1hTime = "After1hTime";
+	public static final String After15MinTime = "After15MinTime";
+	public static final String After30MinTime = "After30MinTime";
+	public static final String After45MinTime = "After45MinTime";
+	public static final String invalidTime = "-1";
+
+	/***
+	 * 
+	 * Description: 获取公式中所有所有变量${}
+	 * 
+	 * @return List<String>
+	 * @author shaohongbo
+	 * @since 2021年8月2日: 上午9:59:34 Update By shaohongbo 2021年8月2日: 上午9:59:34
+	 */
+	public static List<String> getVariablesFromFormula(String computeFormula) {
+		List<String> resultList = new ArrayList<>();
+		// 匹配】
+		Matcher matcher = pattern.matcher(computeFormula);
+		// 处理匹配到的值
+		while (matcher.find()) {
+			resultList.add(matcher.group());
+		}
+		return resultList;
+	}
+
+	public static Date getStartTime(String time, Date timeFrom) {
+		if (time.equals(CurrentTime)) {
+			// 当前时间
+			return timeFrom;
+		}
+		if (time.equals(Last1hTime)) {
+			// 上一小时
+
+			return DateUtils.addHours(timeFrom, -1);
+		}
+		if (time.equals(Last15MinTime)) {
+			// 上15分钟
+			return DateUtils.addMinutes(timeFrom, -15);
+		}
+		if (time.equals(Last30MinTime)) {
+			// 上30分钟
+			return DateUtils.addMinutes(timeFrom, -30);
+		}
+		if (time.equals(Last45MinTime)) {
+			// 上45分钟
+			return DateUtils.addMinutes(timeFrom, -45);
+		}
+
+		if (time.equals(After1hTime)) {
+			// 上一小时
+			return DateUtils.addHours(timeFrom, 1);
+		}
+		if (time.equals(After15MinTime)) {
+			// 当前时间
+			return DateUtils.addMinutes(timeFrom, 15);
+		}
+		if (time.equals(After30MinTime)) {
+			// 当前时间
+			return DateUtils.addMinutes(timeFrom, 30);
+		}	
+		if (time.equals(After45MinTime)) {
+			// 当前时间
+			return DateUtils.addMinutes(timeFrom, 45);
+		}
+		return null;
+	}
+
+}

+ 35 - 0
src/main/java/com/persagy/apm/diagnose/utils/CenterDataUtil.java

@@ -0,0 +1,35 @@
+package com.persagy.apm.diagnose.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.persagy.apm.diagnose.service.dto.ObjRelationDataDTO;
+
+
+/**
+ * Description: Company: Persagy
+ *
+ * @author shaohongbo
+ * @version 1.0
+ * @since: 2019年9月19日: 下午12:17:58 Update By shaohongbo 2019年9月19日: 下午12:17:58
+ */
+
+public class CenterDataUtil {
+
+
+    public static final String graphCode = "MechSubset";
+
+    public static final String relCode = "Sy2Eq";
+
+    public static ObjRelationDataDTO getObjRelationDataDTO(String projectId, String classCode, String objId, String subObjId) {
+        ObjRelationDataDTO objRelationDataDTO = new ObjRelationDataDTO();
+        objRelationDataDTO.setGraphCode(graphCode);
+        objRelationDataDTO.setRelCode(relCode);
+        objRelationDataDTO.setClassCode(classCode);
+        objRelationDataDTO.setObjFrom(objId);
+        objRelationDataDTO.setProjectId(projectId);
+        objRelationDataDTO.setObjTo(subObjId);
+        return objRelationDataDTO;
+    }
+
+}

+ 52 - 0
src/main/java/com/persagy/apm/diagnose/utils/CollectDataUtil.java

@@ -0,0 +1,52 @@
+package com.persagy.apm.diagnose.utils;
+
+import com.persagy.apm.diagnose.indicatorrecord.model.MonitorIndicatorRecord;
+import org.springframework.util.CollectionUtils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.List;
+
+
+/**
+ * @author leifeng
+ * @version 1.0.0
+ * @ClassName CollectDataUtil
+ * @Description 报警服务发送数据工具类
+ * @createTime 2021/9/25 18:41
+ */
+public class CollectDataUtil {
+
+    public static String buildSendParam(List<MonitorIndicatorRecord> recordList) throws Exception {
+
+        if (CollectionUtils.isEmpty(recordList)) {
+            return null;
+        }
+        StringBuilder stringBuilder = new StringBuilder();
+        MonitorIndicatorRecord record1 = recordList.get(0);
+        String date = DateUtils.date2Str(record1.getDate(), "yyyyMMddHHmmss");
+        stringBuilder.append(date).append(";");
+        stringBuilder.append(record1.getObjId()).append(";");
+
+        for (int i = 0; i < recordList.size(); i++) {
+            stringBuilder.append(recordList.get(i).getMonitorIndicatorId());
+            if (i == (recordList.size() - 1)) {
+                stringBuilder.append(";");
+            } else {
+                stringBuilder.append(",");
+            }
+        }
+        for (int i = 0; i < recordList.size(); i++) {
+            stringBuilder.append(recordList.get(i).getValue());
+            if (i == (recordList.size() - 1)) {
+                stringBuilder.append(";");
+            } else {
+                stringBuilder.append(",");
+            }
+        }
+        return stringBuilder.toString();
+
+    }
+
+
+}

+ 63 - 0
src/main/java/com/persagy/apm/diagnose/utils/CommonUtils.java

@@ -0,0 +1,63 @@
+package com.persagy.apm.diagnose.utils;
+
+import java.beans.PropertyDescriptor;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.security.MessageDigest;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.beans.BeanWrapper;
+import org.springframework.beans.BeanWrapperImpl;
+import org.springframework.core.convert.converter.Converter;
+import org.springframework.core.convert.support.GenericConversionService;
+
+
+/**
+ * @ClassName CommonUtils
+ * @author leifeng
+ * @version 1.0.0
+ * @Description 通用工具类
+ * @createTime 2021/9/20 21:45
+ */
+public class CommonUtils {
+
+	public static void sleep(long millisecond) {
+		try {
+			Thread.sleep(millisecond);
+		} catch (InterruptedException e) {
+			// TODO Auto-generated catch block
+		}
+	}
+
+	public static String getExceptionStackTrace(Exception e) {
+		String result;
+		StringWriter sw = null;
+		PrintWriter pw = null;
+		try {
+			sw = new StringWriter();
+			pw = new PrintWriter(sw);
+			e.printStackTrace(pw);
+			pw.flush();
+			sw.flush();
+			result = sw.toString();
+		} catch (Exception ex) {
+			result = "bad getErrorInfoFromException";
+		} finally {
+			if (pw != null) {
+				pw.close();
+			}
+			if (sw != null) {
+				try {
+					sw.close();
+				} catch (Exception ei) {
+					// TODO Auto-generated catch block
+				}
+			}
+		}
+		return result;
+	}
+}

+ 111 - 0
src/main/java/com/persagy/apm/diagnose/utils/ComputeFormulaUtil.java

@@ -0,0 +1,111 @@
+package com.persagy.apm.diagnose.utils;
+
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.util.regex.Pattern;
+
+public class ComputeFormulaUtil {
+
+	private char[] val;
+
+	private int len;
+
+	private int inx;
+
+	public static Pattern pattern = Pattern.compile("\\$\\{(.*?)}");
+
+	// 构造器,把公式传进去,比如: 100 + 20 * 5 + (1 + 2)
+	public ComputeFormulaUtil(String val) {
+		this.val = val.toCharArray();
+		len = this.val.length;
+		inx = 0;
+	}
+
+	// 获取计算结果,使用方法其实就是 new Calc("100 + 20 * 5 + (1 + 2)").getResult();就可以得到结果了
+	public BigDecimal getResult() {
+		return nextValue(BigDecimal.ZERO, '+');
+	}
+
+	// 为什么要获取下一个值,加法、减法、和左小阔号,都需要获取下一个值,因为加法、减法如果碰到乘法、除法,那么运算优先权在右侧,如果碰到左侧小括号,优先权也在右侧,所以要先把右边的值算出来
+	// // 为什么要获取下一个参数,乘法、除法,他们下一个运算符如果不是左侧小括号,那么应该从左往右顺序计算,因此需要直接取到下一个参数进行计算 //
+	// 还有一点要值得注意,那就是:在运算时,减法一律替换成加上一个负数,以此来消除实际对一个负数进行运算产生异常,比如 1 * -3,总不能检测到 -
+	// 的时候,又去做减法运算吧 // 就讲这么多了,不能理解的同学,再反复推敲几遍
+	// 获取下一个值,传入第一个参数和第一个参数后的运算符
+	private BigDecimal nextValue(BigDecimal param1, char operator) {
+		if (param1 == null) {
+			return null;
+		}
+		if (inx < len) {
+			if (operator == ')') {
+				return param1;
+			}
+			if (operator == '+') {
+				BigDecimal nextValue = nextValue(nextParam(), inx < len ? val[inx++] : ')');
+				if (nextValue == null) {
+					return null;
+				}
+				return param1.add(nextValue);
+			} else if (operator == '*') {
+				BigDecimal nextParam = nextParam();
+				if (nextParam == null) {
+					return null;
+				}
+				return nextValue(param1.multiply(nextParam, MathContext.DECIMAL128), inx < len ? val[inx++] : ')');
+			} else if (operator == '/') {
+				BigDecimal nextParam = nextParam();
+				if (nextParam == null) {
+					return null;
+				}
+				if (nextParam.doubleValue() == 0.0) {
+					nextParam = new BigDecimal(1.0);
+				}
+				return nextValue(param1.divide(nextParam, MathContext.DECIMAL128), inx < len ? val[inx++] : ')');
+			}
+		}
+		return param1;
+	}
+
+	// 获取下一个参数
+	private BigDecimal nextParam() {
+
+		char[] param = new char[len - inx + 1];
+
+		int paramInx = 0;
+
+		while (inx < len) {
+
+			if (val[inx] == '-') {
+				if (paramInx == 0) {
+					param[paramInx++] = val[inx];
+					param[paramInx++] = '0';
+				} else {
+					val[--inx] = '+';
+					break;
+				}
+			} else if (val[inx] == '.' || ((int) val[inx] >= 48 && (int) val[inx] <= 57)) {// 如果是
+																							// .
+																							// 或
+																							// 0
+																							// ~
+																							// 9
+				param[paramInx++] = val[inx];
+			} else if (val[inx] == '(') {
+				inx++;
+				return nextValue(BigDecimal.ZERO, '+');
+			} else if (((int) val[inx] >= 41 && (int) val[inx] <= 43) || (int) val[inx] == 47) {
+				break;
+			}
+
+			inx++;
+		}
+
+		return paramInx > 0 ? new BigDecimal(param, 0, paramInx) : BigDecimal.ZERO;
+	}
+
+	public static void main(String[] args) {
+		ComputeFormulaUtil computeUtil = new ComputeFormulaUtil("(10-2)/0*0");
+		BigDecimal result = computeUtil.getResult();
+		System.out.println(result);
+	}
+
+}

+ 295 - 0
src/main/java/com/persagy/apm/diagnose/utils/DataUtils.java

@@ -0,0 +1,295 @@
+package com.persagy.apm.diagnose.utils;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.springframework.util.CollectionUtils;
+
+import com.alibaba.fastjson.JSONObject;
+
+
+/**
+ * 数值、集合处理工具类
+ *
+ * @author cuixubin
+ */
+public class DataUtils {
+
+    /**
+     * 对象转Double类型
+     *
+     * @param object
+     * @return
+     */
+    public static Double parseDouble(Object object) {
+        if (object == null) {
+            return null;
+        }
+        if (object instanceof String) {
+            return Double.valueOf(object.toString());
+        }
+        if (object instanceof Integer) {
+            return ((Integer) object).doubleValue();
+        }
+        if (object instanceof Long) {
+            return ((Long) object).doubleValue();
+        }
+        if (object instanceof Double) {
+            return (Double) object;
+        }
+        if (object instanceof BigDecimal) {
+            return ((BigDecimal) object).doubleValue();
+        }
+        return (Double) object;
+    }
+
+    /**
+     * 设置小数精度
+     *
+     * @param obj
+     * @param count 精确的小数位数
+     * @return
+     */
+    public static Double setDecimalScale(Double obj, int count) {
+        if (obj == null) {
+            return null;
+        }
+        BigDecimal bd = new BigDecimal(obj);
+        return bd.setScale(count, BigDecimal.ROUND_HALF_UP).doubleValue();
+    }
+
+    /**
+     * 将Double类型的数字向下取整
+     *
+     * @param num
+     * @return
+     */
+    public static String getInt(Object num) {
+        if (num == null) {
+            return null;
+        }
+        try {
+            Double dob = Double.valueOf(num + "");
+            DecimalFormat df = new DecimalFormat("#.#");
+            return df.format(dob);
+        } catch (Exception e) {
+            return num + "";
+        }
+    }
+
+    /**
+     * BigDecimal精确计算
+     *
+     * @param dividend
+     * @param divisor
+     * @param decimalScale 小数点精确范围
+     * @return
+     * @throws Exception
+     */
+    public static <T extends Number> Double divide(T dividend, T divisor, Integer decimalScale) throws Exception {
+        if (dividend == null || divisor == null) {
+            return null;
+        }
+        if (divisor.doubleValue() == 0) {
+            return null;
+        }
+        if (decimalScale == null) {
+            decimalScale = DECIMAL_SCALE;
+        }
+        BigDecimal dividendDecimal = new BigDecimal(dividend.toString());
+        BigDecimal divisorDecimal = new BigDecimal(divisor.toString());
+        return dividendDecimal.divide(divisorDecimal, decimalScale, BigDecimal.ROUND_HALF_UP).doubleValue();
+    }
+
+    private static final int DECIMAL_SCALE = 12;
+    public static <T extends Number> Double divide(T dividend, T divisor) throws Exception {
+        return divide(dividend,divisor,DECIMAL_SCALE);
+    }
+
+    /*private static Double round(Double value, int scale) {
+        if (value == null) {
+            return null;
+        }
+        BigDecimal bd = new BigDecimal(value);
+        bd = bd.setScale(scale, BigDecimal.ROUND_HALF_UP);
+        return bd.doubleValue();
+    }*/
+
+    public static Double subtract(Double minuend, Double subtrahend) {
+        if (minuend == null && subtrahend == null) {
+            return null;
+        }
+        if (minuend == null) {
+            return -subtrahend;
+        }
+        if (subtrahend == null) {
+            return minuend;
+        }
+        return minuend - subtrahend;
+    }
+
+    public static Double plus(Double data1, Double data2) {
+        if (data1 == null && data2 == null) {
+            return null;
+        }
+        if (data1 == null) {
+            return data2;
+        }
+        if (data2 == null) {
+            return data1;
+        }
+        return data1 + data2;
+    }
+
+    public static Double plus(Double... dataList) {
+        Double sum = null;
+        for (Double data : dataList) {
+            sum = plus(sum, data);
+        }
+        return sum;
+    }
+
+
+
+    public static Integer getInt(Double data) {
+        if (data == null) {
+            return null;
+        }
+        return (int) (data + 0.5);
+    }
+
+    public static String formatData(Double energyData) {
+        if (energyData == null) {
+            return "--";
+        }
+        double result;
+        if (energyData < 1) {
+            result = DataUtils.setDecimalScale(energyData, 3);
+        } else if (energyData < 1000) {
+            result = DataUtils.setDecimalScale(energyData, 1);
+        } else {
+            result = Math.round(energyData);
+        }
+        NumberFormat nf = NumberFormat.getInstance();
+        nf.setGroupingUsed(false);
+        String resultStr = nf.format(result);
+        if (resultStr.indexOf(".") > 0) {
+            //正则表达 去掉后面无用的零
+            resultStr = resultStr.replaceAll("0+?$", "");
+            //如小数点后面全是零则去掉小数点
+            resultStr = resultStr.replaceAll("[.]$", "");
+        }
+        return resultStr;
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.out.println(formatData(0.4343));
+    }
+
+    public static Double formatDataNumber(Double energyData) {
+        if (energyData == null) {
+            return null;
+        }
+        if (energyData < 1) {
+            return DataUtils.setDecimalScale(energyData, 3);
+        } else if (energyData < 1000) {
+            return DataUtils.setDecimalScale(energyData, 1);
+        } else {
+            return Math.round(energyData) * 1.0;
+        }
+
+    }
+
+    @SuppressWarnings({ "unchecked", "rawtypes" })
+	public static void sortList(List srcList, String sortField, boolean isAsc) throws Exception{
+        if(CollectionUtils.isEmpty(srcList)){
+            return;
+        }
+        Collections.sort(srcList, (o1, o2) -> {
+            JSONObject object1 = JSONObject.parseObject(JSONObject.toJSONString(o1));
+            JSONObject object2 = JSONObject.parseObject(JSONObject.toJSONString(o2));
+            Object name1 = object1.get(sortField);
+            Object name2 = object2.get(sortField);
+            int coefficient;
+            if (isAsc) {
+                coefficient = 1;
+            } else {
+                coefficient = -1;
+            }
+            if (name1 != null && name2 != null) {
+                if (name1 instanceof Double) {
+                    return ((Double) name1).compareTo((Double) name2) * coefficient;
+                } else if (name1 instanceof Integer) {
+                    return ((Integer) name1).compareTo((Integer) name2) * coefficient;
+                } else if (name1 instanceof BigDecimal) {
+                    return ((BigDecimal) name1).compareTo((BigDecimal) name2) * coefficient;
+                } else {
+                    return ((String) name1).compareTo(((String) name2)) * coefficient;
+                }
+            } else if (name1 != null) {
+                return coefficient;
+            } else if (name2 != null) {
+                return -coefficient;
+            } else {
+                return 0;
+            }
+
+        });
+    }
+
+
+
+
+    /**
+     * 分位函数 算法参考http://www.cnblogs.com/gispathfinder/p/5770091.html
+     *
+     * @param dataList
+     * @param location
+     * @return
+     * @throws Exception
+     */
+    public static Double quantileCompute(List<Double> dataList, Double location) throws Exception {
+
+        if (CollectionUtils.isEmpty(dataList) || dataList.size() < 4) {
+            return null;
+        }
+        List<Double> sortedDataList = new ArrayList<>();
+        sortedDataList.addAll(dataList);
+        sortList(sortedDataList);
+        Double quantileLocation = (dataList.size() + 1) * location;
+        int quantileInteger = quantileLocation.intValue();
+        if (quantileInteger == 0) {
+            if (sortedDataList.get(quantileInteger) != null) {
+                return quantileLocation * sortedDataList.get(quantileInteger);
+            }
+        } else {
+            if (sortedDataList.get(quantileInteger - 1) != null && sortedDataList.get(quantileInteger) != null) {
+                return sortedDataList.get(quantileInteger - 1) + (quantileLocation - quantileInteger) * (sortedDataList.get(quantileInteger) - sortedDataList.get(quantileInteger - 1));
+            }
+        }
+        return null;
+    }
+
+    public static void sortList(List<Double> energyList) {
+        Collections.sort(energyList, (o1, o2) -> {
+            if (o1 == null && o2 == null) {
+                return 0;
+            } else if (o1 == null) {
+                return -1;
+            } else if (o2 == null) {
+                return 1;
+            } else {
+                return o1.compareTo(o2);
+            }
+        });
+    }
+}

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1136 - 0
src/main/java/com/persagy/apm/diagnose/utils/DateUtils.java


+ 26 - 0
src/main/java/com/persagy/apm/diagnose/utils/DmpResultUtil.java

@@ -0,0 +1,26 @@
+package com.persagy.apm.diagnose.utils;
+
+import com.persagy.apm.energyalarmstarter.alarmdata.feign.DmpResult;
+import com.persagy.apm.energyalarmstarter.alarmdata.model.vo.AlarmConfigItem;
+import com.persagy.common.utils.StringUtil;
+import org.apache.poi.ss.formula.functions.T;
+
+import java.util.List;
+
+/**
+ * @author admin
+ * @version 1.0.0
+ * @ClassName DmpResultUtil.java
+ * @Description TODO
+ * @createTime 2021年09月23日 10:38:00
+ */
+public class DmpResultUtil {
+
+    public static <T>  T getData(DmpResult<T> configItem) {
+        String result = configItem.getResult();
+        if(StringUtil.isBlank(result)||!result.equals(DmpResult.SUCCESS)){
+            return  null;
+        }
+        return configItem.getData();
+    }
+}

+ 59 - 0
src/main/java/com/persagy/apm/diagnose/utils/RedisLock.java

@@ -0,0 +1,59 @@
+package com.persagy.apm.diagnose.utils;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+
+@Component
+public class RedisLock {
+
+	@Autowired
+	private RedisTemplate redisTemplate;
+
+	/**
+	 * 加锁
+	 * 
+	 * @param key
+	 * @param value
+	 *            当前时间+超时时间
+	 * @return
+	 */
+	public boolean lock(String key, String value) {
+
+		if (redisTemplate.opsForValue().setIfAbsent(key, value)) {
+			// 相当于SETNX,setIfAbsent方法设置了为true,没有设置为false
+			return true;
+		}
+		// 假设currentValue=A 接下来并发进来的两个线程的value都是B
+		// 其中一个线程拿到锁,除非从始至终所有都是在并发(实际上这中情况是不存在的),只要开始时有数据有先后顺序,则分布式锁就不会出现“多卖”的现象
+		String currentValue = String.valueOf(redisTemplate.opsForValue().get(key));
+		// 如果锁过期 解决死锁
+		if (!StringUtils.isEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()) {
+			// 获取上一个锁的时间,锁过期后,GETSET将原来的锁替换成新锁
+			String oldValue = String.valueOf(redisTemplate.opsForValue().getAndSet(key, value));
+			if (!StringUtils.isEmpty(oldValue) && oldValue.equals(currentValue)) {
+				return true;
+			}
+		}
+		// 拿到锁的就有执行权力,拿不到的只有重新再来
+		return false;
+	}
+
+	/**
+	 * 解锁
+	 * 
+	 * @param key
+	 * @param value
+	 */
+	public void unlock(String key, String value) {
+		try {
+			String currentValue = String.valueOf(redisTemplate.opsForValue().get(key));
+			if (!StringUtils.isEmpty(currentValue) && currentValue.equals(value)) {
+				redisTemplate.opsForValue().getOperations().delete(key);
+			}
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+	}
+
+}

+ 818 - 0
src/main/java/com/persagy/apm/diagnose/utils/RedisUtil.java

@@ -0,0 +1,818 @@
+package com.persagy.apm.diagnose.utils;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+import javax.annotation.Resource;
+
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+@Component
+public class RedisUtil {
+
+
+    public static String TargetComputeTime = "ALL-TARGETCOMPUTETIME";
+
+    public static String PROJECT_ALARM_ITEM = "ALL-PROJECT_ALARM_ITEM";
+
+    public static String PROJECT_ITEM_SEND_TIME = "ALL-PROJECT_ITEM_SEND_TIME";
+
+    @Resource(name = "redisTemplate")
+    private RedisTemplate<Object, Object> redisTemplate;
+
+
+    /**
+     * 指定缓存失效时间
+     *
+     * @param key  键
+     * @param time 时间(秒)
+     * @return
+     */
+
+    public boolean expire(String key, long time) {
+        try {
+            if (time > 0) {
+                redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     *
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效
+     */
+
+    public long getExpire(String key) {
+        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 判断key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public boolean hasKey(String key) {
+
+        try {
+
+            return redisTemplate.hasKey(key);
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 删除缓存
+     *
+     * @param key 可以传一个值 或多个
+     */
+    @SuppressWarnings("unchecked")
+    public void del(String... key) {
+
+        if (key != null && key.length > 0) {
+
+            if (key.length == 1) {
+
+                redisTemplate.delete(key[0]);
+
+            } else {
+                redisTemplate.delete(CollectionUtils.arrayToList(key));
+
+            }
+
+        }
+
+    }
+
+    // ============================String=============================
+
+    /**
+     * 普通缓存获取
+     *
+     * @param key 键
+     * @return 值
+     */
+
+    public Object get(String key) {
+
+        return key == null ? null : redisTemplate.opsForValue().get(key);
+
+    }
+
+    /**
+     * 普通缓存放入
+     *
+     * @param key   键
+     * @param value 值
+     * @return true成功 false失败
+     */
+
+    public boolean set(String key, Object value) {
+
+        try {
+
+            redisTemplate.opsForValue().set(key, value);
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 普通缓存放入并设置时间
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
+     * @return true成功 false 失败
+     */
+
+    public boolean set(String key, Object value, long time) {
+
+        try {
+
+            if (time > 0) {
+
+                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+
+            } else {
+
+                set(key, value);
+
+            }
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 递增
+     *
+     * @param key   键
+     * @param delta 要增加几(大于0)
+     * @return
+     */
+
+    public long incr(String key, long delta) {
+
+        if (delta < 0) {
+
+            throw new RuntimeException("递增因子必须大于0");
+
+        }
+
+        return redisTemplate.opsForValue().increment(key, delta);
+
+    }
+
+    /**
+     * 递减
+     *
+     * @param key   键
+     * @param delta 要减少几(小于0)
+     * @return
+     */
+    public long decr(String key, long delta) {
+
+        if (delta < 0) {
+
+            throw new RuntimeException("递减因子必须大于0");
+
+        }
+
+        return redisTemplate.opsForValue().increment(key, -delta);
+
+    }
+
+    // ================================Map=================================
+
+    /**
+     * HashGet
+     *
+     * @param key  键 不能为null
+     * @param item 项 不能为null
+     * @return 值
+     */
+
+    public Object hget(String key, String item) {
+
+        return redisTemplate.opsForHash().get(key, item);
+
+    }
+
+    /**
+     * 获取hashKey对应的所有键值
+     *
+     * @param key 键
+     * @return 对应的多个键值
+     */
+
+    public Map<Object, Object> hmget(String key) {
+
+        return redisTemplate.opsForHash().entries(key);
+
+    }
+
+    /**
+     * HashSet
+     *
+     * @param key 键
+     * @param map 对应多个键值
+     * @return true 成功 false 失败
+     */
+
+    public boolean hmset(String key, Map<String, Object> map) {
+
+        try {
+
+            redisTemplate.opsForHash().putAll(key, map);
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * HashSet 并设置时间
+     *
+     * @param key  键
+     * @param map  对应多个键值
+     * @param time 时间(秒)
+     * @return true成功 false失败
+     */
+
+    public boolean hmset(String key, Map<String, Object> map, long time) {
+
+        try {
+
+            redisTemplate.opsForHash().putAll(key, map);
+
+            if (time > 0) {
+
+                expire(key, time);
+
+            }
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key   键
+     * @param item  项
+     * @param value 值
+     * @return true 成功 false失败
+     */
+
+    public boolean hset(String key, String item, Object value) {
+
+        try {
+
+            redisTemplate.opsForHash().put(key, item, value);
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key   键
+     * @param item  项
+     * @param value 值
+     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
+     * @return true 成功 false失败
+     */
+
+    public boolean hset(String key, String item, Object value, long time) {
+
+        try {
+
+            redisTemplate.opsForHash().put(key, item, value);
+
+            if (time > 0) {
+
+                expire(key, time);
+
+            }
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 删除hash表中的值
+     *
+     * @param key  键 不能为null
+     * @param item 项 可以使多个 不能为null
+     */
+
+    public void hdel(String key, Object... item) {
+
+        redisTemplate.opsForHash().delete(key, item);
+
+    }
+
+    /**
+     * 判断hash表中是否有该项的值
+     *
+     * @param key  键 不能为null
+     * @param item 项 不能为null
+     * @return true 存在 false不存在
+     */
+
+    public boolean hHasKey(String key, String item) {
+
+        return redisTemplate.opsForHash().hasKey(key, item);
+
+    }
+
+    /**
+     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
+     *
+     * @param key  键
+     * @param item 项
+     * @param by   要增加几(大于0)
+     * @return
+     */
+
+    public double hincr(String key, String item, double by) {
+
+        return redisTemplate.opsForHash().increment(key, item, by);
+
+    }
+
+    /**
+     * hash递减
+     *
+     * @param key  键
+     * @param item 项
+     * @param by   要减少记(小于0)
+     * @return
+     */
+
+    public double hdecr(String key, String item, double by) {
+
+        return redisTemplate.opsForHash().increment(key, item, -by);
+
+    }
+
+    // ============================set=============================
+
+    /**
+     * 根据key获取Set中的所有值
+     *
+     * @param key 键
+     * @return
+     */
+
+    public Set<Object> sGet(String key) {
+
+        try {
+
+            return redisTemplate.opsForSet().members(key);
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return null;
+
+        }
+
+    }
+
+    /**
+     * 根据value从一个set中查询,是否存在
+     *
+     * @param key   键
+     * @param value 值
+     * @return true 存在 false不存在
+     */
+
+    public boolean sHasKey(String key, Object value) {
+
+        try {
+
+            return redisTemplate.opsForSet().isMember(key, value);
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 将数据放入set缓存
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+
+    public long sSet(String key, Object... values) {
+
+        try {
+
+            return redisTemplate.opsForSet().add(key, values);
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return 0;
+
+        }
+
+    }
+
+    /**
+     * 将set数据放入缓存
+     *
+     * @param key    键
+     * @param time   时间(秒)
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+
+    public long sSetAndTime(String key, long time, Object... values) {
+
+        try {
+
+            Long count = redisTemplate.opsForSet().add(key, values);
+
+            if (time > 0) {
+                expire(key, time);
+            }
+
+            return count;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return 0;
+
+        }
+
+    }
+
+    /**
+     * 获取set缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+
+    public long sGetSetSize(String key) {
+
+        try {
+
+            return redisTemplate.opsForSet().size(key);
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return 0;
+
+        }
+
+    }
+
+    /**
+     * 移除值为value的
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     * @return 移除的个数
+     */
+
+    public long setRemove(String key, Object... values) {
+
+        try {
+
+            Long count = redisTemplate.opsForSet().remove(key, values);
+
+            return count;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return 0;
+
+        }
+
+    }
+
+    // ===============================list=================================
+
+    /**
+     * 获取list缓存的内容
+     *
+     * @param key   键
+     * @param start 开始
+     * @param end   结束 0 到 -1代表所有值
+     * @return
+     */
+
+    public List<Object> lGet(String key, long start, long end) {
+
+        try {
+
+            return redisTemplate.opsForList().range(key, start, end);
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return null;
+
+        }
+
+    }
+
+    /**
+     * 获取list缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+
+    public long lGetListSize(String key) {
+
+        try {
+
+            return redisTemplate.opsForList().size(key);
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return 0;
+
+        }
+
+    }
+
+    /**
+     * 通过索引 获取list中的值
+     *
+     * @param key   键
+     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
+     * @return
+     */
+
+    public Object lGetIndex(String key, long index) {
+
+        try {
+
+            return redisTemplate.opsForList().index(key, index);
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return null;
+
+        }
+
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param
+     * @return
+     */
+
+    public boolean lSet(String key, Object value) {
+
+        try {
+
+            redisTemplate.opsForList().rightPush(key, value);
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒)
+     * @return
+     */
+
+    public boolean lSet(String key, Object value, long time) {
+
+        try {
+
+            redisTemplate.opsForList().rightPush(key, value);
+
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param
+     * @return
+     */
+
+    public boolean lSet(String key, List<Object> value) {
+
+        try {
+
+            redisTemplate.opsForList().rightPushAll(key, value);
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 将list放入缓存
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒)
+     * @return
+     */
+
+    public boolean lSet(String key, List<Object> value, long time) {
+
+        try {
+            redisTemplate.opsForList().rightPushAll(key, value);
+
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 根据索引修改list中的某条数据
+     *
+     * @param key   键
+     * @param index 索引
+     * @param value 值
+     * @return
+     */
+
+    public boolean lUpdateIndex(String key, long index, Object value) {
+
+        try {
+
+            redisTemplate.opsForList().set(key, index, value);
+
+            return true;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return false;
+
+        }
+
+    }
+
+    /**
+     * 移除N个值为value
+     *
+     * @param key   键
+     * @param count 移除多少个
+     * @param value 值
+     * @return 移除的个数
+     */
+
+    public long lRemove(String key, long count, Object value) {
+
+        try {
+
+            Long remove = redisTemplate.opsForList().remove(key, count, value);
+
+            return remove;
+
+        } catch (Exception e) {
+
+            e.printStackTrace();
+
+            return 0;
+
+        }
+
+    }
+
+}

+ 53 - 0
src/main/java/com/persagy/apm/diagnose/utils/TimeDataUtil.java

@@ -0,0 +1,53 @@
+package com.persagy.apm.diagnose.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import com.persagy.apm.diagnose.constant.EnumTimeType;
+
+
+/**
+ * 作者:zhangyuan(kedou)
+ * 
+ * 时间:2017年9月26日 下午2:18:51
+ * 
+ * 说明:
+ */
+
+public class TimeDataUtil {
+
+	public static Map<String, Double> getTimeDataMap(Date timeFrom, Date timeTo, EnumTimeType timeType) {
+		Map<String, Double> result = new LinkedHashMap<String, Double>();
+
+		Calendar c = Calendar.getInstance();
+		c.setTime(timeFrom);
+		SimpleDateFormat standard = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+		while (c.getTime().getTime() < timeTo.getTime()) {
+			result.put(standard.format(c.getTime()), null);
+			switch (timeType) {
+			case MIN15:
+				c.add(Calendar.MINUTE, 15);
+				break;
+			case HOUR:
+				c.add(Calendar.HOUR, 1);
+				break;
+			case DAY:
+				c.add(Calendar.DATE, 1);
+				break;
+			case MONTH:
+				c.add(Calendar.MONTH, 1);
+				break;
+			case YEAR:
+				c.add(Calendar.YEAR, 1);
+				break;
+			default:
+				c.add(Calendar.DATE, 1);
+				break;
+			}
+		}
+		return result;
+	}
+}

+ 4 - 0
src/main/resources/bootstrap.yml

@@ -19,6 +19,10 @@ spring:
           separator: ";"
           schema: classpath*:db/init/table.sql
 #          data: classpath*:db/init/data.sql
+  eureka:
+    instance:
+      ip-address: 192.168.17.57
+      prefer-ip-address: true
   data:
     elasticsearch:
       repositories: