This commit is contained in:
2025-11-28 16:23:32 +08:00
commit a9e0e16c29
826 changed files with 89805 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
<?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">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>BladeX-Tool</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<artifactId>blade-starter-mongo</artifactId>
<name>${project.artifactId}</name>
<version>${project.parent.version}</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-tool</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-auto</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,28 @@
package org.springblade.core.mongo.config;
import org.springblade.core.mongo.converter.DBObjectToJsonNodeConverter;
import org.springblade.core.mongo.converter.JsonNodeToDocumentConverter;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import java.util.ArrayList;
import java.util.List;
/**
* mongo 配置
*
* @author L.cm
*/
@AutoConfiguration
public class MongoConfiguration {
@Bean
public MongoCustomConversions customConversions() {
List<Converter<?,?>> converters = new ArrayList<>(2);
converters.add(DBObjectToJsonNodeConverter.INSTANCE);
converters.add(JsonNodeToDocumentConverter.INSTANCE);
return new MongoCustomConversions(converters);
}
}

View File

@@ -0,0 +1,30 @@
package org.springblade.core.mongo.converter;
import com.fasterxml.jackson.databind.JsonNode;
import org.bson.BasicBSONObject;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.lang.Nullable;
/**
* mongo DBObject 转 jsonNode
*
* @author L.cm
*/
@ReadingConverter
public enum DBObjectToJsonNodeConverter implements Converter<BasicBSONObject, JsonNode> {
/**
* 实例
*/
INSTANCE;
@Override
public JsonNode convert(@Nullable BasicBSONObject source) {
if (source == null) {
return null;
}
return JsonUtil.getInstance().valueToTree(source);
}
}

View File

@@ -0,0 +1,25 @@
package org.springblade.core.mongo.converter;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.bson.Document;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.WritingConverter;
import org.springframework.lang.Nullable;
/**
* JsonNode 转 mongo Document
*
* @author L.cm
*/
@WritingConverter
public enum JsonNodeToDocumentConverter implements Converter<ObjectNode, Document> {
/**
* 实例
*/
INSTANCE;
@Override
public Document convert(@Nullable ObjectNode source) {
return source == null ? null : Document.parse(source.toString());
}
}

View File

@@ -0,0 +1,85 @@
package org.springblade.core.mongo.utils;
import com.fasterxml.jackson.databind.JsonNode;
import lombok.Getter;
import org.springframework.util.Assert;
import java.util.LinkedList;
import java.util.StringJoiner;
/**
* json tree 节点信息
*
* @author L.cm
*/
public class JsonNodeInfo {
/**
* mongo keys: class1.class2.item
*/
private volatile String nodeKeys;
/**
* jsonPath语法/class1/class2/item
*/
private volatile String nodePath;
/**
* 节点关系
*/
@Getter
private final LinkedList<String> elements;
/**
* tree 的 叶子节点,此处为引用
*/
@Getter
private final JsonNode leafNode;
public JsonNodeInfo(LinkedList<String> elements, JsonNode leafNode) {
Assert.notNull(elements, "elements can not be null.");
this.nodeKeys = null;
this.nodePath = null;
this.elements = elements;
this.leafNode = leafNode;
}
/**
* 获取 mongo db的 key 语法
* @return mongo db的 key 语法
*/
public String getNodeKeys() {
if (nodeKeys == null) {
synchronized (this) {
if (nodeKeys == null) {
StringJoiner nodeKeysJoiner = new StringJoiner(".");
elements.forEach(nodeKeysJoiner::add);
nodeKeys = nodeKeysJoiner.toString();
}
}
}
return nodeKeys;
}
/**
* 获取 json path 语法路径
* @return jsonPath 路径
*/
public String getNodePath() {
if (nodePath == null) {
synchronized (this) {
if (nodePath == null) {
StringJoiner nodePathJoiner = new StringJoiner("/", "/", "");
elements.forEach(nodePathJoiner::add);
nodePath = nodePathJoiner.toString();
}
}
}
return nodePath;
}
/**
* 获取第一个元素
* @return element
*/
public String getFirst() {
return elements.getFirst();
}
}

