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);
+ }
+
+ }
+
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemMemoryMeasurementProvider.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemMemoryMeasurementProvider.java
new file mode 100644
index 00000000..722bbb97
--- /dev/null
+++ b/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;
+
+/**
+ * 实时内存使用率监控
+ *
+ * /dashboard/systemMonitor/memory/info/realTime
+ *
+ *
+ * @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 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;
+ }
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemObjectDefinition.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/measurements/SystemObjectDefinition.java
new file mode 100644
index 00000000..43dd4899
--- /dev/null
+++ b/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();
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeDashboard.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeDashboard.java
new file mode 100644
index 00000000..fb2919eb
--- /dev/null
+++ b/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 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 getObjects() {
+ return Flux.fromIterable(staticObjects.values());
+ }
+
+ @Override
+ public Mono getObject(String id) {
+ return Mono.justOrEmpty(staticObjects.get(id));
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeDashboardObject.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeDashboardObject.java
new file mode 100644
index 00000000..7866ad4b
--- /dev/null
+++ b/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 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 getMeasurements() {
+ return Flux.fromIterable(providers)
+ .flatMap(MeasurementProvider::getMeasurements);
+ }
+
+ @Override
+ public Mono getMeasurement(String id) {
+ return Flux.fromIterable(providers)
+ .flatMap(provider -> provider.getMeasurement(id))
+ .collectList()
+ .filter(CollectionUtils::isNotEmpty)
+ .map(CompositeMeasurement::new);
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeMeasurement.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/CompositeMeasurement.java
new file mode 100644
index 00000000..35c8958d
--- /dev/null
+++ b/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 measurements;
+
+ private Measurement main;
+
+ public CompositeMeasurement(List 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 getDimensions() {
+ return Flux.fromIterable(measurements)
+ .flatMap(Measurement::getDimensions);
+ }
+
+ @Override
+ public Mono getDimension(String id) {
+ return Flux.fromIterable(measurements)
+ .flatMap(measurement -> measurement.getDimension(id))
+ .next();
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/DefaultDashboardManager.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/DefaultDashboardManager.java
new file mode 100644
index 00000000..d1040d41
--- /dev/null
+++ b/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 dashboards = new ConcurrentHashMap<>();
+
+ @Override
+ public Flux getDashboards() {
+ return Flux.fromIterable(dashboards.values());
+ }
+
+ @Override
+ public Mono 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;
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/MeasurementProvider.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/MeasurementProvider.java
new file mode 100644
index 00000000..68e13a03
--- /dev/null
+++ b/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 getMeasurements();
+
+ /**
+ * @param id 指标ID {@link Measurement#getDefinition()} {@link MeasurementDefinition#getId()}
+ * @return 对应等指标, 不存在则返回 {@link Mono#empty()}
+ * @see MeasurementDefinition
+ */
+ Mono getMeasurement(String id);
+
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/StaticMeasurement.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/StaticMeasurement.java
new file mode 100644
index 00000000..d4b9a597
--- /dev/null
+++ b/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 dimensions = new ConcurrentHashMap<>();
+
+ public StaticMeasurement addDimension(MeasurementDimension dimension) {
+
+ dimensions.put(dimension.getDefinition().getId(), dimension);
+
+ return this;
+
+ }
+
+ @Override
+ public Flux getDimensions() {
+ return Flux.fromIterable(dimensions.values());
+ }
+
+ @Override
+ public Mono getDimension(String id) {
+ return Mono.justOrEmpty(dimensions.get(id));
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/StaticMeasurementProvider.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/supports/StaticMeasurementProvider.java
new file mode 100644
index 00000000..595c6c91
--- /dev/null
+++ b/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 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 getMeasurements() {
+ return Flux.fromIterable(measurements.values());
+ }
+
+ @Override
+ public Mono getMeasurement(String id) {
+ return Mono.justOrEmpty(measurements.get(id));
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/DashboardController.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/DashboardController.java
new file mode 100644
index 00000000..bb4e9c13
--- /dev/null
+++ b/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 getDefinitions() {
+ return dashboardManager
+ .getDashboards()
+ .flatMap(DashboardInfo::of);
+ }
+
+ @GetMapping("/def/{dashboard}/{object}/measurements")
+ public Flux 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 getMeasurementValue(@PathVariable String dashboard,
+ @PathVariable String object,
+ @PathVariable String dimension,
+ @PathVariable String measurement,
+ @RequestParam Map 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 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)));
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/request/DashboardMeasurementRequest.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/request/DashboardMeasurementRequest.java
new file mode 100644
index 00000000..4f66eb00
--- /dev/null
+++ b/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 params;
+
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DashboardInfo.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DashboardInfo.java
new file mode 100644
index 00000000..6f951951
--- /dev/null
+++ b/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 objects;
+
+ public static Mono 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;
+ });
+
+ }
+
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DashboardMeasurementResponse.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DashboardMeasurementResponse.java
new file mode 100644
index 00000000..c56c7786
--- /dev/null
+++ b/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;
+
+
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DimensionInfo.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/DimensionInfo.java
new file mode 100644
index 00000000..9fb622cb
--- /dev/null
+++ b/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;
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/MeasurementInfo.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/MeasurementInfo.java
new file mode 100644
index 00000000..e280e27d
--- /dev/null
+++ b/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 dimensions;
+
+ public static Mono 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;
+ });
+ }
+}
diff --git a/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/ObjectInfo.java b/jetlinks-components/dashboard-components/src/main/java/org/jetlinks/community/dashboard/web/response/ObjectInfo.java
new file mode 100644
index 00000000..c97a1a9b
--- /dev/null
+++ b/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;
+ }
+
+}
diff --git a/jetlinks-components/pom.xml b/jetlinks-components/pom.xml
index 749571c8..17abc0f2 100644
--- a/jetlinks-components/pom.xml
+++ b/jetlinks-components/pom.xml
@@ -16,6 +16,8 @@
gateway-component
io-component
elasticsearch-component
+ timeseries-components
+ dashboard-components
jetlinks-components