Explorar o código

增加dashboard

zhouhao %!s(int64=5) %!d(string=hai) anos
pai
achega
76d8411139
Modificáronse 36 ficheiros con 1197 adicións e 0 borrados
  1. 95 0
      jetlinks-components/dashboard-components/README.md
  2. 28 0
      jetlinks-components/dashboard-components/pom.xml
  3. 23 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/CommonDimensionDefinition.java
  4. 27 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/CommonMeasurementDefinition.java
  5. 14 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/Dashboard.java
  6. 5 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DashboardDefinition.java
  7. 12 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DashboardManager.java
  8. 17 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DashboardObject.java
  9. 31 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DefaultDashboardDefinition.java
  10. 10 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/Definition.java
  11. 5 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DimensionDefinition.java
  12. 31 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/Measurement.java
  13. 5 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/MeasurementDefinition.java
  14. 23 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/MeasurementDimension.java
  15. 19 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/MeasurementParameter.java
  16. 11 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/MeasurementValue.java
  17. 5 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/ObjectDefinition.java
  18. 18 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/SimpleMeasurementValue.java
  19. 121 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemCpuMeasurementProvider.java
  20. 126 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemMemoryMeasurementProvider.java
  21. 20 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemObjectDefinition.java
  22. 47 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeDashboard.java
  23. 45 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeDashboardObject.java
  24. 42 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeMeasurement.java
  25. 59 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/DefaultDashboardManager.java
  26. 34 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/MeasurementProvider.java
  27. 42 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/StaticMeasurement.java
  28. 41 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/StaticMeasurementProvider.java
  29. 73 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/DashboardController.java
  30. 24 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/request/DashboardMeasurementRequest.java
  31. 34 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DashboardInfo.java
  32. 20 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DashboardMeasurementResponse.java
  33. 29 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DimensionInfo.java
  34. 35 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/MeasurementInfo.java
  35. 24 0
      jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/ObjectInfo.java
  36. 2 0
      jetlinks-components/pom.xml

+ 95 - 0
jetlinks-components/dashboard-components/README.md

@@ -0,0 +1,95 @@
+# 仪表盘组件
+
+获取所有类型
+
+/dashboard/defs
+
+    [
+      {
+          "id":"system",
+          "name":"系统",
+          "objects":[
+            {
+              "id":"memory",
+              "name":"内存""
+            },
+            {
+              "id":"cpu",
+              "name":"CPU""
+            }
+          ]
+      }
+    ]
+
+
+获取类型支持的指标和维度
+
+/dashboard/类型/对象/指标
+
+/dashboard/system/memory/measurements
+
+    [
+        {
+         "id":"max",
+         "name":"最大值",
+         "dimensions":[ //指标支持的维度
+           {"id":"time-interval","name":"历史数据","params":{"properties":[ ... ]}},
+           {"id":"real-time","name":"实时数据","params":{"properties":[ ... ]}}
+         ]
+        },
+        {
+         "id":"usage",
+         "name":"已使用"
+        }
+    ]
+
+
+
+POST /dashboard/system/memory/_batch
+
+    [
+        {
+           "measurement":"usage",
+           "dimension":"time-interval",
+           "params":{"interval":"1s"}
+        },
+        {
+           "measurement":"max",
+           "dimension":"time-interval",
+           "params":{"interval":"1s"}
+        }
+    ]
+
+
+    {
+     "usage":[
+        {
+           "time":"15:00",
+           "value":1.2
+        },
+        {
+           "time":"16:00",
+           "value":1.3
+        }
+     ]
+     ,
+     "max":[
+         {
+            "time":"15:00",
+            "value":2
+         },
+         {
+            "time":"16:00",
+            "value":2
+         }
+      ]
+    }
+
+/dashboard/类型/对象/维度/指标?参数
+
+GET /dashboard/device/property/temp/realTime?history=10
+ 
+     {
+        "timestamp":1578914267417,
+        "value":5.6
+     }