View File

@@ -0,0 +1,126 @@
package org.springblade.core.mongo.utils;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import java.util.*;
/**
* 处理 mongo json 数据结构
*
* @author L.cm
*/
public class MongoJsonUtils {
/**
* 获取所有的叶子节点和路径信息
*
* @param jsonNode jsonTree
* @return tree叶子信息
*/
public static List<JsonNodeInfo> getLeafNodes(JsonNode jsonNode) {
if (jsonNode == null || !jsonNode.isObject()) {
return Collections.emptyList();
}
List<JsonNodeInfo> list = new ArrayList<>();
// 双向的队列 Deque 代替 StackStack 性能不好
LinkedList<String> deque = new LinkedList<>();
// 递归获取叶子 🍃🍃🍃 节点
getLeafNodes(jsonNode, null, deque, list);
return list;
}
private static void getLeafNodes(JsonNode jsonNode, JsonNode parentNode, LinkedList<String> deque, List<JsonNodeInfo> list) {
Iterator<Map.Entry<String, JsonNode>> iterator;
if (parentNode == null) {
iterator = jsonNode.fields();
} else {
iterator = parentNode.fields();
}
// tree 子节点
while (iterator.hasNext()) {
Map.Entry<String, JsonNode> entry = iterator.next();
String fieldName = entry.getKey();
JsonNode nextNode = entry.getValue();
// 如果不是值节点
if (nextNode.isObject()) {
// 添加到队列尾,先进先出
deque.addLast(fieldName);
getLeafNodes(parentNode, nextNode, deque, list);
}
// 如果是值节点,也就是到叶子节点了,取叶子节点上级即可
if (nextNode.isValueNode()) {
// 封装节点列表
LinkedList<String> elements = new LinkedList<>(deque);
// tree 的 叶子节点,此处为引用
list.add(new JsonNodeInfo(elements, parentNode));
break;
}
// 栈非空时弹出
if (!deque.isEmpty()) {
deque.removeLast();
}
}
}
/**
* 构建树形节点
*
* @param jsonNode 父级节点
* @param elements tree节点列表
* @return JsonNode 叶子节点,返回用于塞数据
*/
public static ObjectNode buildNode(ObjectNode jsonNode, List<String> elements) {
ObjectNode newNode = jsonNode;
for (String element : elements) {
// 如果已经存在节点,这不生成新的
if (newNode.has(element)) {
newNode = (ObjectNode) newNode.get(element);
} else {
newNode = newNode.putObject(element);
}
}
return newNode;
}
/**
* 获取所有 🍃🍃🍃 节点的值,并构建成 mongodb update 语句
* @param prefix 前缀
* @param nodeKeys mongo keys
* @param objectNode tree 🍃 节点
* @return tree 节点信息
*/
public static Map<String, Object> getAllUpdate(String prefix, String nodeKeys, ObjectNode objectNode) {
Map<String, Object> values = new HashMap<>(8);
Iterator<String> iterator = objectNode.fieldNames();
while (iterator.hasNext()) {
String fieldName = iterator.next();
JsonNode valueNode = objectNode.get(fieldName);
if (valueNode.isValueNode()) {
Object value;
if (valueNode.isShort()) {
value = valueNode.shortValue();
} else if (valueNode.isInt()) {
value = valueNode.intValue();
} else if (valueNode.isLong()) {
value = valueNode.longValue();
} else if (valueNode.isBoolean()) {
value = valueNode.booleanValue();
} else if (valueNode.isFloat()) {
value = valueNode.floatValue();
} else if (valueNode.isDouble()) {
value = valueNode.doubleValue();
} else if (valueNode.isMissingNode()) {
value = null;
} else {
value = valueNode.textValue();
}
if (value != null) {
String valueKey = prefix + '.' + nodeKeys + '.' + fieldName;
values.put(valueKey, value);
}
}
}
return values;
}
}