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();
}
}
......@@ -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