Commit aa84ce70 by 独孤求胜 Committed by Gitee

!7 增加了支持Mongo的功能 同时解决了选用其他数据库的mongo自动获取连接的问题

Merge pull request !7 from 龚宣璋/master
parents d1face53 1c9a8cd0
<?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">
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>
<groupId>io.renren</groupId>
<artifactId>renren-generator</artifactId>
......@@ -29,6 +29,7 @@
<mysql.version>8.0.17</mysql.version>
<mssql.version>4.0</mssql.version>
<oracle.version>11.2.0.3</oracle.version>
<mongo.version>3.11.0</mongo.version>
</properties>
<dependencies>
......@@ -120,6 +121,12 @@
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
</dependency>
<!-- mongo驱动 -->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>${mongo.version}</version>
</dependency>
</dependencies>
<build>
......
......@@ -3,8 +3,10 @@ package io.renren;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
@SpringBootApplication
@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
@MapperScan("io.renren.dao")
public class RenrenApplication {
......
package io.renren.adaptor;
import io.renren.entity.mongo.MongoDefinition;
import io.renren.entity.mongo.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* mongo适配器
*
* @author: gxz gongxuanzhang@foxmail.com
**/
public class MongoTableInfoAdaptor {
/**
* 查询表信息的时候 mongo只能获得表名 其他只能手动填写
*
* @param names 表名
*/
public static List<Map<String, String>> tableInfo(List<String> names) {
List<Map<String, String>> result = new ArrayList<>(names.size());
for (String name : names) {
result.add(tableInfo(name));
}
return result;
}
public static Map<String, String> tableInfo(String name) {
Map<String, String> tableInfo = new HashMap<>(4 * 4 / 3 + 1);
tableInfo.put("engine", "mongo无引擎");
tableInfo.put("createTime", "mongo无法查询创建时间");
tableInfo.put("tableComment", "mongo无备注");
tableInfo.put("tableName", name);
return tableInfo;
}
/**
* 在查询列名的时候 需要将解析出的mongo信息适配成关系型数据库所需要的信息形式
* 此方法只针对主Bean
*/
public static List<Map<String, String>> columnInfo(MongoDefinition mongoDefinition) {
List<MongoDefinition> child = mongoDefinition.getChild();
List<Map<String, String>> result = new ArrayList<>(child.size());
final String mongoKey = "_id";
for (MongoDefinition definition : child) {
Map<String, String> map = new HashMap<>(5 * 4 / 3 + 1);
String type = Type.typeInfo(definition.getType());
String propertyName = definition.getPropertyName();
String extra = definition.isArray() ? "array" : "";
map.put("extra", extra);
map.put("columnComment", "");
map.put("dataType", definition.hasChild() ? propertyName : type);
map.put("columnName", propertyName);
// mongo默认主键是_id
String columnKey = propertyName.equals(mongoKey) ? "PRI" : "";
map.put("columnKey", columnKey);
result.add(map);
}
return result;
}
}
/**
* Copyright (c) 2018 人人开源 All rights reserved.
*
* <p>
* https://www.renren.io
*
* <p>
* 版权所有,侵权必究!
*/
......@@ -13,6 +13,7 @@ import io.renren.utils.RRException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
......@@ -34,19 +35,35 @@ public class DbConfig {
@Autowired
private PostgreSQLGeneratorDao postgreSQLGeneratorDao;
private static boolean mongo = false;
@Bean
@Primary
public GeneratorDao getGeneratorDao(){
if("mysql".equalsIgnoreCase(database)){
@Conditional(MongoNullCondition.class)
public GeneratorDao getGeneratorDao() {
if ("mysql".equalsIgnoreCase(database)) {
return mySQLGeneratorDao;
}else if("oracle".equalsIgnoreCase(database)){
} else if ("oracle".equalsIgnoreCase(database)) {
return oracleGeneratorDao;
}else if("sqlserver".equalsIgnoreCase(database)){
} else if ("sqlserver".equalsIgnoreCase(database)) {
return sqlServerGeneratorDao;
}else if("postgresql".equalsIgnoreCase(database)){
} else if ("postgresql".equalsIgnoreCase(database)) {
return postgreSQLGeneratorDao;
}else {
} else {
throw new RRException("不支持当前数据库:" + database);
}
}
@Bean
@Primary
@Conditional(MongoCondition.class)
public GeneratorDao getMongoDBDao(MongoDBGeneratorDao mongoDBGeneratorDao) {
mongo = true;
return mongoDBGeneratorDao;
}
public static boolean isMongo() {
return mongo;
}
}
package io.renren.config;
import org.apache.commons.lang.StringUtils;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author: gxz gongxuanzhang@foxmail.com
**/
public class MongoCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String database = context.getEnvironment().getProperty("renren.database");
return "mongodb".equalsIgnoreCase(database);
}
}
package io.renren.config;
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDatabase;
import io.renren.factory.MongoDBCollectionFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author: gxz gongxuanzhang@foxmail.com
**/
@Component
@ConfigurationProperties(prefix = "mongodb")
public class MongoConfig {
private String host;
private int port;
private String username;
private String password;
private String dataBase;
private boolean auth;
private String source;
@Bean
@Conditional(MongoCondition.class)
private MongoClient getMongoClient() {
List<ServerAddress> adds = new ArrayList<>();
ServerAddress serverAddress = new ServerAddress(this.host, this.port);
adds.add(serverAddress);
if (this.auth) {
MongoCredential mongoCredential = MongoCredential.
createScramSha1Credential(this.username, this.source, this.password.toCharArray());
MongoClientOptions mongoClientOptions = MongoClientOptions.builder().build();
return new MongoClient(adds, mongoCredential, mongoClientOptions);
}
return new MongoClient(adds);
}
@Bean
@Conditional(MongoCondition.class)
public MongoDatabase getDataBase() {
return getMongoClient().getDatabase(dataBase);
}
public MongoConfig setHost(String host) {
this.host = host;
return this;
}
public MongoConfig setPort(int port) {
this.port = port;
return this;
}
public MongoConfig setUsername(String username) {
this.username = username;
return this;
}
public MongoConfig setPassword(String password) {
this.password = password;
return this;
}
public MongoConfig setDataBase(String dataBase) {
this.dataBase = dataBase;
return this;
}
public MongoConfig setAuth(boolean auth) {
this.auth = auth;
return this;
}
public MongoConfig setSource(String source) {
this.source = source;
return this;
}
}
package io.renren.config;
import io.renren.entity.mongo.MongoDefinition;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author gxz
* @date 2020/5/10 12:05
*/
public class MongoManager {
/***mongo扫描很消耗性能 尤其是子类的封装 使用缓存**/
private static Map<String, MongoDefinition> mongoCache = new ConcurrentHashMap<>();
public static Map<String, MongoDefinition> getCache() {
return mongoCache;
}
public static MongoDefinition getInfo(String tableName) {
return mongoCache.getOrDefault(tableName, null);
}
public static MongoDefinition putInfo(String tableName, MongoDefinition mongoDefinition) {
return mongoCache.put(tableName, mongoDefinition);
}
/**
* 当前配置是否为mongo内容
*/
public static boolean isMongo() {
return DbConfig.isMongo();
}
}
package io.renren.config;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author: gxz gongxuanzhang@foxmail.com
**/
public class MongoNullCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String database = context.getEnvironment().getProperty("renren.database");
return !"mongodb".equalsIgnoreCase(database);
}
}
package io.renren.dao;
import io.renren.adaptor.MongoTableInfoAdaptor;
import io.renren.config.MongoCondition;
import io.renren.config.MongoManager;
import io.renren.entity.mongo.MongoDefinition;
import io.renren.factory.MongoDBCollectionFactory;
import io.renren.utils.MongoScanner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author: gxz gongxuanzhang@foxmail.com
**/
@Repository
@Conditional(MongoCondition.class)
public class MongoDBGeneratorDao implements GeneratorDao {
@Autowired
private MongoDBCollectionFactory mongoDBCollectionFactory;
@Override
public List<Map<String, Object>> queryList(Map<String, Object> map) {
List<String> collectionNames = MongoDBCollectionFactory.getCollectionNames(map);
return (List) MongoTableInfoAdaptor.tableInfo(collectionNames);
}
@Override
public Map<String, String> queryTable(String tableName) {
Map<String, String> result = new HashMap<>(4 * 4 / 3 + 1);
result.put("engine", "");
result.put("createTime", "");
result.put("tableComment", "mongoDB " + tableName);
result.put("tableName", tableName);
return result;
}
@Override
public List<Map<String, String>> queryColumns(String tableName) {
MongoDefinition mongoDefinition = MongoManager.getInfo(tableName);
if (mongoDefinition == null) {
System.out.println(tableName);
MongoScanner mongoScanner = new MongoScanner(mongoDBCollectionFactory.getCollection(tableName));
mongoDefinition = mongoScanner.getProduct();
}
return MongoTableInfoAdaptor.columnInfo(mongoDefinition);
}
}
package io.renren.entity.mongo;
import io.renren.adaptor.MongoTableInfoAdaptor;
import org.apache.commons.collections.CollectionUtils;
import java.io.Serializable;
import java.util.*;
/**
* 解析表之后得到的信息实体
* 换句话说这个类就是一张mongo一张表的内容
*
* @author gxz 514190950@qq.com
*/
public class MongoDefinition implements Serializable {
/***属性名**/
private String propertyName;
/***属性类型 对应mongodb api $type 如果没有类型 表示这是一个顶层实体 而不是内嵌属性**/
private Integer type;
/***此属性是否是数组**/
private boolean array = false;
/***如果此属性是对象 那么他仍然有此类型的子类**/
private List<MongoDefinition> child;
public List<MongoGeneratorEntity> getChildrenInfo(String tableName) {
List<MongoGeneratorEntity> result = new ArrayList<>();
MongoGeneratorEntity info = new MongoGeneratorEntity();
// 表信息
Map<String, String> tableInfo = MongoTableInfoAdaptor.tableInfo(tableName);
// 列名信息
List<Map<String, String>> columnsInfo = new ArrayList<>();
info.setColumns(columnsInfo);
info.setTableInfo(tableInfo);
result.add(info);
List<MongoDefinition> child = this.getChild();
for (MongoDefinition mongoDefinition : child) {
Map<String, String> columnInfo = new HashMap<>(5);
columnInfo.put("columnName", mongoDefinition.getPropertyName());
columnInfo.put("dataType", Type.typeInfo(mongoDefinition.getType()));
columnInfo.put("extra", mongoDefinition.isArray() ? "array" : "");
columnsInfo.add(columnInfo);
if (mongoDefinition.hasChild()) {
result.addAll(mongoDefinition.getChildrenInfo(mongoDefinition.getPropertyName()));
}
}
return result;
}
public boolean hasChild() {
final int objectType = 3;
return type == null || Objects.equals(type, objectType) || CollectionUtils.isNotEmpty(child);
}
public boolean primaryBean() {
return type == null;
}
public MongoDefinition setType(Integer type) {
this.type = type;
return this;
}
public String getPropertyName() {
return propertyName;
}
public MongoDefinition setPropertyName(String propertyName) {
this.propertyName = propertyName;
return this;
}
public Integer getType() {
return type;
}
public boolean isArray() {
return array;
}
public MongoDefinition setArray(boolean array) {
this.array = array;
return this;
}
public List<MongoDefinition> getChild() {
return child;
}
public MongoDefinition setChild(List<MongoDefinition> child) {
this.child = child;
return this;
}
}
package io.renren.entity.mongo;
import io.renren.entity.TableEntity;
import java.util.List;
import java.util.Map;
/**
* mysql一张表只需要一个表信息和列名信息
* 但是mongo一张表可能需要多个实体类 所以单独用一个bean封装
*
* @author gxz
* @date 2020/5/10 0:14
*/
public class MongoGeneratorEntity {
/***表信息**/
private Map<String, String> tableInfo;
/***主类的列名信息**/
private List<Map<String, String>> columns;
public TableEntity toTableEntity() {
TableEntity tableEntity = new TableEntity();
Map<String, String> tableInfo = this.tableInfo;
tableEntity.setTableName(tableInfo.get("tableName"));
tableEntity.setComments("");
return tableEntity;
}
public Map<String, String> getTableInfo() {
return tableInfo;
}
public MongoGeneratorEntity setTableInfo(Map<String, String> tableInfo) {
this.tableInfo = tableInfo;
return this;
}
public List<Map<String, String>> getColumns() {
return columns;
}
public MongoGeneratorEntity setColumns(List<Map<String, String>> columns) {
this.columns = columns;
return this;
}
}
package io.renren.entity.mongo;
import java.util.Objects;
public enum Type {
/***
* 类型 和对应mongodb api 的$type的数字
**/
varchar(2),
NUMBER(16),
bigint(18),
OBJECT(3),
ARRAY(4),
date(9),
bit(8),
DOUBLE(1);
private final int num;
Type(int num) {
this.num = num;
}
public static String typeInfo(int num) {
Type[] values = values();
for (Type value : values) {
if (Objects.equals(num, value.num)) {
return value.toString();
}
}
return null;
}
}
package io.renren.factory;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
import io.renren.config.MongoCondition;
import org.bson.Document;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @author: gxz gongxuanzhang@foxmail.com
**/
@Component
@Conditional(MongoCondition.class)
public class MongoDBCollectionFactory {
private static final String TABLE_NAME_KEY = "tableName";
private static final String LIMIT_KEY = "limit";
private static final String OFFSET_KEY = "offset";
private static MongoDatabase mongoDatabase;
// 此处是为了兼容mongo相关内容和关系型数据库的静态耦合所导致的问题
@Autowired
private MongoDatabase database;
@PostConstruct
public void initMongoDatabase(){
mongoDatabase = database;
}
/***
* 通过表名获得查询对象
* @author gxz
* @date 2020/5/9
* @param collectionName mongo的集合名(表名)
* @return 连接查询对象
**/
public MongoCollection<Document> getCollection(String collectionName) {
return mongoDatabase.getCollection(collectionName);
}
/***
* 获得当前数据库的集合名称
* 注: mongo相对关系型数据库较为特殊,查询表名无法分页,用stream实现
* @author gxz
* @date 2020/5/9
* @param map 这是查询条件 和关系型数据库一致
* @return 集合名称
**/
public static List<String> getCollectionNames(Map<String, Object> map) {
int limit = Integer.valueOf(map.get(LIMIT_KEY).toString());
int skip = Integer.valueOf(map.get(OFFSET_KEY).toString());
List<String> names;
if (map.containsKey(TABLE_NAME_KEY)) {
names = getCollectionNames(map.get(TABLE_NAME_KEY).toString());
} else {
names = getCollectionNames();
}
return names.stream().skip(skip).limit(limit).collect(Collectors.toList());
}
/***
* 获得集合名称总数(表的数量) 为了适配MyBatisPlus的分页插件 提供方法
* @author gxz
* @date 2020/5/9
* @param map 这是查询条件 和关系型数据库一致
* @return int
**/
public static int getCollectionTotal(Map<String, Object> map) {
if (map.containsKey(TABLE_NAME_KEY)) {
return getCollectionNames(map.get(TABLE_NAME_KEY).toString()).size();
}
return getCollectionNames().size();
}
private static List<String> getCollectionNames() {
MongoIterable<String> names = mongoDatabase.listCollectionNames();
List<String> result = new ArrayList<>();
for (String name : names) {
result.add(name);
}
return result;
}
private static List<String> getCollectionNames(String likeName) {
return getCollectionNames()
.stream()
.filter((name) -> name.contains(likeName)).collect(Collectors.toList());
}
}
/**
* Copyright (c) 2018 人人开源 All rights reserved.
*
* <p>
* https://www.renren.io
*
* <p>
* 版权所有,侵权必究!
*/
......@@ -10,7 +10,11 @@ package io.renren.service;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.renren.config.MongoManager;
import io.renren.dao.GeneratorDao;
import io.renren.dao.MongoDBGeneratorDao;
import io.renren.entity.mongo.MongoDefinition;
import io.renren.factory.MongoDBCollectionFactory;
import io.renren.utils.GenUtils;
import io.renren.utils.PageUtils;
import io.renren.utils.Query;
......@@ -25,42 +29,51 @@ import java.util.zip.ZipOutputStream;
/**
* 代码生成器
*
*
* @author Mark sunlightcs@gmail.com
*/
@Service
public class SysGeneratorService {
@Autowired
private GeneratorDao generatorDao;
@Autowired
private GeneratorDao generatorDao;
public PageUtils queryList(Query query) {
Page<?> page = PageHelper.startPage(query.getPage(), query.getLimit());
List<Map<String, Object>> list = generatorDao.queryList(query);
int total = (int) page.getTotal();
if (generatorDao instanceof MongoDBGeneratorDao) {
total = MongoDBCollectionFactory.getCollectionTotal(query);
}
return new PageUtils(list, total, query.getLimit(), query.getPage());
}
public PageUtils queryList(Query query) {
Page<?> page = PageHelper.startPage(query.getPage(), query.getLimit());
List<Map<String, Object>> list = generatorDao.queryList(query);
public Map<String, String> queryTable(String tableName) {
return generatorDao.queryTable(tableName);
}
return new PageUtils(list, (int)page.getTotal(), query.getLimit(), query.getPage());
}
public List<Map<String, String>> queryColumns(String tableName) {
return generatorDao.queryColumns(tableName);
}
public Map<String, String> queryTable(String tableName) {
return generatorDao.queryTable(tableName);
}
public List<Map<String, String>> queryColumns(String tableName) {
return generatorDao.queryColumns(tableName);
}
public byte[] generatorCode(String[] tableNames) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
for (String tableName : tableNames) {
//查询表信息
Map<String, String> table = queryTable(tableName);
//查询列信息
List<Map<String, String>> columns = queryColumns(tableName);
//生成代码
GenUtils.generatorCode(table, columns, zip);
}
if (MongoManager.isMongo()) {
GenUtils.generatorMongoCode(tableNames, zip);
}
public byte[] generatorCode(String[] tableNames) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ZipOutputStream zip = new ZipOutputStream(outputStream);
for(String tableName : tableNames){
//查询表信息
Map<String, String> table = queryTable(tableName);
//查询列信息
List<Map<String, String>> columns = queryColumns(tableName);
//生成代码
GenUtils.generatorCode(table, columns, zip);
}
IOUtils.closeQuietly(zip);
return outputStream.toByteArray();
}
IOUtils.closeQuietly(zip);
return outputStream.toByteArray();
}
}
package io.renren.utils;
import io.renren.config.MongoManager;
import io.renren.entity.ColumnEntity;
import io.renren.entity.TableEntity;
import io.renren.entity.mongo.MongoDefinition;
import io.renren.entity.mongo.MongoGeneratorEntity;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
......@@ -28,19 +31,35 @@ import java.util.zip.ZipOutputStream;
*/
public class GenUtils {
public static List<String> getTemplates(){
private static String currentTableName;
public static List<String> getTemplates() {
List<String> templates = new ArrayList<String>();
templates.add("template/Entity.java.vm");
templates.add("template/Dao.java.vm");
templates.add("template/Dao.xml.vm");
templates.add("template/menu.sql.vm");
templates.add("template/Service.java.vm");
templates.add("template/ServiceImpl.java.vm");
templates.add("template/Controller.java.vm");
templates.add("template/menu.sql.vm");
templates.add("template/Dao.java.vm");
templates.add("template/index.vue.vm");
templates.add("template/add-or-update.vue.vm");
if (MongoManager.isMongo()) {
// mongo不需要mapper、sql 实体类需要替换
templates.remove(0);
templates.remove(1);
templates.remove(2);
templates.add("template/MongoEntity.java.vm");
}
return templates;
}
public static List<String> getMongoChildTemplates() {
List<String> templates = new ArrayList<String>();
templates.add("template/MongoChildrenEntity.java.vm");
return templates;
}
......@@ -52,10 +71,11 @@ public class GenUtils {
//配置信息
Configuration config = getConfig();
boolean hasBigDecimal = false;
boolean hasList = false;
//表信息
TableEntity tableEntity = new TableEntity();
tableEntity.setTableName(table.get("tableName" ));
tableEntity.setComments(table.get("tableComment" ));
tableEntity.setTableName(table.get("tableName"));
tableEntity.setComments(table.get("tableComment"));
//表名转换成Java类名
String className = tableToJava(tableEntity.getTableName(), config.getStringArray("tablePrefix"));
tableEntity.setClassName(className);
......@@ -63,12 +83,12 @@ public class GenUtils {
//列信息
List<ColumnEntity> columsList = new ArrayList<>();
for(Map<String, String> column : columns){
for (Map<String, String> column : columns) {
ColumnEntity columnEntity = new ColumnEntity();
columnEntity.setColumnName(column.get("columnName" ));
columnEntity.setDataType(column.get("dataType" ));
columnEntity.setComments(column.get("columnComment" ));
columnEntity.setExtra(column.get("extra" ));
columnEntity.setColumnName(column.get("columnName"));
columnEntity.setDataType(column.get("dataType"));
columnEntity.setComments(column.get("columnComment"));
columnEntity.setExtra(column.get("extra"));
//列名转换成Java属性名
String attrName = columnToJava(columnEntity.getColumnName());
......@@ -76,13 +96,18 @@ public class GenUtils {
columnEntity.setAttrname(StringUtils.uncapitalize(attrName));
//列的数据类型,转换成Java类型
String attrType = config.getString(columnEntity.getDataType(), "unknowType" );
String attrType = config.getString(columnEntity.getDataType(), columnToJava(columnEntity.getDataType()));
columnEntity.setAttrType(attrType);
if (!hasBigDecimal && attrType.equals("BigDecimal" )) {
if (!hasBigDecimal && attrType.equals("BigDecimal")) {
hasBigDecimal = true;
}
if (!hasList && "array".equals(columnEntity.getExtra())) {
hasList = true;
}
//是否主键
if ("PRI".equalsIgnoreCase(column.get("columnKey" )) && tableEntity.getPk() == null) {
if ("PRI".equalsIgnoreCase(column.get("columnKey")) && tableEntity.getPk() == null) {
tableEntity.setPk(columnEntity);
}
......@@ -97,9 +122,9 @@ public class GenUtils {
//设置velocity资源加载器
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" );
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
String mainPath = config.getString("mainPath" );
String mainPath = config.getString("mainPath");
mainPath = StringUtils.isBlank(mainPath) ? "io.renren" : mainPath;
//封装模板数据
Map<String, Object> map = new HashMap<>();
......@@ -111,11 +136,12 @@ public class GenUtils {
map.put("pathName", tableEntity.getClassname().toLowerCase());
map.put("columns", tableEntity.getColumns());
map.put("hasBigDecimal", hasBigDecimal);
map.put("hasList", hasList);
map.put("mainPath", mainPath);
map.put("package", config.getString("package" ));
map.put("moduleName", config.getString("moduleName" ));
map.put("author", config.getString("author" ));
map.put("email", config.getString("email" ));
map.put("package", config.getString("package"));
map.put("moduleName", config.getString("moduleName"));
map.put("author", config.getString("author"));
map.put("email", config.getString("email"));
map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
VelocityContext context = new VelocityContext(map);
......@@ -124,13 +150,13 @@ public class GenUtils {
for (String template : templates) {
//渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, "UTF-8" );
Template tpl = Velocity.getTemplate(template, "UTF-8");
tpl.merge(context, sw);
try {
//添加到zip
zip.putNextEntry(new ZipEntry(getFileName(template, tableEntity.getClassName(), config.getString("package" ), config.getString("moduleName" ))));
IOUtils.write(sw.toString(), zip, "UTF-8" );
zip.putNextEntry(new ZipEntry(getFileName(template, tableEntity.getClassName(), config.getString("package"), config.getString("moduleName"))));
IOUtils.write(sw.toString(), zip, "UTF-8");
IOUtils.closeQuietly(sw);
zip.closeEntry();
} catch (IOException e) {
......@@ -139,20 +165,116 @@ public class GenUtils {
}
}
/**
* 生成mongo其他实体类的代码
*/
public static void generatorMongoCode(String[] tableNames, ZipOutputStream zip) {
for (String tableName : tableNames) {
MongoDefinition info = MongoManager.getInfo(tableName);
currentTableName = tableName;
List<MongoGeneratorEntity> childrenInfo = info.getChildrenInfo(tableName);
childrenInfo.remove(0);
for (MongoGeneratorEntity mongoGeneratorEntity : childrenInfo) {
generatorChildrenBeanCode(mongoGeneratorEntity, zip);
}
}
}
private static void generatorChildrenBeanCode(MongoGeneratorEntity mongoGeneratorEntity, ZipOutputStream zip) {
//配置信息
Configuration config = getConfig();
boolean hasList = false;
//表信息
TableEntity tableEntity = mongoGeneratorEntity.toTableEntity();
//表名转换成Java类名
String className = tableToJava(tableEntity.getTableName(), config.getStringArray("tablePrefix"));
tableEntity.setClassName(className);
tableEntity.setClassname(StringUtils.uncapitalize(className));
//列信息
List<ColumnEntity> columsList = new ArrayList<>();
for (Map<String, String> column : mongoGeneratorEntity.getColumns()) {
ColumnEntity columnEntity = new ColumnEntity();
String columnName = column.get("columnName");
if (columnName.contains(".")) {
columnName = columnName.substring(columnName.lastIndexOf(".") + 1);
}
columnEntity.setColumnName(columnName);
columnEntity.setDataType(column.get("dataType"));
columnEntity.setExtra(column.get("extra"));
//列名转换成Java属性名
String attrName = columnToJava(columnEntity.getColumnName());
columnEntity.setAttrName(attrName);
columnEntity.setAttrname(StringUtils.uncapitalize(attrName));
//列的数据类型,转换成Java类型
String attrType = config.getString(columnEntity.getDataType(), columnToJava(columnEntity.getDataType()));
columnEntity.setAttrType(attrType);
if (!hasList && "array".equals(columnEntity.getExtra())) {
hasList = true;
}
columsList.add(columnEntity);
}
tableEntity.setColumns(columsList);
//设置velocity资源加载器
Properties prop = new Properties();
prop.put("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
Velocity.init(prop);
String mainPath = config.getString("mainPath");
mainPath = StringUtils.isBlank(mainPath) ? "io.renren" : mainPath;
//封装模板数据
Map<String, Object> map = new HashMap<>();
map.put("tableName", tableEntity.getTableName());
map.put("comments", tableEntity.getComments());
map.put("pk", tableEntity.getPk());
map.put("className", tableEntity.getClassName());
map.put("classname", tableEntity.getClassname());
map.put("pathName", tableEntity.getClassname().toLowerCase());
map.put("columns", tableEntity.getColumns());
map.put("hasList", hasList);
map.put("mainPath", mainPath);
map.put("package", config.getString("package"));
map.put("moduleName", config.getString("moduleName"));
map.put("author", config.getString("author"));
map.put("email", config.getString("email"));
map.put("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
VelocityContext context = new VelocityContext(map);
//获取模板列表
List<String> templates = getMongoChildTemplates();
for (String template : templates) {
//渲染模板
StringWriter sw = new StringWriter();
Template tpl = Velocity.getTemplate(template, "UTF-8");
tpl.merge(context, sw);
try {
//添加到zip
zip.putNextEntry(new ZipEntry(getFileName(template, tableEntity.getClassName(), config.getString("package"), config.getString("moduleName"))));
IOUtils.write(sw.toString(), zip, "UTF-8");
IOUtils.closeQuietly(sw);
zip.closeEntry();
} catch (IOException e) {
throw new RRException("渲染模板失败,表名:" + tableEntity.getTableName(), e);
}
}
}
/**
* 列名转换成Java属性名
*/
public static String columnToJava(String columnName) {
return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "" );
return WordUtils.capitalizeFully(columnName, new char[]{'_'}).replace("_", "");
}
/**
* 表名转换成Java类名
*/
public static String tableToJava(String tableName, String[] tablePrefixArray) {
if(null != tablePrefixArray && tablePrefixArray.length>0){
for(String tablePrefix : tablePrefixArray){
if (null != tablePrefixArray && tablePrefixArray.length > 0) {
for (String tablePrefix : tablePrefixArray) {
tableName = tableName.replace(tablePrefix, "");
}
}
......@@ -164,7 +286,7 @@ public class GenUtils {
*/
public static Configuration getConfig() {
try {
return new PropertiesConfiguration("generator.properties" );
return new PropertiesConfiguration("generator.properties");
} catch (ConfigurationException e) {
throw new RRException("获取配置文件失败,", e);
}
......@@ -178,45 +300,52 @@ public class GenUtils {
if (StringUtils.isNotBlank(packageName)) {
packagePath += packageName.replace(".", File.separator) + File.separator + moduleName + File.separator;
}
if (template.contains("Entity.java.vm" )) {
if (template.contains("MongoChildrenEntity.java.vm")) {
return packagePath + "entity" + File.separator + "inner" + File.separator + currentTableName+ File.separator + splitInnerName(className)+ "InnerEntity.java";
}
if (template.contains("Entity.java.vm") || template.contains("MongoEntity.java.vm")) {
return packagePath + "entity" + File.separator + className + "Entity.java";
}
if (template.contains("Dao.java.vm" )) {
if (template.contains("Dao.java.vm")) {
return packagePath + "dao" + File.separator + className + "Dao.java";
}
if (template.contains("Service.java.vm" )) {
if (template.contains("Service.java.vm")) {
return packagePath + "service" + File.separator + className + "Service.java";
}
if (template.contains("ServiceImpl.java.vm" )) {
if (template.contains("ServiceImpl.java.vm")) {
return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
}
if (template.contains("Controller.java.vm" )) {
if (template.contains("Controller.java.vm")) {
return packagePath + "controller" + File.separator + className + "Controller.java";
}
if (template.contains("Dao.xml.vm" )) {
if (template.contains("Dao.xml.vm")) {
return "main" + File.separator + "resources" + File.separator + "mapper" + File.separator + moduleName + File.separator + className + "Dao.xml";
}
if (template.contains("menu.sql.vm" )) {
if (template.contains("menu.sql.vm")) {
return className.toLowerCase() + "_menu.sql";
}
if (template.contains("index.vue.vm" )) {
if (template.contains("index.vue.vm")) {
return "main" + File.separator + "resources" + File.separator + "src" + File.separator + "views" + File.separator + "modules" +
File.separator + moduleName + File.separator + className.toLowerCase() + ".vue";
}
if (template.contains("add-or-update.vue.vm" )) {
if (template.contains("add-or-update.vue.vm")) {
return "main" + File.separator + "resources" + File.separator + "src" + File.separator + "views" + File.separator + "modules" +
File.separator + moduleName + File.separator + className.toLowerCase() + "-add-or-update.vue";
}
return null;
}
private static String splitInnerName(String name){
name = name.replaceAll("\\.","_");
return name;
}
}
package io.renren.utils;
import com.mongodb.BasicDBObject;
import com.mongodb.MongoCommandException;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import io.renren.config.MongoManager;
import io.renren.entity.mongo.MongoDefinition;
import io.renren.entity.mongo.Type;
import org.bson.Document;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.*;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
import java.util.stream.Collectors;
/**
* @author: gxz 514190950@qq.com
**/
public class MongoScanner {
private Logger logger = LoggerFactory.getLogger(getClass());
private MongoCollection<Document> collection;
final private int scanCount;
private List<String> colNames;
private MongoDefinition mongoDefinition;
private final static int[] TYPE = {3, 16, 18, 8, 9, 2, 1};
private final static int ARRAY_TYPE = 4;
private final static int MAX_COUNT = 200000;
private final static int DEFAULT_COUNT = 100000;
public MongoScanner(MongoCollection<Document> collection) {
this.collection = collection;
this.scanCount = DEFAULT_COUNT;
scan();
}
private void scan() {
// 初始化
initColNames();
// 解析属性值
mongoDefinition = scanType();
MongoManager.putInfo(collection.getNamespace().getCollectionName(), mongoDefinition);
// 解析完成之后释放链接资源
this.collection = null;
}
public MongoDefinition getProduct() {
return mongoDefinition;
}
/**
* 功能描述:分组发送聚合函数(获得一级属性名)
*
* @author : gxz
*/
public List<String> groupAggregation(Integer skip, Integer limit) throws MongoCommandException {
skip = skip == null ? 0 : skip;
limit = limit == null ? scanCount : limit;
MongoCollection<Document> collection = this.collection;
BasicDBObject $project = new BasicDBObject("$project", new BasicDBObject("arrayofkeyvalue", new BasicDBObject("$objectToArray", "$$ROOT")));
BasicDBObject $unwind = new BasicDBObject("$unwind", "$arrayofkeyvalue");
BasicDBObject $skip = new BasicDBObject("$skip", skip);
BasicDBObject $limit = new BasicDBObject("$limit", limit);
BasicDBObject filed = new BasicDBObject("_id", "null");
filed.append("allkeys", new BasicDBObject("$addToSet", "$arrayofkeyvalue.k"));
BasicDBObject $group = new BasicDBObject("$group", filed);
List<BasicDBObject> dbStages = Arrays.asList($project, $skip, $limit, $unwind, $group);
// System.out.println(dbStages); 发送的聚合函数 获得所有参数名称
AggregateIterable<Document> aggregate = collection.aggregate(dbStages);
Document document = aggregate.first();
if (document == null) {
BasicDBObject existsQuery = new BasicDBObject("$ROOT", new BasicDBObject("$exists", true));
MongoCursor<Document> existsList = collection.find(existsQuery).limit(100).iterator();
Set<String> keySet = new HashSet<>();
while (existsList.hasNext()) {
Document next = existsList.next();
Map<String, Object> keyMap = (Document) next.get("$ROOT");
keySet.addAll(keyMap.keySet());
}
return new ArrayList<>(keySet);
} else {
return (List<String>) document.get("allkeys");
}
}
/**
* 如果一个文档是对象类型 获得这个属性的下一级的属性名的集合
* 例子: user:{name:"张三",age:12} 传入user 返回[name,age]
*
* @param parameterName 上层参数名 这个参数名可以包含一个或多个.
* 注: 参数传递之前需确认: 1.上层属性一定是对象类型
* @return 返回这个属性内的所有属性名
*/
public Set<String> getNextParameterNames(String parameterName) {
Document condition = new Document(parameterName, new Document("$exists", true));
Document match = new Document("$match", condition);
String unwindName = parameterName;
if (parameterName.contains(".")) {
unwindName = parameterName.split("\\.")[0];
}
Document unwind = new Document("$unwind", "$" + unwindName);
Document limit = new Document("$limit", 3000);
Document project = new Document("$project", new Document("list", "$" + parameterName).append("_id", false));
Document unwind2 = new Document("$unwind", "$list");
AggregateIterable<Document> aggregate = this.collection.aggregate(Arrays.asList(match, unwind, limit, project, unwind2));
Set<String> names = new HashSet<>();
for (Document document : aggregate) {
Object list = document.get("list");
if (list instanceof Map) {
Set<String> documentNames = ((Document) list).keySet();
names.addAll(documentNames);
}
}
logger.info("解析" + parameterName + "有" + names.size() + "个子属性");
return names;
}
/**
* 功能描述:提供属性名 解析属性类型
* 获取相应的属性信息 封装成generator对象
*
* @return : 解析之后的Model {@see #MongoDefinition}
* @param: propertyName 属性名 可以是层级名 比如 name 也可以是info.name
* @see MongoDefinition
*/
public MongoDefinition processNameType(String propertyName) {
MongoCollection<Document> collection = this.collection;
MongoDefinition result = new MongoDefinition();
if ("_id".equals(propertyName)) {
result.setType(2);
result.setPropertyName("_id");
return result;
}
result.setPropertyName(propertyName);
MongoCursor<Document> isArray = collection.find(new Document(propertyName, new Document("$type", ARRAY_TYPE))).limit(1).iterator();
if (isArray.hasNext()) {
result.setArray(true);
for (int i : TYPE) {
MongoCursor<Document> iterator = collection.find(new Document(propertyName, new Document("$type", i))).limit(1).iterator();
if (iterator.hasNext()) {
if (i == 3) {
result.setChild(this.produceChildList(propertyName));
}
//1是double 2是string 3是对象 4是数组 16是int 18 是long
result.setType(i);
logger.info("解析[" + propertyName + "]是[List][" + Type.typeInfo(result.getType()) + "]");
return result;
}
}
} else {
for (int i : TYPE) {
MongoCursor<Document> iterator = collection.find(new Document(propertyName, new Document("$type", i))).limit(1).iterator();
if (iterator.hasNext()) {
if (i == 3) {
result.setChild(this.produceChildList(propertyName));
}
//1是double 2是string 3是对象 4是数组 16是int 18 是long
//到这里就是数组了
result.setType(i);
logger.info("解析[" + propertyName + "]是[" + Type.typeInfo(result.getType()) + "]");
return result;
}
}
result.setType(2);
}
logger.info("解析[" + propertyName + "]是[" + Type.typeInfo(result.getType()) + "]");
return result;
}
private List<MongoDefinition> produceChildList(String parentName) {
Set<String> nextParameterNames = this.getNextParameterNames(parentName);
List<String> strings = new ArrayList<>(nextParameterNames);
List<String> collect = strings.stream().map(name -> parentName + "." + name).collect(Collectors.toList());
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<List<MongoDefinition>> task = new ForkJoinProcessType(collect);
return pool.invoke(task);
}
private List<String> distinctAndJoin(List<String> a, List<String> b) {
a.removeAll(b);
a.addAll(b);
return a;
}
/**
* 功能描述:解析这个集合的列名 用ForkJoin框架实现
*/
private void initColNames() {
long start = System.currentTimeMillis();
int scan = this.scanCount;
long count = this.collection.countDocuments();
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<List<String>> task;
if (count > (long) scan) {
task = new ForkJoinGetProcessName(0, scan);
} else {
task = new ForkJoinGetProcessName(0, (int) count);
}
this.colNames = pool.invoke(task);
logger.info("collection[" + this.collection.getNamespace().getCollectionName() +
"]初始化列名成功..... 用时: " + (System.currentTimeMillis() - start) + "毫秒");
}
private MongoDefinition scanType() {
MongoDefinition result = new MongoDefinition();
List<String> colNames = this.colNames;
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask<List<MongoDefinition>> task = new ForkJoinProcessType(colNames);
List<MongoDefinition> invoke = pool.invoke(task);
return result.setChild(invoke).setPropertyName(this.collection.getNamespace().getCollectionName());
}
/**
* 功能描述:forkJoin多线程框架的实现 通过业务拆分解析类型
*/
class ForkJoinProcessType extends RecursiveTask<List<MongoDefinition>> {
List<String> names;
private final int THRESHOLD = 6;
ForkJoinProcessType(List<String> names) {
this.names = names;
}
@Override
protected List<MongoDefinition> compute() {
if (names.size() <= THRESHOLD) {
List<MongoDefinition> result = new ArrayList<>();
for (String name : names) {
MongoDefinition childrenDefinition = processNameType(name);
result.add(childrenDefinition);
}
return result;
} else {
int size = names.size();
int middle = size / 2;
List<String> leftList = names.subList(0, middle);
List<String> rightList = names.subList(middle, size);
ForkJoinProcessType pre = new ForkJoinProcessType(leftList);
pre.fork();
ForkJoinProcessType next = new ForkJoinProcessType(rightList);
next.fork();
return mergeList(pre.join(), next.join());
}
}
}
/**
* 功能描述:forkJoin多线程框架的实现 通过业务拆分获得属性名
*/
class ForkJoinGetProcessName extends RecursiveTask<List<String>> {
private int begin; //查询开始位置
private int end;
private final int THRESHOLD = 5000;
ForkJoinGetProcessName(int begin, int end) {
this.begin = begin;
this.end = end;
}
@Override
protected List<String> compute() {
int count = end - begin;
if (THRESHOLD >= count) {
return groupAggregation(begin, count);
} else {
int middle = (begin + end) / 2;
ForkJoinGetProcessName pre = new ForkJoinGetProcessName(begin, middle);
pre.fork();
ForkJoinGetProcessName next = new ForkJoinGetProcessName(middle + 1, end);
next.fork();
return distinctAndJoin(pre.join(), next.join()); //去重合并
}
}
}
public <T> List<T> mergeList(List<T> list1, List<T> list2){
list1.addAll(list2);
return list1;
}
}
......@@ -25,12 +25,23 @@ spring:
# url: jdbc:postgresql://192.168.10.10:5432/renren_fast
# username: postgres
# password: 123456
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
resources:
static-locations: classpath:/static/,classpath:/views/
#mongodb:
# host: localhost
# port: 27017
# auth: false #是否使用密码验证
# username: tincery
# password: renren
# source: 123456
# database: test
mybatis-plus:
mapperLocations: classpath:mapper/**/*.xml
......@@ -42,7 +53,7 @@ pagehelper:
params: count=countSql
#指定数据库,可选值有【mysql、oracle、sqlserver、postgresql】
#指定数据库,可选值有【mysql、oracle、sqlserver、postgresql、mongodb
renren:
database: mysql
......@@ -30,6 +30,7 @@ text=String
mediumtext=String
longtext=String
date=Date
datetime=Date
timestamp=Date
......
package ${package}.${moduleName}.entity;
#if(${hasList})
import java.util.List;
#end
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.annotation.Id;
/**
* ${comments}
*
* @author ${author}
* @email ${email}
* @date ${datetime}
*/
@Data
public class ${className}InnerEntity {
#foreach ($column in $columns)
private #if($column.extra == "array")List<#end$column.attrType#if($column.extra == "array")>#end $column.attrname;
#end
}
package ${package}.${moduleName}.entity;
#if(${hasBigDecimal})
import java.math.BigDecimal;
#end
#if(${hasList})
import java.util.List;
#end
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.annotation.Id;
/**
* ${comments}
*
* @author ${author}
* @email ${email}
* @date ${datetime}
*/
@Data
@Document(collection = "${tableName}")
public class ${className}Entity implements Serializable {
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
#if($column.columnName == "id")
@Id
#end
private #if($column.extra == "array")List<#end$column.attrType#if($column.extra == "array")>#end $column.attrname;
#end
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment