新增实时监控功能
左边是设备通道树,右边是分屏预览
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
package com.genersoft.iot.vmp.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class CollectionUtil {
|
||||
|
||||
public static <T> boolean contains(T[] array, final T element) {
|
||||
return array != null && Arrays.stream(array).anyMatch((x) -> {
|
||||
return ObjectUtils.nullSafeEquals(x, element);
|
||||
});
|
||||
}
|
||||
}
|
||||
41
src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java
Normal file
41
src/main/java/com/genersoft/iot/vmp/utils/ObjectUtils.java
Normal file
@@ -0,0 +1,41 @@
|
||||
package com.genersoft.iot.vmp.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
public class ObjectUtils {
|
||||
public static boolean nullSafeEquals(Object o1, Object o2) {
|
||||
if (o1 == o2) {
|
||||
return true;
|
||||
} else if (o1 != null && o2 != null) {
|
||||
if (o1.equals(o2)) {
|
||||
return true;
|
||||
} else {
|
||||
return o1.getClass().isArray() && o2.getClass().isArray() && arrayEquals(o1, o2);
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean arrayEquals(Object o1, Object o2) {
|
||||
if (o1 instanceof Object[] && o2 instanceof Object[]) {
|
||||
return Arrays.equals((Object[])((Object[])o1), (Object[])((Object[])o2));
|
||||
} else if (o1 instanceof boolean[] && o2 instanceof boolean[]) {
|
||||
return Arrays.equals((boolean[])((boolean[])o1), (boolean[])((boolean[])o2));
|
||||
} else if (o1 instanceof byte[] && o2 instanceof byte[]) {
|
||||
return Arrays.equals((byte[])((byte[])o1), (byte[])((byte[])o2));
|
||||
} else if (o1 instanceof char[] && o2 instanceof char[]) {
|
||||
return Arrays.equals((char[])((char[])o1), (char[])((char[])o2));
|
||||
} else if (o1 instanceof double[] && o2 instanceof double[]) {
|
||||
return Arrays.equals((double[])((double[])o1), (double[])((double[])o2));
|
||||
} else if (o1 instanceof float[] && o2 instanceof float[]) {
|
||||
return Arrays.equals((float[])((float[])o1), (float[])((float[])o2));
|
||||
} else if (o1 instanceof int[] && o2 instanceof int[]) {
|
||||
return Arrays.equals((int[])((int[])o1), (int[])((int[])o2));
|
||||
} else if (o1 instanceof long[] && o2 instanceof long[]) {
|
||||
return Arrays.equals((long[])((long[])o1), (long[])((long[])o2));
|
||||
} else {
|
||||
return o1 instanceof short[] && o2 instanceof short[] && Arrays.equals((short[]) ((short[]) o1), (short[]) ((short[]) o2));
|
||||
}
|
||||
}
|
||||
}
|
||||
54
src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
Normal file
54
src/main/java/com/genersoft/iot/vmp/utils/node/BaseNode.java
Normal file
@@ -0,0 +1,54 @@
|
||||
package com.genersoft.iot.vmp.utils.node;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 节点基类
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
public class BaseNode<T> implements INode<T> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 主键ID
|
||||
*/
|
||||
protected String id;
|
||||
|
||||
/**
|
||||
* 父节点ID
|
||||
*/
|
||||
protected String parentId;
|
||||
|
||||
/**
|
||||
* 子孙节点
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
protected List<T> children = new ArrayList<T>();
|
||||
|
||||
/**
|
||||
* 是否有子孙节点
|
||||
*/
|
||||
@JsonInclude(JsonInclude.Include.NON_EMPTY)
|
||||
private Boolean hasChildren;
|
||||
|
||||
/**
|
||||
* 是否有子孙节点
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
@Override
|
||||
public Boolean getHasChildren() {
|
||||
if (children.size() > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return this.hasChildren;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.genersoft.iot.vmp.utils.node;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
|
||||
/**
|
||||
* 森林节点类
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class ForestNode extends BaseNode<ForestNode> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 节点内容
|
||||
*/
|
||||
private Object content;
|
||||
|
||||
public ForestNode(String id, String parentId, Object content) {
|
||||
this.id = id;
|
||||
this.parentId = parentId;
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.genersoft.iot.vmp.utils.node;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 森林管理类
|
||||
*
|
||||
* @author smallchill
|
||||
*/
|
||||
public class ForestNodeManager<T extends INode<T>> {
|
||||
|
||||
/**
|
||||
* 森林的所有节点
|
||||
*/
|
||||
private final ImmutableMap<String, T> nodeMap;
|
||||
|
||||
/**
|
||||
* 森林的父节点ID
|
||||
*/
|
||||
private final Map<String, Object> parentIdMap = Maps.newHashMap();
|
||||
|
||||
public ForestNodeManager(List<T> nodes) {
|
||||
nodeMap = Maps.uniqueIndex(nodes, INode::getId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据节点ID获取一个节点
|
||||
*
|
||||
* @param id 节点ID
|
||||
* @return 对应的节点对象
|
||||
*/
|
||||
public INode<T> getTreeNodeAt(String id) {
|
||||
if (nodeMap.containsKey(id)) {
|
||||
return nodeMap.get(id);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加父节点ID
|
||||
*
|
||||
* @param parentId 父节点ID
|
||||
*/
|
||||
public void addParentId(String parentId) {
|
||||
parentIdMap.put(parentId, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取树的根节点(一个森林对应多颗树)
|
||||
*
|
||||
* @return 树的根节点集合
|
||||
*/
|
||||
public List<T> getRoot() {
|
||||
List<T> roots = new ArrayList<>();
|
||||
nodeMap.forEach((key, node) -> {
|
||||
if (node.getParentId() == null || parentIdMap.containsKey(node.getId())) {
|
||||
roots.add(node);
|
||||
}
|
||||
});
|
||||
return roots;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.genersoft.iot.vmp.utils.node;
|
||||
|
||||
import com.genersoft.iot.vmp.utils.CollectionUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 森林节点归并类
|
||||
*
|
||||
*/
|
||||
public class ForestNodeMerger {
|
||||
|
||||
/**
|
||||
* 将节点数组归并为一个森林(多棵树)(填充节点的children域)
|
||||
* 时间复杂度为O(n^2)
|
||||
*
|
||||
* @param items 节点域
|
||||
* @return 多棵树的根节点集合
|
||||
*/
|
||||
public static <T extends INode<T>> List<T> merge(List<T> items) {
|
||||
ForestNodeManager<T> forestNodeManager = new ForestNodeManager<>(items);
|
||||
items.forEach(forestNode -> {
|
||||
if (forestNode.getParentId() != null) {
|
||||
INode<T> node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());
|
||||
if (node != null) {
|
||||
node.getChildren().add(forestNode);
|
||||
} else {
|
||||
forestNodeManager.addParentId(forestNode.getId());
|
||||
}
|
||||
}
|
||||
});
|
||||
return forestNodeManager.getRoot();
|
||||
}
|
||||
|
||||
public static <T extends INode<T>> List<T> merge(List<T> items, String[] parentIds) {
|
||||
ForestNodeManager<T> forestNodeManager = new ForestNodeManager<>(items);
|
||||
items.forEach(forestNode -> {
|
||||
if (forestNode.getParentId() != null) {
|
||||
INode<T> node = forestNodeManager.getTreeNodeAt(forestNode.getParentId());
|
||||
if (CollectionUtil.contains(parentIds, forestNode.getId())){
|
||||
forestNodeManager.addParentId(forestNode.getId());
|
||||
} else {
|
||||
if (node != null){
|
||||
node.getChildren().add(forestNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return forestNodeManager.getRoot();
|
||||
}
|
||||
}
|
||||
42
src/main/java/com/genersoft/iot/vmp/utils/node/INode.java
Normal file
42
src/main/java/com/genersoft/iot/vmp/utils/node/INode.java
Normal file
@@ -0,0 +1,42 @@
|
||||
package com.genersoft.iot.vmp.utils.node;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* 节点
|
||||
*/
|
||||
public interface INode<T> extends Serializable {
|
||||
|
||||
/**
|
||||
* 主键
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* 父主键
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String getParentId();
|
||||
|
||||
/**
|
||||
* 子孙节点
|
||||
*
|
||||
* @return List<T>
|
||||
*/
|
||||
List<T> getChildren();
|
||||
|
||||
/**
|
||||
* 是否有子孙节点
|
||||
*
|
||||
* @return Boolean
|
||||
*/
|
||||
default Boolean getHasChildren() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
21
src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
Normal file
21
src/main/java/com/genersoft/iot/vmp/utils/node/TreeNode.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package com.genersoft.iot.vmp.utils.node;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* 树型节点类
|
||||
*
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
public class TreeNode extends BaseNode<TreeNode> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String title;
|
||||
|
||||
private String key;
|
||||
|
||||
private String value;
|
||||
}
|
||||
Reference in New Issue
Block a user