父依赖
UTF-8
UTF-8
3.3.1
1.1.13
2.6
2.5
1.10
1.2.60
1.7
1.2.5
8.0.17
4.0
11.2.0.3
3.11.0
Maven管理依赖
com.baomidou
mybatis-plus-boot-starter
${mybatisplus.version}
com.baomidou
mybatis-plus-generator
commons-lang
commons-lang
${commons.lang.version}
commons-io
commons-io
${commons.io.version}
commons-configuration
commons-configuration
${commons.configuration.version}
com.alibaba
fastjson
${fastjson.version}
velocity
org.apache.velocity
${velocity.version}
com.github.pagehelper
pagehelper-spring-boot-starter
${pagehelper.spring.boot.version}
org.mybatis
mybatis
org.mybatis
mybatis-spring
com.oracle
ojdbc6
${oracle.version}
com.microsoft.sqlserver
sqljdbc4
${mssql.version}
org.postgresql
postgresql
org.mongodb
mongo-java-driver
${mongo.version}
mysql
mysql-connector-java
runtime
com.alibaba
druid-spring-boot-starter
1.2.9
org.springframework.boot
spring-boot-starter-jdbc
org.springframework.boot
spring-boot-configuration-processor
true
org.projectlombok
lombok
true
entity(实体类)
ColumnEntity
/**
* 列的属性
*
* @author chenshun
* @email [email protected]
* @date 2016年12月20日 上午12:01:45
*/
public class ColumnEntity {
//列名
private String columnName;
//列名类型
private String dataType;
//列名备注
private String comments;
//属性名称(第一个字母大写),如:user_name => UserName
private String attrName;
//属性名称(第一个字母小写),如:user_name => userName
private String attrname;
//属性类型
private String attrType;
//auto_increment
private String extra;
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getDataType() {
return dataType;
}
public void setDataType(String dataType) {
this.dataType = dataType;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public String getAttrname() {
return attrname;
}
public void setAttrname(String attrname) {
this.attrname = attrname;
}
public String getAttrName() {
return attrName;
}
public void setAttrName(String attrName) {
this.attrName = attrName;
}
public String getAttrType() {
return attrType;
}
public void setAttrType(String attrType) {
this.attrType = attrType;
}
public String getExtra() {
return extra;
}
public void setExtra(String extra) {
this.extra = extra;
}
}
TableEntity
import java.util.List;
/**
* 表数据
*
* @author chenshun
* @email [email protected]
* @date 2016年12月20日 上午12:02:55
*/
public class TableEntity {
//表的名称
private String tableName;
//表的备注
private String comments;
//表的主键
private ColumnEntity pk;
//表的列名(不包含主键)
private List columns;
//类名(第一个字母大写),如:sys_user => SysUser
private String className;
//类名(第一个字母小写),如:sys_user => sysUser
private String classname;
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getComments() {
return comments;
}
public void setComments(String comments) {
this.comments = comments;
}
public ColumnEntity getPk() {
return pk;
}
public void setPk(ColumnEntity pk) {
this.pk = pk;
}
public List getColumns() {
return columns;
}
public void setColumns(List columns) {
this.columns = columns;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
}
MongoDefinition
import com.yongyuankuaile.product.generotor.adaptor.MongoTableInfoAdaptor;
import org.apache.commons.collections.CollectionUtils;
import java.io.Serializable;
import java.util.*;
/**
* 解析表之后得到的信息实体
* 换句话说这个类就是一张mongo一张表的内容
*
* @author gxz [email protected]
*/
public class MongoDefinition implements Serializable {
/***属性名**/
private String propertyName;
/***属性类型 对应mongodb api $type 如果没有类型 表示这是一个顶层实体 而不是内嵌属性**/
private Integer type;
/***此属性是否是数组**/
private boolean array = false;
/***如果此属性是对象 那么他仍然有此类型的子类**/
private List child;
public List getChildrenInfo(String tableName) {
List result = new ArrayList<>();
MongoGeneratorEntity info = new MongoGeneratorEntity();
// 表信息
Map tableInfo = MongoTableInfoAdaptor.tableInfo(tableName);
// 列名信息
List
MongoGeneratorEntity
import com.yongyuankuaile.product.generotor.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 tableInfo;
/***主类的列名信息**/
private List
Type
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;
}
}
utils (工具类)
Constant
/**
* 常量
*
* @author chenshun
* @email [email protected]
* @date 2016年11月15日 下午1:23:52
*/
public class Constant {
}
DateUtils
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 日期处理
*
* @author chenshun
* @email [email protected]
* @date 2016年12月21日 下午12:53:33
*/
public class DateUtils {
/** 时间格式(yyyy-MM-dd) */
public final static String DATE_PATTERN = "yyyy-MM-dd";
/** 时间格式(yyyy-MM-dd HH:mm:ss) */
public final static String DATE_TIME_PATTERN = "yyyy-MM-dd HH:mm:ss";
public static String format(Date date) {
return format(date, DATE_PATTERN);
}
public static String format(Date date, String pattern) {
if(date != null){
SimpleDateFormat df = new SimpleDateFormat(pattern);
return df.format(date);
}
return null;
}
}
GenUtils
import com.yongyuankuaile.product.generotor.config.MongoManager;
import com.yongyuankuaile.product.generotor.entity.ColumnEntity;
import com.yongyuankuaile.product.generotor.entity.TableEntity;
import com.yongyuankuaile.product.generotor.entity.mongo.MongoDefinition;
import com.yongyuankuaile.product.generotor.entity.mongo.MongoGeneratorEntity;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.WordUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 代码生成器 工具类
*
* @author chenshun
* @email [email protected]
* @date 2016年12月19日 下午11:40:24
*/
public class GenUtils {
private static String currentTableName;
public static List getTemplates() {
List templates = new ArrayList();
templates.add("template/Entity.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/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 getMongoChildTemplates() {
List templates = new ArrayList();
templates.add("template/MongoChildrenEntity.java.vm");
return templates;
}
/**
* 生成代码
*/
public static void generatorCode(Map table,
List> columns, ZipOutputStream zip) {
//配置信息
Configuration config = getConfig();
boolean hasBigDecimal = false;
boolean hasList = false;
//表信息
TableEntity tableEntity = new TableEntity();
tableEntity.setTableName(table.get("tableName"));
tableEntity.setComments(table.get("tableComment"));
//表名转换成Java类名
String className = tableToJava(tableEntity.getTableName(), config.getStringArray("tablePrefix"));
tableEntity.setClassName(className);
tableEntity.setClassname(StringUtils.uncapitalize(className));
//列信息
List columsList = new ArrayList<>();
for (Map 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"));
//列名转换成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 (!hasBigDecimal && attrType.equals("BigDecimal")) {
hasBigDecimal = true;
}
if (!hasList && "array".equals(columnEntity.getExtra())) {
hasList = true;
}
//是否主键
if ("PRI".equalsIgnoreCase(column.get("columnKey")) && tableEntity.getPk() == null) {
tableEntity.setPk(columnEntity);
}
columsList.add(columnEntity);
}
tableEntity.setColumns(columsList);
//没主键,则第一个字段为主键
if (tableEntity.getPk() == null) {
tableEntity.setPk(tableEntity.getColumns().get(0));
}
//设置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) ? "com.yongyuankuaile.product.generotor" : mainPath;
//封装模板数据
Map 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("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("datetime", DateUtils.format(new Date(), DateUtils.DATE_TIME_PATTERN));
VelocityContext context = new VelocityContext(map);
//获取模板列表
List templates = getTemplates();
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);
}
}
}
/**
* 生成mongo其他实体类的代码
*/
public static void generatorMongoCode(String[] tableNames, ZipOutputStream zip) {
for (String tableName : tableNames) {
MongoDefinition info = MongoManager.getInfo(tableName);
currentTableName = tableName;
List 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 columsList = new ArrayList<>();
for (Map 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) ? "com.yongyuankuaile.product.generotor" : mainPath;
//封装模板数据
Map 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 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("_", "");
}
/**
* 表名转换成Java类名
*/
public static String tableToJava(String tableName, String[] tablePrefixArray) {
if (null != tablePrefixArray && tablePrefixArray.length > 0) {
for (String tablePrefix : tablePrefixArray) {
if (tableName.startsWith(tablePrefix)){
tableName = tableName.replaceFirst(tablePrefix, "");
}
}
}
return columnToJava(tableName);
}
/**
* 获取配置信息
*/
public static Configuration getConfig() {
try {
return new PropertiesConfiguration("generator.properties");
} catch (ConfigurationException e) {
throw new RRException("获取配置文件失败,", e);
}
}
/**
* 获取文件名
*/
public static String getFileName(String template, String className, String packageName, String moduleName) {
String packagePath = "main" + File.separator + "java" + File.separator;
if (StringUtils.isNotBlank(packageName)) {
packagePath += packageName.replace(".", File.separator) + File.separator + moduleName + File.separator;
}
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")) {
return packagePath + "dao" + File.separator + className + "Dao.java";
}
if (template.contains("Service.java.vm")) {
return packagePath + "service" + File.separator + className + "Service.java";
}
if (template.contains("ServiceImpl.java.vm")) {
return packagePath + "service" + File.separator + "impl" + File.separator + className + "ServiceImpl.java";
}
if (template.contains("Controller.java.vm")) {
return packagePath + "controller" + File.separator + className + "Controller.java";
}
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")) {
return className.toLowerCase() + "_menu.sql";
}
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")) {
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;
}
}
HttpStatus
/**
* 返回状态码
*
* @author ruoyi
*/
public class HttpStatus
{
/**
* 操作成功
*/
public static final int SUCCESS = 200;
/**
* 对象创建成功
*/
public static final int CREATED = 201;
/**
* 请求已经被接受
*/
public static final int ACCEPTED = 202;
/**
* 操作已经执行成功,但是没有返回数据
*/
public static final int NO_CONTENT = 204;
/**
* 资源已被移除
*/
public static final int MOVED_PERM = 301;
/**
* 重定向
*/
public static final int SEE_OTHER = 303;
/**
* 资源没有被修改
*/
public static final int NOT_MODIFIED = 304;
/**
* 参数列表错误(缺少,格式不匹配)
*/
public static final int BAD_REQUEST = 400;
/**
* 未授权
*/
public static final int UNAUTHORIZED = 401;
/**
* 访问受限,授权过期
*/
public static final int FORBIDDEN = 403;
/**
* 资源,服务未找到
*/
public static final int NOT_FOUND = 404;
/**
* 不允许的http方法
*/
public static final int BAD_METHOD = 405;
/**
* 资源冲突,或者资源被锁
*/
public static final int CONFLICT = 409;
/**
* 不支持的数据,媒体类型
*/
public static final int UNSUPPORTED_TYPE = 415;
/**
* 系统内部错误
*/
public static final int ERROR = 500;
/**
* 接口未实现
*/
public static final int NOT_IMPLEMENTED = 501;
}
MongoScanner
import com.mongodb.BasicDBObject;
import com.mongodb.MongoCommandException;
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoCursor;
import com.yongyuankuaile.product.generotor.config.MongoManager;
import com.yongyuankuaile.product.generotor.entity.mongo.MongoDefinition;
import com.yongyuankuaile.product.generotor.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 [email protected]
**/
public class MongoScanner {
private Logger logger = LoggerFactory.getLogger(getClass());
private MongoCollection collection;
final private int scanCount;
private List 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 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 groupAggregation(Integer skip, Integer limit) throws MongoCommandException {
skip = skip == null ? 0 : skip;
limit = limit == null ? scanCount : limit;
MongoCollection 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 dbStages = Arrays.asList($project, $skip, $limit, $unwind, $group);
// System.out.println(dbStages); 发送的聚合函数 获得所有参数名称
AggregateIterable aggregate = collection.aggregate(dbStages);
Document document = aggregate.first();
if (document == null) {
BasicDBObject existsQuery = new BasicDBObject("$ROOT", new BasicDBObject("$exists", true));
MongoCursor existsList = collection.find(existsQuery).limit(100).iterator();
Set keySet = new HashSet<>();
while (existsList.hasNext()) {
Document next = existsList.next();
Map keyMap = (Document) next.get("$ROOT");
keySet.addAll(keyMap.keySet());
}
return new ArrayList<>(keySet);
} else {
return (List) document.get("allkeys");
}
}
/**
* 如果一个文档是对象类型 获得这个属性的下一级的属性名的集合
* 例子: user:{name:"张三",age:12} 传入user 返回[name,age]
*
* @param parameterName 上层参数名 这个参数名可以包含一个或多个.
* 注: 参数传递之前需确认: 1.上层属性一定是对象类型
* @return 返回这个属性内的所有属性名
*/
public Set 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 aggregate = this.collection.aggregate(Arrays.asList(match, unwind, limit, project, unwind2));
Set names = new HashSet<>();
for (Document document : aggregate) {
Object list = document.get("list");
if (list instanceof Map) {
Set 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 collection = this.collection;
MongoDefinition result = new MongoDefinition();
if ("_id".equals(propertyName)) {
result.setType(2);
result.setPropertyName("_id");
return result;
}
result.setPropertyName(propertyName);
MongoCursor 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 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 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 produceChildList(String parentName) {
Set nextParameterNames = this.getNextParameterNames(parentName);
List strings = new ArrayList<>(nextParameterNames);
List collect = strings.stream().map(name -> parentName + "." + name).collect(Collectors.toList());
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask> task = new ForkJoinProcessType(collect);
return pool.invoke(task);
}
private List distinctAndJoin(List a, List 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> 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 colNames = this.colNames;
ForkJoinPool pool = new ForkJoinPool();
ForkJoinTask> task = new ForkJoinProcessType(colNames);
List invoke = pool.invoke(task);
return result.setChild(invoke).setPropertyName(this.collection.getNamespace().getCollectionName());
}
/**
* 功能描述:forkJoin多线程框架的实现 通过业务拆分解析类型
*/
class ForkJoinProcessType extends RecursiveTask> {
List names;
private final int THRESHOLD = 6;
ForkJoinProcessType(List names) {
this.names = names;
}
@Override
protected List compute() {
if (names.size() <= THRESHOLD) {
List 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 leftList = names.subList(0, middle);
List 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> {
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 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 List mergeList(List list1, List list2){
list1.addAll(list2);
return list1;
}
}
PageUtils
import java.io.Serializable;
import java.util.List;
/**
* 分页工具类
*
* @author chenshun
* @email [email protected]
* @date 2016年11月4日 下午12:59:00
*/
public class PageUtils implements Serializable {
private static final long serialVersionUID = 1L;
//总记录数
private int totalCount;
//每页记录数
private int pageSize;
//总页数
private int totalPage;
//当前页数
private int currPage;
//列表数据
private List> list;
/**
* 分页
* @param list 列表数据
* @param totalCount 总记录数
* @param pageSize 每页记录数
* @param currPage 当前页数
*/
public PageUtils(List> list, int totalCount, int pageSize, int currPage) {
this.list = list;
this.totalCount = totalCount;
this.pageSize = pageSize;
this.currPage = currPage;
this.totalPage = (int)Math.ceil((double)totalCount/pageSize);
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getPageSize() {
return pageSize;
}
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
public int getTotalPage() {
return totalPage;
}
public void setTotalPage(int totalPage) {
this.totalPage = totalPage;
}
public int getCurrPage() {
return currPage;
}
public void setCurrPage(int currPage) {
this.currPage = currPage;
}
public List> getList() {
return list;
}
public void setList(List> list) {
this.list = list;
}
}
Query
package com.yongyuankuaile.product.generotor.utils;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
@ApiModel(
description = "查询条件"
)
@Data
@Accessors(chain = true)
public class Query extends LinkedHashMap {
//当前页面
@TableField(exist = false)
private Integer current;
//每页条数
@TableField(exist = false)
private Integer size;
public Query(Map params){
this.putAll(params);
//分页参数
this.current = Integer.parseInt(params.get("current").toString());
this.size = Integer.parseInt(params.get("size").toString());
this.put("offset", (current - 1) * size);
this.put("current", current);
this.put("size", size);
}
/**
* 分页、计算page
* @return
*/
public void getHandlePage(){
current = (current-1)*size;
}
}
R
import java.io.Serializable;
/**
* 响应信息主体
*统一返回数据格式
* @author ruoyi
*/
public class R implements Serializable
{
private static final long serialVersionUID = 1L;
/** 成功 */
public static final int SUCCESS = HttpStatus.SUCCESS;
/** 失败 */
public static final int FAIL = HttpStatus.ERROR;
/*
* 状态码
* */
private Integer code;
/*
* 状态码含义
* */
private String msg;
/*
* 状态码含义描述
* */
private T data;
public static R ok()
{
return restResult(null, SUCCESS, "操作成功");
}
public static R ok(T data)
{
return restResult(data, SUCCESS, "操作成功");
}
public static R ok(T data, String msg)
{
return restResult(data, SUCCESS, msg);
}
public static R fail()
{
return restResult(null, FAIL, "操作失败");
}
public static R fail(String msg)
{
return restResult(null, FAIL, msg);
}
public static R fail(T data)
{
return restResult(data, FAIL, "操作失败");
}
public static R fail(T data, String msg)
{
return restResult(data, FAIL, msg);
}
public static R fail(int code, String msg)
{
return restResult(null, code, msg);
}
private static R restResult(T data, int code, String msg)
{
R apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode()
{
return code;
}
public void setCode(int code)
{
this.code = code;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
public R() {
}
public R(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public R(Integer code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
}
RRException
/**
* 自定义异常
*
* @author chenshun
* @email [email protected]
* @date 2016年10月27日 下午10:11:27
*/
public class RRException extends RuntimeException {
private static final long serialVersionUID = 1L;
private String msg;
private int code = 500;
public RRException(String msg) {
super(msg);
this.msg = msg;
}
public RRException(String msg, Throwable e) {
super(msg, e);
this.msg = msg;
}
public RRException(String msg, int code) {
super(msg);
this.msg = msg;
this.code = code;
}
public RRException(String msg, int code, Throwable e) {
super(msg, e);
this.msg = msg;
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
RRExceptionHandler
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 异常处理器
*
* @author chenshun
* @email [email protected]
* @date 2016年10月27日 下午10:16:19
*/
@Component
public class RRExceptionHandler implements HandlerExceptionResolver {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public ModelAndView resolveException(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex) {
R r = new R();
try {
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
if (ex instanceof RRException) {
r.ok("code", String.valueOf(((RRException) ex).getCode()));
r.ok("msg", ex.getMessage());
}else if(ex instanceof DuplicateKeyException){
r = R.fail("数据库中已存在该记录");
}else{
r = R.fail();
}
//记录异常日志
logger.error(ex.getMessage(), ex);
String json = JSON.toJSONString(r);
response.getWriter().print(json);
} catch (Exception e) {
logger.error("RRExceptionHandler 异常处理失败", e);
}
return new ModelAndView();
}
}
Controller层
import com.yongyuankuaile.product.generotor.service.SysGeneratorService;
import com.yongyuankuaile.product.generotor.utils.PageUtils;
import com.yongyuankuaile.product.generotor.utils.Query;
import com.yongyuankuaile.product.generotor.utils.R;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
/**
* 代码生成器
*
* @author Mark [email protected]
*/
@Controller
@RequestMapping("/sys/generator")
public class SysGeneratorController {
@Autowired
private SysGeneratorService sysGeneratorService;
/**
* 列表
*/
@ResponseBody
@RequestMapping("/list")
public R list(@RequestParam Map params){
PageUtils pageUtil = sysGeneratorService.queryList(new Query(params));
return R.ok(pageUtil);
}
/**
* 生成代码
*/
@RequestMapping("/code")
public void code(String tables, HttpServletResponse response) throws IOException{
byte[] data = sysGeneratorService.generatorCode(tables.split(","));
response.reset();
response.setHeader("Content-Disposition", "attachment; filename=\"renren.zip\"");
response.addHeader("Content-Length", "" + data.length);
response.setContentType("application/octet-stream; charset=UTF-8");
IOUtils.write(data, response.getOutputStream());
}
}
Service层
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.yongyuankuaile.product.generotor.config.MongoManager;
import com.yongyuankuaile.product.generotor.dao.GeneratorDao;
import com.yongyuankuaile.product.generotor.dao.MongoDBGeneratorDao;
import com.yongyuankuaile.product.generotor.factory.MongoDBCollectionFactory;
import com.yongyuankuaile.product.generotor.utils.GenUtils;
import com.yongyuankuaile.product.generotor.utils.PageUtils;
import com.yongyuankuaile.product.generotor.utils.Query;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.ByteArrayOutputStream;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipOutputStream;
/**
* 代码生成器
*
* @author Mark [email protected]
*/
@Service
public class SysGeneratorService {
@Autowired
private GeneratorDao generatorDao;
public PageUtils queryList(Query query) {
Page> page = PageHelper.startPage(query.getCurrent(), query.getSize());
List> list = generatorDao.queryList(query);
int total = (int) page.getTotal();
if (generatorDao instanceof MongoDBGeneratorDao) {
total = MongoDBCollectionFactory.getCollectionTotal(query);
}
return new PageUtils(list, total, query.getSize(), query.getCurrent());
}
public Map queryTable(String tableName) {
return generatorDao.queryTable(tableName);
}
public List> 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 table = queryTable(tableName);
//查询列信息
List> columns = queryColumns(tableName);
//生成代码
GenUtils.generatorCode(table, columns, zip);
}
if (MongoManager.isMongo()) {
GenUtils.generatorMongoCode(tableNames, zip);
}
IOUtils.closeQuietly(zip);
return outputStream.toByteArray();
}
}
Dao层
GeneratorDao
import java.util.List;
import java.util.Map;
/**
* 数据库接口
*
* @author Mark [email protected]
* @since 2018-07-24
*/
public interface GeneratorDao {
List> queryList(Map map);
Map queryTable(String tableName);
List> queryColumns(String tableName);
}
MongoDBGeneratorDao
import com.yongyuankuaile.product.generotor.adaptor.MongoTableInfoAdaptor;
import com.yongyuankuaile.product.generotor.config.MongoCondition;
import com.yongyuankuaile.product.generotor.config.MongoManager;
import com.yongyuankuaile.product.generotor.entity.mongo.MongoDefinition;
import com.yongyuankuaile.product.generotor.factory.MongoDBCollectionFactory;
import com.yongyuankuaile.product.generotor.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 [email protected]
**/
@Repository
@Conditional(MongoCondition.class)
public class MongoDBGeneratorDao implements GeneratorDao {
@Autowired
private MongoDBCollectionFactory mongoDBCollectionFactory;
@Override
public List> queryList(Map map) {
List collectionNames = MongoDBCollectionFactory.getCollectionNames(map);
return (List) MongoTableInfoAdaptor.tableInfo(collectionNames);
}
@Override
public Map queryTable(String tableName) {
Map 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> 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);
}
}
MySQLGeneratorDao
import org.apache.ibatis.annotations.Mapper;
/**
* MySQL代码生成器
*
* @author Mark [email protected]
* @since 2018-07-24
*/
@Mapper
public interface MySQLGeneratorDao extends GeneratorDao {
}
OracleGeneratorDao
import org.apache.ibatis.annotations.Mapper;
/**
* Oracle代码生成器
*
* @author Mark [email protected]
* @since 2018-07-24
*/
@Mapper
public interface OracleGeneratorDao extends GeneratorDao {
}
PostgreSQLGeneratorDao
import org.apache.ibatis.annotations.Mapper;
/**
* PostgreSQL代码生成器
*
* @author Mark [email protected]
* @since 2018-07-24
*/
@Mapper
public interface PostgreSQLGeneratorDao extends GeneratorDao {
}
SQLServerGeneratorDao
import org.apache.ibatis.annotations.Mapper;
/**
* SQLServer代码生成器
*
* @author Mark [email protected]
* @since 2018-07-24
*/
@Mapper
public interface SQLServerGeneratorDao extends GeneratorDao {
}
对应的xml层
MySQLGeneratorDao.xml
OracleGeneratorDao.xml
PostgreSQLGeneratorDao.xml
SQLServerGeneratorDao.xml
config配置类
DbConfig
import com.yongyuankuaile.product.generotor.dao.*;
import com.yongyuankuaile.product.generotor.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;
/**
* 数据库配置
*
* @author Mark [email protected]
*/
@Configuration
public class DbConfig {
@Value("${renren.database: mysql}")
private String database;
@Autowired
private MySQLGeneratorDao mySQLGeneratorDao;
@Autowired
private OracleGeneratorDao oracleGeneratorDao;
@Autowired
private SQLServerGeneratorDao sqlServerGeneratorDao;
@Autowired
private PostgreSQLGeneratorDao postgreSQLGeneratorDao;
private static boolean mongo = false;
@Bean
@Primary
@Conditional(MongoNullCondition.class)
public GeneratorDao getGeneratorDao() {
if ("mysql".equalsIgnoreCase(database)) {
return mySQLGeneratorDao;
} else if ("oracle".equalsIgnoreCase(database)) {
return oracleGeneratorDao;
} else if ("sqlserver".equalsIgnoreCase(database)) {
return sqlServerGeneratorDao;
} else if ("postgresql".equalsIgnoreCase(database)) {
return postgreSQLGeneratorDao;
} 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;
}
}
MongoCondition
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author: gxz [email protected]
**/
public class MongoCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String database = context.getEnvironment().getProperty("renren.database");
return "mongodb".equalsIgnoreCase(database);
}
}
MongoConfig
import com.mongodb.MongoClient;
import com.mongodb.MongoClientOptions;
import com.mongodb.MongoCredential;
import com.mongodb.ServerAddress;
import com.mongodb.client.MongoDatabase;
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 [email protected]
**/
@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 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;
}
}
MongoManager
import com.yongyuankuaile.product.generotor.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 mongoCache = new ConcurrentHashMap<>();
public static Map 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();
}
}
MongoNullCondition
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
/**
* @author: gxz [email protected]
**/
public class MongoNullCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
String database = context.getEnvironment().getProperty("renren.database");
return !"mongodb".equalsIgnoreCase(database);
}
}
adaptor类
MongoTableInfoAdaptor
import com.yongyuankuaile.product.generotor.entity.mongo.MongoDefinition;
import com.yongyuankuaile.product.generotor.entity.mongo.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* mongo适配器
*
* @author: gxz [email protected]
**/
public class MongoTableInfoAdaptor {
/**
* 查询表信息的时候 mongo只能获得表名 其他只能手动填写
*
* @param names 表名
*/
public static List> tableInfo(List names) {
List> result = new ArrayList<>(names.size());
for (String name : names) {
result.add(tableInfo(name));
}
return result;
}
public static Map tableInfo(String name) {
Map 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> columnInfo(MongoDefinition mongoDefinition) {
List child = mongoDefinition.getChild();
List> result = new ArrayList<>(child.size());
final String mongoKey = "_id";
for (MongoDefinition definition : child) {
Map 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;
}
}
factory类
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.MongoIterable;
import com.yongyuankuaile.product.generotor.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 [email protected]
**/
@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 getCollection(String collectionName) {
return mongoDatabase.getCollection(collectionName);
}
/***
* 获得当前数据库的集合名称
* 注: mongo相对关系型数据库较为特殊,查询表名无法分页,用stream实现
* @author gxz
* @date 2020/5/9
* @param map 这是查询条件 和关系型数据库一致
* @return 集合名称
**/
public static List getCollectionNames(Map map) {
int limit = Integer.valueOf(map.get(LIMIT_KEY).toString());
int skip = Integer.valueOf(map.get(OFFSET_KEY).toString());
List 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 map) {
if (map.containsKey(TABLE_NAME_KEY)) {
return getCollectionNames(map.get(TABLE_NAME_KEY).toString()).size();
}
return getCollectionNames().size();
}
private static List getCollectionNames() {
MongoIterable names = mongoDatabase.listCollectionNames();
List result = new ArrayList<>();
for (String name : names) {
result.add(name);
}
return result;
}
private static List getCollectionNames(String likeName) {
return getCollectionNames()
.stream()
.filter((name) -> name.contains(likeName)).collect(Collectors.toList());
}
}
applaction.yml
server:
port: 5000
spring:
# mvc:
# view:
# prefix: /pages/
# suffix: .html
datasource:
name: druidDataSource
type: com.alibaba.druid.pool.DruidDataSource
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://IP地址:端口号/数据库?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false
username: 账号
password: 密码
filters: stat,wall,slf4j,config #配置监控统计拦截的filters,去掉后监控界面SQL无法进行统计,wall用于防火墙。
max-active: 100 #最大连接数
initial-size: 1 #初始化大小
max-wait: 60000 #获取连接等待超时时间
min-idle: 1 #最小连接数
time-between-eviction-runs-millis: 60000 #间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒。
min-evictable-idle-time-millis: 300000 #一个连接在池中最小生存的时间,单位是毫秒。
validation-query: select 'x'
test-while-idle: true
test-on-borrow: false
test-on-return: false
pool-prepared-statements: true
max-pool-prepared-statement-per-connection-size: 20
web:
resources:
static-locations: classpath:/static/,classpath:/views/
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd HH:mm:ss
logging:
config: classpath:logback.xml
#mongodb:
# host: localhost
# port: 27017
# auth: false #是否使用密码验证
# username: tincery
# password: renren
# source: 123456
# database: test
mybatis-plus:
mapperLocations: classpath:mapper/**/*.xml
pagehelper:
reasonable: true
supportMethodsArguments: true
params: count=countSql
#指定数据库,可选值有【mysql、oracle、sqlserver、postgresql、mongodb】
renren:
database: mysql
接下来就是页面模板和前端页面
页面模板是固定的前端是用js和html编写成的
页面模板
add-or-update.vue.vm
#foreach($column in $columns)
#if($column.columnName != $pk.columnName)
#end
#end
Controller.java.vm
package ${package}.${moduleName}.controller;
import java.util.Arrays;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import com.github.pagehelper.PageInfo;
import ${package}.${moduleName}.entity.${className}Entity;
import ${package}.${moduleName}.service.${className}Service;
import ${mainPath}.common.utils.PageUtils;
import ${mainPath}.common.utils.R;
import io.swagger.annotations.Api;
/**
* ${comments}
*
* @author ${author}
* @email ${email}
* @date ${datetime}
*/
@RestController
@RequestMapping("${moduleName}/${pathName}")
@Api(tags = {"${comments}模块"}, description = "${comments}")
public class ${className}Controller {
@Autowired
private ${className}Service ${classname}Service;
/**
* 使用Mybatis-plus自带分页操作 并对deptVO进行条件构造
*/
@PostMapping("/list")
@ApiOperation(value = "分页查询", notes = "分页查询",response = ${className}Entity.class)
public R list(@RequestBody(required = false) ${className}Entity ${classname}) {
PageInfo page = ${classname}Service.PageQuery(${classname});
return R.ok(page);
}
/**
* 信息
*/
@GetMapping("/info/{${pk.attrname}}")
public R info(@PathVariable("${pk.attrname}") ${pk.attrType} ${pk.attrname}){
${className}Entity ${classname} = ${classname}Service.getById(${pk.attrname});
return R.ok( ${classname});
}
/**
* 保存
*/
@PostMapping("/save")
@ApiOperation(value = "保存", notes = "保存时,ID由数据库生成,无需填写,有则忽略", tags = "保存")
public R save(@RequestBody ${className}Entity ${classname}){
${classname}Service.save(${classname});
return R.ok();
}
/**
* 修改
*/
@PostMapping("/update")
@ApiOperation(value = "更新", notes = "id必填,其它属性存在则更新,否则忽略", tags = "更新")
public R update(@RequestBody ${className}Entity ${classname}){
${classname}Service.updateById(${classname});
return R.ok();
}
/**
* 删除
*/
@GetMapping("/delete")
@ApiOperation(value = "删除", notes = "删除后无法恢复", tags = "删除")
public R delete(@RequestBody ${pk.attrType}[] ${pk.attrname}s){
${classname}Service.removeByIds(Arrays.asList(${pk.attrname}s));
return R.ok();
}
}
Dao.java.vm
package ${package}.${moduleName}.dao;
import ${package}.${moduleName}.entity.${className}Entity;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* ${comments}
*
* @author ${author}
* @email ${email}
* @date ${datetime}
*/
@Mapper
public interface ${className}Dao extends BaseMapper<${className}Entity> {
}
Dao.xml.vm
#foreach($column in $columns)
#end
Entity.java.vm
package ${package}.${moduleName}.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import ${package}.${moduleName}.common.QueryVo;
#if(${hasBigDecimal})
import java.math.BigDecimal;
#end
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import io.swagger.annotations.ApiModelProperty;
/**
* ${comments}
*
* @author ${author}
* @email ${email}
* @date ${datetime}
*/
@Data
@TableName("${tableName}")
@ApiModel("${comments}")
public class ${className}Entity implements Serializable {
private static final long serialVersionUID = 1L;
#foreach ($column in $columns)
/**
* $column.comments
*/
@ApiModelProperty("$column.comments")
#if($column.columnName == $pk.columnName)
@TableId
#end
private $column.attrType $column.attrname;
#end
//当前页面
@TableField(exist = false)
private Integer current;
//每页条数
@TableField(exist = false)
private Integer size;
}
}
index.vue.vm
查询
新增
批量删除
#foreach($column in $columns)
#end
修改
删除
menu.sql.vm
-- 菜单SQL
INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)
VALUES ('1', '${comments}', '${moduleName}/${pathName}', NULL, '1', 'config', '6');
-- 按钮父菜单ID
set @parentId = @@identity;
-- 菜单对应按钮SQL
INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)
SELECT @parentId, '查看', null, '${moduleName}:${pathName}:list,${moduleName}:${pathName}:info', '2', null, '6';
INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)
SELECT @parentId, '新增', null, '${moduleName}:${pathName}:save', '2', null, '6';
INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)
SELECT @parentId, '修改', null, '${moduleName}:${pathName}:update', '2', null, '6';
INSERT INTO `sys_menu` (`parent_id`, `name`, `url`, `perms`, `type`, `icon`, `order_num`)
SELECT @parentId, '删除', null, '${moduleName}:${pathName}:delete', '2', null, '6';
MongoChildrenEntity.java.vm
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
}
MongoEntity.java.vm
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
}
Service.java.vm
package ${package}.${moduleName}.service;
import com.baomidou.mybatisplus.extension.service.IService;
import ${package}.${moduleName}.entity.${className}Entity;
import com.github.pagehelper.PageInfo;
import java.util.Map;
/**
* ${comments}
*
* @author ${author}
* @email ${email}
* @date ${datetime}
*/
public interface ${className}Service extends IService<${className}Entity> {
PageInfo PageQuery(${className}Entity ${classname});
}
ServiceImpl.java.vm
package ${package}.${moduleName}.service.impl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Map;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${mainPath}.common.PageUtils;
import ${mainPath}.common.Query;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import ${package}.${moduleName}.dao.${className}Dao;
import ${package}.${moduleName}.entity.${className}Entity;
import ${package}.${moduleName}.service.${className}Service;
@Service("${classname}Service")
public class ${className}ServiceImpl extends ServiceImpl<${className}Dao, ${className}Entity> implements ${className}Service {
@Autowired
${className}Dao ${classname}dao;
@Override
public PageInfo PageQuery(${className}Entity ${classname}) {
QueryWrapper<${className}Entity> queryWrapper = new QueryWrapper<>();
//开启分页功能
PageHelper.startPage(${classname}.getCurrent(), ${classname}.getSize());
//查所有数据返回
PageInfo pageInfo = new PageInfo(${classname}dao.selectList(queryWrapper));
return pageInfo;
}
}
generator.properties
#路径
mainPath=com.yongyuankuaile.product
#包路径
package=com.yongyuankuaile.product
#模块名称
moduleName=sys
#用户名
author=zy
#邮箱
[email protected]
#路径
tablePrefix=tb_
#泛型
tinyint=Integer
smallint=Integer
mediumint=Integer
int=Integer
integer=Integer
bigint=Long
float=Float
double=Double
decimal=BigDecimal
bit=Boolean
char=String
varchar=String
tinytext=String
text=String
mediumtext=String
longtext=String
date=Date
datetime=Date
timestamp=Date
NUMBER=Integer
INT=Integer
INTEGER=Integer
BINARY_INTEGER=Integer
LONG=String
FLOAT=Float
BINARY_FLOAT=Float
DOUBLE=Double
BINARY_DOUBLE=Double
DECIMAL=BigDecimal
CHAR=String
VARCHAR=String
VARCHAR2=String
NVARCHAR=String
NVARCHAR2=String
CLOB=String
BLOB=String
DATE=Date
DATETIME=Date
TIMESTAMP=Date
TIMESTAMP(6)=Date
int8=Long
int4=Integer
int2=Integer
numeric=BigDecimal
nvarchar=String