权限管理后端篇(二)之创建权限管理表引入人人开源代码生成器

父依赖

 
     
        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> columnsInfo = new ArrayList<>();
        info.setColumns(columnsInfo);
        info.setTableInfo(tableInfo);
        result.add(info);
        List child = this.getChild();
        for (MongoDefinition mongoDefinition : child) {
            Map 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 getChild() {
        return child;
    }

    public MongoDefinition setChild(List child) {
        this.child = child;
        return this;
    }
}
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> columns;


    public TableEntity toTableEntity() {
        TableEntity tableEntity = new TableEntity();
        Map tableInfo = this.tableInfo;
        tableEntity.setTableName(tableInfo.get("tableName"));
        tableEntity.setComments("");
        return tableEntity;
    }


    public Map getTableInfo() {
        return tableInfo;
    }

    public MongoGeneratorEntity setTableInfo(Map tableInfo) {
        this.tableInfo = tableInfo;
        return this;
    }

    public List> getColumns() {
        return columns;
    }

    public MongoGeneratorEntity setColumns(List> columns) {
        this.columns = columns;
        return this;
    }

}
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




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




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

你可能感兴趣的:(权限管理,数据库,mybatis,postgresql)