import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
* 解析Json 创建表结构
*/
@Service
public class JsonService {
/**
* 根据Json返回字符串创建表语句
* @param jsonParam
* @return
*/
public String createTableSqlByJson(String jsonParam) {
List<JsonMapper> analysisResult = analysisJson(jsonParam);
if (CollectionUtils.isNotEmpty(analysisResult)) {
//Map<String, List<JsonMapper>> mapperByParentName = analysisResult.stream().collect(Collectors.groupingBy(JsonMapper::getParentName));
Map<String, List<String>> mapperByParentName = analysisResult.stream().collect(Collectors.groupingBy(JsonMapper::getParentName,
Collectors.mapping(JsonMapper::getCurrName, Collectors.toList())));
Iterator iterator = mapperByParentName.entrySet().iterator();
String sql = "";
while (iterator.hasNext()) {
Map.Entry entry = (Map.Entry) iterator.next();
sql = sql + createSql(entry.getKey().toString(), (List<String>) entry.getValue());
}
return sql;
}
return null;
}
/**
* Jackson 解析json
* @param jsonParam
* @return
*/
public List<JsonMapper> analysisJson(String jsonParam) {
try {
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNodeRoot = mapper.readTree(jsonParam);
List<JsonMapper> tableMapper = new ArrayList<>();
List<JsonMapper> fieldMapper = new ArrayList<>();
recursiveAnalysis(tableMapper, fieldMapper, "rootJson",jsonNodeRoot);
// 表与表之间
if (CollectionUtils.isNotEmpty(tableMapper)) {
// 合并
fieldMapper.addAll(tableMapper);
/*for (JsonMapper jsonMapper : tableMapper){
System.out.println(jsonMapper.getParentName() + "===111===" +jsonMapper.getCurrName());
}*/
}
// 属性与表之间
if (CollectionUtils.isNotEmpty(fieldMapper)) {
// 去重
List<JsonMapper> fieldMapperAfter = fieldMapper.stream().collect(Collectors.collectingAndThen(
Collectors.toCollection(() -> new TreeSet<>(
Comparator.comparing(o -> o.getParentName() + ";" + o.getCurrName()))), ArrayList::new));
// 排序
Collections.sort(fieldMapperAfter, new Comparator<JsonMapper>(){
public int compare(JsonMapper o1, JsonMapper o2) {
return o1.getParentName().compareTo(o2.getParentName());// 按照父节点升序
}
});
/*for (JsonMapper jsonMapper : fieldMapperAfter){
System.out.println(jsonMapper.getParentName() + "======" +jsonMapper.getCurrName());
}*/
return fieldMapperAfter;
}
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* Jackson 递归解析子节点
* @param tableMapper 表与表之间关联映射
* @param fieldMapper 字段属性与表之间关联映射
* @param parentNodeName 父节点名称
* @param jsonNode 当前节点
*/
public void recursiveAnalysis(List<JsonMapper> tableMapper,List<JsonMapper> fieldMapper, String parentNodeName,JsonNode jsonNode) {
if (jsonNode.isContainerNode()){
if (JsonNodeType.OBJECT == jsonNode.getNodeType()) {
Iterator<String> fieldNames = jsonNode.fieldNames();
while (fieldNames.hasNext()) {
String fieldName = fieldNames.next();
if (jsonNode.get(fieldName).isContainerNode()){
//System.out.println("父对象:" +parentNodeName +"当前对象的名称:" + fieldName);
tableMapper.add(new JsonMapper(parentNodeName, fieldName));
recursiveAnalysis(tableMapper, fieldMapper, fieldName, jsonNode.get(fieldName));
} else {
//System.out.println("父属性:" +parentNodeName +"当前属性的名称:" +fieldName + "===" + jsonNode.get(fieldName).getNodeType());
fieldMapper.add(new JsonMapper(parentNodeName, fieldName + ":" + jsonNode.get(fieldName).getNodeType()));
}
}
} else if (JsonNodeType.ARRAY == jsonNode.getNodeType()) {
Iterator<JsonNode> jsonNodeElements = jsonNode.iterator();
while (jsonNodeElements.hasNext()) {
JsonNode jsonNodeElement = jsonNodeElements.next();
recursiveAnalysis(tableMapper, fieldMapper, parentNodeName, jsonNodeElement);
}
}
}
}
/**
* 获取创建表前缀,根据拆分表数字
* @param tableName
* @param splitNum
* @return
*/
public String getTablePrefix(String tableName, int splitNum) {
if (splitNum > 0) {
tableName = tableName + "_" + splitNum;
}
StringBuilder tablePrefix = new StringBuilder();
tablePrefix.append("CREATE TABLE `"+tableName+"` ( \r\n");
tablePrefix.append(" `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键', \r\n");
tablePrefix.append(" `orders_id` INT(11) NOT NULL COMMENT '订单ID', \r\n");
tablePrefix.append(" `user_id` INT(11) DEFAULT NULL, \r\n");
return tablePrefix.toString();
}
/**
* 获取创建表后缀
* @param tableName
* @return
*/
public String getTableSuffix(String tableName) {
StringBuilder tableSuffix = new StringBuilder();
tableSuffix.append(" `create_time` DATETIME DEFAULT NULL, \r\n");
tableSuffix.append("PRIMARY KEY (`id`), \r\n");
tableSuffix.append("KEY `index_user_id` (`user_id`) USING BTREE \r\n");
tableSuffix.append(") ENGINE=InnoDB DEFAULT CHARSET=UTF8; \r\n");
tableSuffix.append(" \r\n");
return tableSuffix.toString();
}
/**
* 根据表名以及列名称创建表结构
* @param tableName
* @param columnNames
* @return
*/
public String createSql(String tableName, List<String> columnNames) {
boolean isSplit = isSplitToTables(columnNames.size());
StringBuilder sqlAll = new StringBuilder();
sqlAll.append(getTablePrefix(tableName, 0));
for (int i = 0; i < columnNames.size(); i++) {
if (columnNames.get(i).contains(":")) {
String str[] = columnNames.get(i).split(":");
String columnType = buildColumnType(str[1]);
sqlAll.append(" `"+str[0]+"` "+columnType+" DEFAULT NULL, \r\n");
}else {
sqlAll.append(" `"+columnNames.get(i)+"` LONGTEXT DEFAULT NULL, \r\n");
}
if (isSplit) {
if (i > 0 && i % 50 == 0) {
sqlAll.append(getTableSuffix(tableName));
sqlAll.append(getTablePrefix(tableName, i / 50));
}
}
}
sqlAll.append(getTableSuffix(tableName));
return sqlAll.toString();
}
/**
* 根据json 字段类型构建数据库字段类型
* 默认 varchar(20)
* @param jsonType
*/
public String buildColumnType(String jsonType) {
if (JsonNodeType.BOOLEAN.toString().equals(jsonType)) {
return "CHAR(1)";
} else if (JsonNodeType.NUMBER.toString().equals(jsonType)) {
if (jsonType.contains(".")) {
return "VARCHAR(20)";
}
return "INT(11)";
} else if (JsonNodeType.STRING.toString().equals(jsonType)) {
return "VARCHAR(100)";
} else {
return "VARCHAR(20)";
}
}
/**
* 根据表的列数判断是否需要拆分字段到多个表
* 当字段 > 80 时,自动创建多表,多表采用单表 50个字段进行分拆
* @param columns
* @return
*/
public boolean isSplitToTables(int columns){
if (columns >= 80) {
return true;
}
return false;
}
}@Data
public class JsonMapper implements Serializable {
private String parentName;
private String currName;
public JsonMapper(String parentName, String currName) {
this.parentName = parentName;
this.currName =currName;
}
}