+ 28 - 0
jetlinks-components/dashboard-components/pom.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>jetlinks-components</artifactId>
+        <groupId>org.jetlinks.community</groupId>
+        <version>1.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>dashboard-components</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.jetlinks</groupId>
+            <artifactId>jetlinks-core</artifactId>
+            <version>${jetlinks.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.hswebframework</groupId>
+            <artifactId>hsweb-easy-orm-rdb</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 23 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/CommonDimensionDefinition.java

@@ -0,0 +1,23 @@
+package org.jetlinks.community.dashboard;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 通用维度定义
+ *
+ * @author zhouhao
+ */
+@AllArgsConstructor
+@Getter
+public enum CommonDimensionDefinition implements DimensionDefinition {
+    realTime("实时"),
+    history("历史");
+
+    private String name;
+
+    @Override
+    public String getId() {
+        return name();
+    }
+}

+ 27 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/CommonMeasurementDefinition.java

@@ -0,0 +1,27 @@
+package org.jetlinks.community.dashboard;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 通用指标定义
+ *
+ * @author zhouhao
+ */
+@AllArgsConstructor
+@Getter
+public enum CommonMeasurementDefinition implements MeasurementDefinition {
+    usage("使用率"),
+    used("已使用"),
+    info("明细"),
+    max("最大值"),
+    min("最小值"),
+    avg("平均值");
+
+    private String name;
+
+    @Override
+    public String getId() {
+        return name();
+    }
+}

+ 14 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/Dashboard.java

@@ -0,0 +1,14 @@
+package org.jetlinks.community.dashboard;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public interface Dashboard {
+
+    DashboardDefinition getDefinition();
+
+    Flux<DashboardObject> getObjects();
+
+    Mono<DashboardObject> getObject(String id);
+
+}

+ 5 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DashboardDefinition.java

@@ -0,0 +1,5 @@
+package org.jetlinks.community.dashboard;
+
+public interface DashboardDefinition extends Definition {
+
+}

+ 12 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DashboardManager.java

@@ -0,0 +1,12 @@
+package org.jetlinks.community.dashboard;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public interface DashboardManager {
+
+    Flux<Dashboard> getDashboards();
+
+    Mono<Dashboard> getDashboard(String id);
+
+}

+ 17 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DashboardObject.java

@@ -0,0 +1,17 @@
+package org.jetlinks.community.dashboard;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * 仪表对象: CPU,内存
+ */
+public interface DashboardObject  {
+
+    ObjectDefinition getDefinition();
+
+    Flux<Measurement> getMeasurements();
+
+    Mono<Measurement> getMeasurement(String id);
+
+}

+ 31 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DefaultDashboardDefinition.java

@@ -0,0 +1,31 @@
+package org.jetlinks.community.dashboard;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.hswebframework.web.dict.EnumDict;
+
+@AllArgsConstructor
+@Getter
+public enum DefaultDashboardDefinition implements DashboardDefinition, EnumDict<String> {
+
+    systemMonitor("系统监控")
+
+    ;
+
+    private String name;
+
+    @Override
+    public String getId() {
+        return name();
+    }
+
+    @Override
+    public String getValue() {
+        return getId();
+    }
+
+    @Override
+    public String getText() {
+        return name;
+    }
+}

+ 10 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/Definition.java

@@ -0,0 +1,10 @@
+package org.jetlinks.community.dashboard;
+
+public interface Definition {
+    String getId();
+
+    String getName();
+
+
+
+}

+ 5 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/DimensionDefinition.java

@@ -0,0 +1,5 @@
+package org.jetlinks.community.dashboard;
+
+public interface DimensionDefinition extends Definition {
+
+}

+ 31 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/Measurement.java

@@ -0,0 +1,31 @@
+package org.jetlinks.community.dashboard;
+
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+/**
+ * 度量,指标. 如: 使用率
+ *
+ * @author zhouhao
+ * @since 1.0
+ */
+public interface Measurement {
+
+    MeasurementDefinition getDefinition();
+
+    /**
+     * 获取所有指标维度
+     *
+     * @return 维度
+     */
+    Flux<MeasurementDimension> getDimensions();
+
+    /**
+     * 获取指定ID的维度
+     *
+     * @param id 维度定义ID
+     * @return 指定的维度, 不存在则返回 {@link Mono#empty()}
+     */
+    Mono<MeasurementDimension> getDimension(String id);
+
+}

+ 5 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/MeasurementDefinition.java

@@ -0,0 +1,5 @@
+package org.jetlinks.community.dashboard;
+
+public interface MeasurementDefinition extends Definition {
+
+}

+ 23 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/MeasurementDimension.java

@@ -0,0 +1,23 @@
+package org.jetlinks.community.dashboard;
+
+import org.jetlinks.core.metadata.ConfigMetadata;
+import org.jetlinks.core.metadata.DataType;
+import reactor.core.publisher.Flux;
+
+/**
+ * 指标维度,如: 每小时,服务器1
+ * @author zhouhao
+ */
+public interface MeasurementDimension {
+
+    DimensionDefinition getDefinition();
+
+    DataType getValueType();
+
+    ConfigMetadata getParams();
+
+    boolean isRealTime();
+
+    Flux<MeasurementValue> getValue(MeasurementParameter parameter);
+
+}

+ 19 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/MeasurementParameter.java

@@ -0,0 +1,19 @@
+package org.jetlinks.community.dashboard;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.hswebframework.ezorm.core.param.QueryParam;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Getter
+@Setter
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+public class MeasurementParameter {
+    private Map<String,Object> params=new HashMap<>();
+
+}

+ 11 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/MeasurementValue.java

@@ -0,0 +1,11 @@
+package org.jetlinks.community.dashboard;
+
+public interface MeasurementValue {
+
+    Object getValue();
+
+    String getTimeString();
+
+    long getTimestamp();
+
+}

+ 5 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/ObjectDefinition.java

@@ -0,0 +1,5 @@
+package org.jetlinks.community.dashboard;
+
+public interface ObjectDefinition extends Definition {
+
+}

+ 18 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/SimpleMeasurementValue.java

@@ -0,0 +1,18 @@
+package org.jetlinks.community.dashboard;
+
+import lombok.*;
+
+@Getter
+@Setter
+@Builder
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+public class SimpleMeasurementValue implements MeasurementValue {
+
+    private Object value;
+
+    private String timeString;
+
+    private long timestamp;
+
+}

+ 121 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemCpuMeasurementProvider.java

@@ -0,0 +1,121 @@
+package org.jetlinks.community.dashboard.measurements;
+
+import lombok.SneakyThrows;
+import org.hswebframework.utils.time.DateFormatter;
+import org.jetlinks.community.dashboard.*;
+import org.jetlinks.community.dashboard.supports.StaticMeasurement;
+import org.jetlinks.community.dashboard.supports.StaticMeasurementProvider;
+import org.jetlinks.core.metadata.ConfigMetadata;
+import org.jetlinks.core.metadata.DataType;
+import org.jetlinks.core.metadata.types.DoubleType;
+import org.jetlinks.core.metadata.unit.UnifyUnit;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Flux;
+
+import java.lang.management.ManagementFactory;
+import java.lang.management.OperatingSystemMXBean;
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Callable;
+
+import static java.math.BigDecimal.ROUND_HALF_UP;
+
+/**
+ * 实时CPU 使用率监控
+ * <pre>
+ *     /dashboard/systemMonitor/cpu/usage/realTime
+ * </pre>
+ * @author zhouhao
+ */
+@Component
+public class SystemCpuMeasurementProvider
+    extends StaticMeasurementProvider {
+
+    public SystemCpuMeasurementProvider() {
+        super(DefaultDashboardDefinition.systemMonitor, SystemObjectDefinition.cpu);
+        addMeasurement(cpuUseAgeMeasurement);
+    }
+
+    static DataType type = new DoubleType().scale(1).min(0).max(100).unit(UnifyUnit.percent);
+
+    static StaticMeasurement cpuUseAgeMeasurement = new StaticMeasurement(CommonMeasurementDefinition.usage)
+        .addDimension(new CpuRealTimeMeasurementDimension());
+
+    static OperatingSystemMXBean osMxBean = ManagementFactory.getOperatingSystemMXBean();
+
+    static Callable<Double> processCpuUsage;
+    static Callable<Double> systemCpuUsage;
+
+    private static final List<String> OPERATING_SYSTEM_BEAN_CLASS_NAMES = Arrays.asList(
+        "com.sun.management.OperatingSystemMXBean", // HotSpot
+        "com.ibm.lang.management.OperatingSystemMXBean" // J9
+    );
+
+    static {
+        Class<?> mxBeanClass = null;
+        for (String s : OPERATING_SYSTEM_BEAN_CLASS_NAMES) {
+            try {
+                mxBeanClass = Class.forName(s);
+            } catch (Exception ignore) {
+
+            }
+        }
+        try {
+            if (mxBeanClass != null) {
+                Method method = mxBeanClass.getMethod("getProcessCpuLoad");
+                Method system = mxBeanClass.getMethod("getSystemCpuLoad");
+                processCpuUsage = () -> (double) method.invoke(osMxBean);
+                systemCpuUsage = () -> (double) system.invoke(osMxBean);
+            } else {
+                processCpuUsage = () -> 0D;
+                systemCpuUsage = () -> 0D;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    static class CpuRealTimeMeasurementDimension implements MeasurementDimension {
+
+        @Override
+        public DimensionDefinition getDefinition() {
+            return CommonDimensionDefinition.realTime;
+        }
+
+        @Override
+        public DataType getValueType() {
+            return type;
+        }
+
+        @Override
+        public ConfigMetadata getParams() {
+            return null;
+        }
+
+        @Override
+        public boolean isRealTime() {
+            return true;
+        }
+
+        @SneakyThrows
+        public double getProcessCpu() {
+            return processCpuUsage.call() * 100;
+        }
+
+        @Override
+        public Flux<MeasurementValue> getValue(MeasurementParameter parameter) {
+            // TODO: 2020/1/15 性能优化
+            return Flux.interval(Duration.ofSeconds(1))
+                .map(t -> SimpleMeasurementValue.of(BigDecimal.valueOf(getProcessCpu()).setScale(1, ROUND_HALF_UP),
+                    DateFormatter.toString(new Date(), "HH:mm:ss"),
+                    System.currentTimeMillis()))
+                .cast(MeasurementValue.class);
+        }
+
+    }
+
+}

+ 126 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemMemoryMeasurementProvider.java

@@ -0,0 +1,126 @@
+package org.jetlinks.community.dashboard.measurements;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.hswebframework.utils.time.DateFormatter;
+import org.jetlinks.community.dashboard.*;
+import org.jetlinks.community.dashboard.supports.StaticMeasurement;
+import org.jetlinks.community.dashboard.supports.StaticMeasurementProvider;
+import org.jetlinks.core.metadata.ConfigMetadata;
+import org.jetlinks.core.metadata.DataType;
+import org.jetlinks.core.metadata.SimplePropertyMetadata;
+import org.jetlinks.core.metadata.types.DoubleType;
+import org.jetlinks.core.metadata.types.LongType;
+import org.jetlinks.core.metadata.types.ObjectType;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Flux;
+
+import java.lang.management.*;
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.util.Date;
+
+import static java.math.BigDecimal.ROUND_HALF_UP;
+
+/**
+ * 实时内存使用率监控
+ * <pre>
+ *     /dashboard/systemMonitor/memory/info/realTime
+ * </pre>
+ *
+ * @author zhouhao
+ */
+@Component
+public class SystemMemoryMeasurementProvider extends StaticMeasurementProvider {
+    public SystemMemoryMeasurementProvider() {
+        super(DefaultDashboardDefinition.systemMonitor, SystemObjectDefinition.memory);
+        addMeasurement(jvmMemoryInfo);
+    }
+
+    static ObjectType type = new ObjectType();
+
+    static {
+        {
+            SimplePropertyMetadata metadata = new SimplePropertyMetadata();
+            metadata.setId("max");
+            metadata.setName("最大值");
+            metadata.setValueType(new LongType());
+            type.addPropertyMetadata(metadata);
+        }
+
+        {
+            SimplePropertyMetadata metadata = new SimplePropertyMetadata();
+            metadata.setId("used");
+            metadata.setName("已使用");
+            metadata.setValueType(new LongType());
+            type.addPropertyMetadata(metadata);
+        }
+
+        {
+            SimplePropertyMetadata metadata = new SimplePropertyMetadata();
+            metadata.setId("usage");
+            metadata.setName("使用率");
+            metadata.setValueType(new DoubleType());
+            type.addPropertyMetadata(metadata);
+        }
+
+    }
+
+    static StaticMeasurement jvmMemoryInfo = new StaticMeasurement(CommonMeasurementDefinition.info)
+        .addDimension(new JvmMemoryInfoDimension());
+
+    static class JvmMemoryInfoDimension implements MeasurementDimension {
+
+        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
+
+        @Override
+        public DimensionDefinition getDefinition() {
+            return CommonDimensionDefinition.realTime;
+        }
+
+        @Override
+        public DataType getValueType() {
+            return type;
+        }
+
+        @Override
+        public ConfigMetadata getParams() {
+            return null;
+        }
+
+        @Override
+        public boolean isRealTime() {
+            return true;
+        }
+
+        @Override
+        public Flux<MeasurementValue> getValue(MeasurementParameter parameter) {
+            // TODO: 2020/1/15 性能优化
+            return Flux.interval(Duration.ofSeconds(1))
+                .map(t -> SimpleMeasurementValue.of(MemoryInfo.of(memoryMXBean.getHeapMemoryUsage()),
+                    DateFormatter.toString(new Date(), "HH:mm:ss"),
+                    System.currentTimeMillis()))
+                .cast(MeasurementValue.class);
+        }
+
+    }
+
+    @Getter
+    @Setter
+    public static class MemoryInfo {
+        private long max;
+
+        private long used;
+
+        private double usage;
+
+        public static MemoryInfo of(MemoryUsage usage) {
+            MemoryInfo info = new MemoryInfo();
+            info.max = (usage.getMax()) / 1000 / 1000;
+            info.used = usage.getUsed() / 1000 / 1000;
+            info.usage = BigDecimal.valueOf(((double) usage.getMax() / usage.getUsed()) / 100D).setScale(2, ROUND_HALF_UP)
+                .doubleValue();
+            return info;
+        }
+    }
+}

+ 20 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemObjectDefinition.java

@@ -0,0 +1,20 @@
+package org.jetlinks.community.dashboard.measurements;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import org.jetlinks.community.dashboard.ObjectDefinition;
+
+@Getter
+@AllArgsConstructor
+public enum SystemObjectDefinition implements ObjectDefinition {
+
+    cpu("CPU"),
+    memory("内存");
+
+    private String name;
+
+    @Override
+    public String getId() {
+        return name();
+    }
+}

+ 47 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeDashboard.java

@@ -0,0 +1,47 @@
+package org.jetlinks.community.dashboard.supports;
+
+import lombok.Getter;
+import org.jetlinks.community.dashboard.Dashboard;
+import org.jetlinks.community.dashboard.DashboardDefinition;
+import org.jetlinks.community.dashboard.DashboardObject;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+class CompositeDashboard implements Dashboard {
+
+    @Getter
+    private DashboardDefinition definition;
+
+    public CompositeDashboard(DashboardDefinition definition) {
+        this.definition = definition;
+    }
+
+    private Map<String, DashboardObject> staticObjects = new ConcurrentHashMap<>();
+
+    public void addProvider(MeasurementProvider provider) {
+
+        DashboardObject object = staticObjects.computeIfAbsent(provider.getObjectDefinition().getId(), __ -> new CompositeDashboardObject());
+        if(object instanceof CompositeDashboardObject){
+            CompositeDashboardObject compose = ((CompositeDashboardObject) object);
+            compose.addProvider(provider);
+        }
+
+    }
+
+    public void addObject(DashboardObject object) {
+        staticObjects.put(object.getDefinition().getId(), object);
+    }
+
+    @Override
+    public Flux<DashboardObject> getObjects() {
+        return Flux.fromIterable(staticObjects.values());
+    }
+
+    @Override
+    public Mono<DashboardObject> getObject(String id) {
+        return Mono.justOrEmpty(staticObjects.get(id));
+    }
+}

+ 45 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeDashboardObject.java

@@ -0,0 +1,45 @@
+package org.jetlinks.community.dashboard.supports;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.jetlinks.community.dashboard.DashboardObject;
+import org.jetlinks.community.dashboard.Measurement;
+import org.jetlinks.community.dashboard.ObjectDefinition;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+class CompositeDashboardObject implements DashboardObject {
+
+    private ObjectDefinition definition;
+
+    private List<MeasurementProvider> providers = new CopyOnWriteArrayList<>();
+
+    public void addProvider(MeasurementProvider provider) {
+        if (definition == null) {
+            definition = provider.getObjectDefinition();
+        }
+        providers.add(provider);
+    }
+
+    @Override
+    public ObjectDefinition getDefinition() {
+        return definition;
+    }
+
+    @Override
+    public Flux<Measurement> getMeasurements() {
+        return Flux.fromIterable(providers)
+            .flatMap(MeasurementProvider::getMeasurements);
+    }
+
+    @Override
+    public Mono<Measurement> getMeasurement(String id) {
+        return Flux.fromIterable(providers)
+            .flatMap(provider -> provider.getMeasurement(id))
+            .collectList()
+            .filter(CollectionUtils::isNotEmpty)
+            .map(CompositeMeasurement::new);
+    }
+}

+ 42 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeMeasurement.java

@@ -0,0 +1,42 @@
+package org.jetlinks.community.dashboard.supports;
+
+import org.jetlinks.community.dashboard.MeasurementDimension;
+import org.jetlinks.community.dashboard.Measurement;
+import org.jetlinks.community.dashboard.MeasurementDefinition;
+import org.springframework.util.Assert;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+class CompositeMeasurement implements Measurement {
+
+    private List<Measurement> measurements;
+
+    private Measurement main;
+
+    public CompositeMeasurement(List<Measurement> measurements) {
+        Assert.notEmpty(measurements, "measurements can not be empty");
+        this.measurements = measurements;
+        this.main = measurements.get(0);
+    }
+
+    @Override
+    public MeasurementDefinition getDefinition() {
+        return main.getDefinition();
+    }
+
+
+    @Override
+    public Flux<MeasurementDimension> getDimensions() {
+        return Flux.fromIterable(measurements)
+            .flatMap(Measurement::getDimensions);
+    }
+
+    @Override
+    public Mono<MeasurementDimension> getDimension(String id) {
+        return Flux.fromIterable(measurements)
+            .flatMap(measurement -> measurement.getDimension(id))
+            .next();
+    }
+}

+ 59 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/DefaultDashboardManager.java

@@ -0,0 +1,59 @@
+package org.jetlinks.community.dashboard.supports;
+
+import org.jetlinks.community.dashboard.DashboardDefinition;
+import org.jetlinks.community.dashboard.DashboardManager;
+import org.jetlinks.community.dashboard.Dashboard;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class DefaultDashboardManager implements DashboardManager, BeanPostProcessor {
+
+    private Map<String, Dashboard> dashboards = new ConcurrentHashMap<>();
+
+    @Override
+    public Flux<Dashboard> getDashboards() {
+        return Flux.fromIterable(dashboards.values());
+    }
+
+    @Override
+    public Mono<Dashboard> getDashboard(String id) {
+        return Mono.justOrEmpty(dashboards.get(id));
+    }
+
+
+    private void addProvider(MeasurementProvider provider) {
+
+        DashboardDefinition definition = provider.getDashboardDefinition();
+
+        Dashboard dashboard = dashboards.computeIfAbsent(definition.getId(), __ -> new CompositeDashboard(definition));
+
+        if (dashboard instanceof CompositeDashboard) {
+            CompositeDashboard compose = ((CompositeDashboard) dashboard);
+            compose.addProvider(provider);
+        } else {
+            throw new UnsupportedOperationException("unsupported register dashboard object : " + provider);
+        }
+    }
+
+    private void addDashboard(Dashboard dashboard) {
+        dashboards.put(dashboard.getDefinition().getId(), dashboard);
+    }
+
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+
+        if (bean instanceof MeasurementProvider) {
+            addProvider(((MeasurementProvider) bean));
+        } else if (bean instanceof Dashboard) {
+            addDashboard(((Dashboard) bean));
+        }
+        return bean;
+    }
+}

+ 34 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/MeasurementProvider.java

@@ -0,0 +1,34 @@
+package org.jetlinks.community.dashboard.supports;
+
+import org.jetlinks.community.dashboard.*;
+import org.jetlinks.community.dashboard.measurements.SystemObjectDefinition;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+public interface MeasurementProvider {
+
+    /**
+     * @return 仪表定义
+     * @see DefaultDashboardDefinition
+     */
+    DashboardDefinition getDashboardDefinition();
+
+    /**
+     * @return 对象定义
+     * @see SystemObjectDefinition
+     */
+    ObjectDefinition getObjectDefinition();
+
+    /**
+     * @return 全部指标
+     */
+    Flux<Measurement> getMeasurements();
+
+    /**
+     * @param id 指标ID {@link Measurement#getDefinition()} {@link MeasurementDefinition#getId()}
+     * @return 对应等指标, 不存在则返回 {@link Mono#empty()}
+     * @see MeasurementDefinition
+     */
+    Mono<Measurement> getMeasurement(String id);
+
+}

+ 42 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/StaticMeasurement.java

@@ -0,0 +1,42 @@
+package org.jetlinks.community.dashboard.supports;
+
+import lombok.Getter;
+import org.jetlinks.community.dashboard.Measurement;
+import org.jetlinks.community.dashboard.MeasurementDefinition;
+import org.jetlinks.community.dashboard.MeasurementDimension;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class StaticMeasurement implements Measurement {
+
+    @Getter
+    private MeasurementDefinition definition;
+
+
+    public StaticMeasurement(MeasurementDefinition definition) {
+        this.definition = definition;
+    }
+
+    private Map<String, MeasurementDimension> dimensions = new ConcurrentHashMap<>();
+
+    public StaticMeasurement addDimension(MeasurementDimension dimension) {
+
+        dimensions.put(dimension.getDefinition().getId(), dimension);
+
+        return this;
+
+    }
+
+    @Override
+    public Flux<MeasurementDimension> getDimensions() {
+        return Flux.fromIterable(dimensions.values());
+    }
+
+    @Override
+    public Mono<MeasurementDimension> getDimension(String id) {
+        return Mono.justOrEmpty(dimensions.get(id));
+    }
+}

+ 41 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/StaticMeasurementProvider.java

@@ -0,0 +1,41 @@
+package org.jetlinks.community.dashboard.supports;
+
+import lombok.Getter;
+import org.jetlinks.community.dashboard.DashboardDefinition;
+import org.jetlinks.community.dashboard.Measurement;
+import org.jetlinks.community.dashboard.ObjectDefinition;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public abstract class StaticMeasurementProvider implements MeasurementProvider {
+
+    private Map<String, Measurement> measurements = new ConcurrentHashMap<>();
+
+    @Getter
+    private DashboardDefinition dashboardDefinition;
+    @Getter
+    private ObjectDefinition objectDefinition;
+
+    public StaticMeasurementProvider(DashboardDefinition dashboardDefinition,
+                                     ObjectDefinition objectDefinition) {
+        this.dashboardDefinition = dashboardDefinition;
+        this.objectDefinition = objectDefinition;
+    }
+
+    protected void addMeasurement(Measurement measurement) {
+        measurements.put(measurement.getDefinition().getId(), measurement);
+    }
+
+    @Override
+    public Flux<Measurement> getMeasurements() {
+        return Flux.fromIterable(measurements.values());
+    }
+
+    @Override
+    public Mono<Measurement> getMeasurement(String id) {
+        return Mono.justOrEmpty(measurements.get(id));
+    }
+}

+ 73 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/DashboardController.java

@@ -0,0 +1,73 @@
+package org.jetlinks.community.dashboard.web;
+
+import com.alibaba.fastjson.JSON;
+import org.hswebframework.web.exception.NotFoundException;
+import org.jetlinks.community.dashboard.DashboardManager;
+import org.jetlinks.community.dashboard.DashboardObject;
+import org.jetlinks.community.dashboard.MeasurementParameter;
+import org.jetlinks.community.dashboard.MeasurementValue;
+import org.jetlinks.community.dashboard.web.response.DashboardMeasurementResponse;
+import org.jetlinks.community.dashboard.web.response.MeasurementInfo;
+import org.jetlinks.community.dashboard.web.request.DashboardMeasurementRequest;
+import org.jetlinks.community.dashboard.web.response.DashboardInfo;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.*;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+
+import java.util.Map;
+
+@RestController
+@RequestMapping("/dashboard")
+public class DashboardController {
+
+    private final DashboardManager dashboardManager;
+
+    public DashboardController(DashboardManager dashboardManager) {
+        this.dashboardManager = dashboardManager;
+    }
+
+    @GetMapping("/defs")
+    public Flux<DashboardInfo> getDefinitions() {
+        return dashboardManager
+            .getDashboards()
+            .flatMap(DashboardInfo::of);
+    }
+
+    @GetMapping("/def/{dashboard}/{object}/measurements")
+    public Flux<MeasurementInfo> getMeasurementDefinitions(@PathVariable String dashboard,
+                                                           @PathVariable String object) {
+        return dashboardManager
+            .getDashboard(dashboard)
+            .flatMap(dash -> dash.getObject(object))
+            .flatMapMany(DashboardObject::getMeasurements)
+            .flatMap(MeasurementInfo::of);
+    }
+
+    @GetMapping(value = "/{dashboard}/{object}/{measurement}/{dimension}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    public Flux<MeasurementValue> getMeasurementValue(@PathVariable String dashboard,
+                                                      @PathVariable String object,
+                                                      @PathVariable String dimension,
+                                                      @PathVariable String measurement,
+                                                      @RequestParam Map<String, Object> params) {
+        return dashboardManager
+            .getDashboard(dashboard)
+            .flatMap(dash -> dash.getObject(object))
+            .flatMap(obj -> obj.getMeasurement(measurement))
+            .flatMap(meas -> meas.getDimension(dimension))
+            .switchIfEmpty(Mono.error(() -> new NotFoundException("不支持的仪表盘")))
+            .flatMapMany(dim -> dim.getValue(MeasurementParameter.of(params)));
+    }
+
+    @GetMapping(value = "/_multi", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
+    public Flux<DashboardMeasurementResponse> getMultiMeasurementValue(@RequestParam String requestJson) {
+        return Flux.fromIterable(JSON.parseArray(requestJson, DashboardMeasurementRequest.class))
+            .flatMap(request -> dashboardManager
+                .getDashboard(request.getDashboard())
+                .flatMap(dash -> dash.getObject(request.getObject()))
+                .flatMap(obj -> obj.getMeasurement(request.getMeasurement()))
+                .flatMap(meas -> meas.getDimension(request.getDimension()))
+                .flatMapMany(dim -> dim.getValue(MeasurementParameter.of(request.getParams())))
+                .map(val -> DashboardMeasurementResponse.of(request.getGroup(), val)));
+    }
+}

+ 24 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/request/DashboardMeasurementRequest.java

@@ -0,0 +1,24 @@
+package org.jetlinks.community.dashboard.web.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Map;
+
+@Getter
+@Setter
+public class DashboardMeasurementRequest {
+
+    private String group;
+
+    private String dashboard;
+
+    private String object;
+
+    private String measurement;
+
+    private String dimension;
+
+    private Map<String,Object> params;
+
+}

+ 34 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DashboardInfo.java

@@ -0,0 +1,34 @@
+package org.jetlinks.community.dashboard.web.response;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.jetlinks.community.dashboard.Dashboard;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class DashboardInfo {
+
+    private String id;
+
+    private String name;
+
+    private List<ObjectInfo> objects;
+
+    public static Mono<DashboardInfo> of(Dashboard dashboard) {
+        return dashboard.getObjects()
+            .map(ObjectInfo::of)
+            .collectList()
+            .map(list -> {
+                DashboardInfo dashboardInfo = new DashboardInfo();
+                dashboardInfo.setId(dashboard.getDefinition().getId());
+                dashboardInfo.setName(dashboard.getDefinition().getName());
+                dashboardInfo.setObjects(list);
+                return dashboardInfo;
+            });
+
+    }
+
+}

+ 20 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DashboardMeasurementResponse.java

@@ -0,0 +1,20 @@
+package org.jetlinks.community.dashboard.web.response;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.Setter;
+import org.jetlinks.community.dashboard.MeasurementValue;
+
+@Getter
+@Setter
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+public class DashboardMeasurementResponse {
+
+    private String group;
+
+    private MeasurementValue data;
+
+
+}

+ 29 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DimensionInfo.java

@@ -0,0 +1,29 @@
+package org.jetlinks.community.dashboard.web.response;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.jetlinks.core.metadata.ConfigMetadata;
+import org.jetlinks.core.metadata.DataType;
+import org.jetlinks.community.dashboard.MeasurementDimension;
+
+@Getter
+@Setter
+public class DimensionInfo {
+    private String id;
+
+    private String name;
+
+    private DataType type;
+
+    private ConfigMetadata params;
+
+    public static DimensionInfo of(MeasurementDimension dimension){
+        DimensionInfo dimensionInfo=new DimensionInfo();
+        dimensionInfo.setId(dimension.getDefinition().getId());
+        dimensionInfo.setName(dimension.getDefinition().getName());
+        dimensionInfo.setParams(dimension.getParams());
+        dimensionInfo.setType(dimension.getValueType());
+
+        return dimensionInfo;
+    }
+}

+ 35 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/MeasurementInfo.java

@@ -0,0 +1,35 @@
+package org.jetlinks.community.dashboard.web.response;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.jetlinks.core.metadata.DataType;
+import org.jetlinks.community.dashboard.Measurement;
+import reactor.core.publisher.Mono;
+
+import java.util.List;
+
+@Getter
+@Setter
+public class MeasurementInfo {
+
+    private String id;
+
+    private String name;
+
+    private DataType type;
+
+    private List<DimensionInfo> dimensions;
+
+    public static Mono<MeasurementInfo> of(Measurement measurement){
+        return measurement.getDimensions()
+            .map(DimensionInfo::of)
+            .collectList()
+            .map(list->{
+                MeasurementInfo info=new MeasurementInfo();
+                info.setId(measurement.getDefinition().getId());
+                info.setName(measurement.getDefinition().getName());
+                info.setDimensions(list);
+                return info;
+            });
+    }
+}

+ 24 - 0
jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/ObjectInfo.java

@@ -0,0 +1,24 @@
+package org.jetlinks.community.dashboard.web.response;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.jetlinks.community.dashboard.DashboardObject;
+
+@Getter
+@Setter
+public class ObjectInfo {
+
+    private String id;
+
+    private String name;
+
+
+    public static ObjectInfo of(DashboardObject object){
+        ObjectInfo objectInfo=new ObjectInfo();
+        objectInfo.setName(object.getDefinition().getName());
+        objectInfo.setId(object.getDefinition().getId());
+
+        return objectInfo;
+    }
+
+}

+ 2 - 0
jetlinks-components/pom.xml

@@ -16,6 +16,8 @@
         <module>gateway-component</module>
         <module>io-component</module>
         <module>elasticsearch-component</module>
+        <module>timeseries-components</module>
+        <module>dashboard-components</module>
     </modules>
 
     <artifactId>jetlinks-components</artifactId>