Loading...

本篇文章实现了由模板一键生成 entity、controller、service、dao 相关类

dao 层主要是基于 Hibernate 框架和 PostgreSQL 数据库。

# 项目结构

  1. 新建 maven 项目,删除所有生成的文件,只留下 pom.xml,作为总项目。
  2. 在当前项目下,新建一个 maven 子模块,取名为 base 模块,包含基础类以及下面自动生成类的相关实现也放在此模块中。
  3. 在当前项目下,新建一个 maven 子模块,取名为 business 模块,包含相关业务实现类。
  4. 在 business 新建四个模块,分别为 business-entity、business-dao、business-service、business-controller 模块。
  5. 在 business 模块中需要引入 base 模块依赖。

在总项目 pom.xml 中引入所需依赖

<dependencies>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.10</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.2.11</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.11</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.32</version>
    </dependency>
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.29</version>
    </dependency>
    <dependency>
        <groupId>io.swagger</groupId>
        <artifactId>swagger-annotations</artifactId>
        <version>1.6.5</version>
    </dependency>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-core</artifactId>
        <version>5.6.7.Final</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.data</groupId>
        <artifactId>spring-data-jpa</artifactId>
        <version>2.6.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
        <version>2.6.6</version>
    </dependency>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.3.3</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>2.6.6</version>
    </dependency>
</dependencies>

# 配置常量类

新建包名 com.qiyin.base.generator.config,当前下的所有类都放在这个包下面。

ConstVal

package com.qiyin.base.generator.config;
import java.nio.charset.StandardCharsets;
/**
 * 常量
 **/
public interface ConstVal {
    String KT_SUFFIX = ".kt";
    String JAVA_SUFFIX = ".java";
    String MODULE_NAME = "ModuleName";
    String ENTITY = "Entity";
    String DAO = "Dao";
    String DAO_IMPL = "DaoImpl";
    String SERVICE = "Service";
    String SERVICE_IMPL = "ServiceImpl";
    String CONTROLLER = "Controller";
    String ENTITY_PATH = "entity_path";
    String DAO_PATH = "dao_path";
    String DAO_IMPL_PATH = "dao_impl_path";
    String SERVICE_PATH = "service_path";
    String SERVICE_IMPL_PATH = "service_impl_path";
    String CONTROLLER_PATH = "controller_path";
    String JAVA_TMPDIR = "java.io.tmpdir";
    String UTF8 = StandardCharsets.UTF_8.name();
    String TEMPLATE_ENTITY = "/templates/entity.java";
    String TEMPLATE_DAO = "/templates/dao.java";
    String TEMPLATE_DAO_IMPL = "/templates/daoImpl.java";
    String TEMPLATE_SERVICE = "/templates/service.java";
    String TEMPLATE_SERVICE_IMPL = "/templates/serviceImpl.java";
    String TEMPLATE_CONTROLLER = "/templates/controller.java";
    String MODEL_NORMAL = "normal";
    String MODEL_OTHER = "other";
}

StringVal

package com.qiyin.base.generator.config;
/**
 * 字符串常用常量
 */
public interface StringVal {
    String AMPERSAND = "&";
    String AND = "and";
    String AT = "@";
    String ASTERISK = "*";
    String STAR = ASTERISK;
    String BACK_SLASH = "\\";
    String COLON = ":";
    String COMMA = ",";
    String DASH = "-";
    String DOLLAR = "$";
    String DOT = ".";
    String DOTDOT = "..";
    String DOT_CLASS = ".class";
    String DOT_JAVA = ".java";
    String DOT_XML = ".xml";
    String EMPTY = "";
    String EQUALS = "=";
    String FALSE = "false";
    String SLASH = "/";
    String HASH = "#";
    String HAT = "^";
    String LEFT_BRACE = "{";
    String LEFT_BRACKET = "(";
    String LEFT_CHEV = "<";
    String DOT_NEWLINE = ",\n";
    String NEWLINE = "\n";
    String N = "n";
    String NO = "no";
    String NULL = "null";
    String OFF = "off";
    String ON = "on";
    String PERCENT = "%";
    String PIPE = "|";
    String PLUS = "+";
    String QUESTION_MARK = "?";
    String EXCLAMATION_MARK = "!";
    String QUOTE = "\"";
    String RETURN = "\r";
    String TAB = "\t";
    String RIGHT_BRACE = "}";
    String RIGHT_BRACKET = ")";
    String RIGHT_CHEV = ">";
    String SEMICOLON = ";";
    String SINGLE_QUOTE = "'";
    String BACKTICK = "`";
    String SPACE = " ";
    String TILDA = "~";
    String LEFT_SQ_BRACKET = "[";
    String RIGHT_SQ_BRACKET = "]";
    String TRUE = "true";
    String UNDERSCORE = "_";
    String UTF_8 = "UTF-8";
    String US_ASCII = "US-ASCII";
    String ISO_8859_1 = "ISO-8859-1";
    String Y = "y";
    String YES = "yes";
    String ONE = "1";
    String ZERO = "0";
    String DOLLAR_LEFT_BRACE = "${";
    String HASH_LEFT_BRACE = "#{";
    String CRLF = "\r\n";
    String HTML_NBSP = "&nbsp;";
    String HTML_AMP = "&amp";
    String HTML_QUOTE = "&quot;";
    String HTML_LT = "&lt;";
    String HTML_GT = "&gt;";
}

GlobalConfig

package com.qiyin.base.generator.config;
/**
 * 全局配置
 */
public class GlobalConfig {
    private boolean kotlin = false;
    /**
     * 是否覆盖已有文件
     */
    private boolean fileOverride = true;
    /**
     * 生成文件的输出目录【默认 D 盘根目录】
     */
    private String outputDir = "D://";
    private String author;
    private String tableName;
    private String project;
    private String comment;
    /**
     * 数据库模式
     */
    private String schema;
    /**
     * 数据表
     */
    private String dataTableName;
    /**
     * 数据表前缀
     */
    private String dataTablePrefix;
    /**
     * 生成类型.
     * normal: 正常
     */
    private String classType = ConstVal.MODEL_NORMAL;
    public boolean isKotlin() {
        return kotlin;
    }
    public GlobalConfig setKotlin(boolean kotlin) {
        this.kotlin = kotlin;
        return this;
    }
    public boolean isFileOverride() {
        return fileOverride;
    }
    public GlobalConfig setFileOverride(boolean fileOverride) {
        this.fileOverride = fileOverride;
        return this;
    }
    public String getOutputDir() {
        return outputDir;
    }
    public GlobalConfig setOutputDir(String outputDir) {
        this.outputDir = outputDir;
        return this;
    }
    public String getAuthor() {
        return author;
    }
    public GlobalConfig setAuthor(String author) {
        this.author = author;
        return this;
    }
    public String getTableName() {
        return tableName;
    }
    public GlobalConfig setTableName(String tableName) {
        this.tableName = tableName;
        return this;
    }
    public String getProject() {
        return project;
    }
    public GlobalConfig setProject(String project) {
        this.project = project;
        return this;
    }
    public String getComment() {
        return comment;
    }
    public GlobalConfig setComment(String comment) {
        this.comment = comment;
        return this;
    }
    public String getClassType() {
        return classType;
    }
    public GlobalConfig setClassType(String classType) {
        this.classType = classType;
        return this;
    }
    public GlobalConfig setSchema(String schema) {
        this.schema = schema;
        return this;
    }
    public GlobalConfig setDataTableName(String dataTableName) {
        this.dataTableName = dataTableName;
        return this;
    }
    public GlobalConfig setDataTablePrefix(String dataTablePrefix) {
        this.dataTablePrefix = dataTablePrefix;
        return this;
    }
    public String getSchema() {
        return schema;
    }
    public String getDataTableName() {
        return dataTableName;
    }
    public String getDataTablePrefix() {
        return dataTablePrefix;
    }
}

PackageConfig

package com.qiyin.base.generator.config;
import java.util.Map;
public class PackageConfig {
    private String parent = "";
    /**
     * 生成实体在那个包下.
     */
    private String packageName = "";
    private String entity = "entity";
    private String dao = "dao";
    private String daoImpl = "dao";
    private String service = "service";
    private String serviceImpl = "service.impl";
    private String controller = "controller";
    /**
     * 路径配置信息
     */
    private Map<String, String> pathInfo;
    public String getParent() {
        return parent;
    }
    public PackageConfig setParent(String parent) {
        this.parent = parent;
        return this;
    }
    public String getPackageName() {
        return packageName;
    }
    public PackageConfig setPackageName(String packageName) {
        this.packageName = packageName;
        return this;
    }
    public String getEntity() {
        return entity;
    }
    public PackageConfig setEntity(String entity) {
        this.entity = entity;
        return this;
    }
    public String getDao() {
        return dao;
    }
    public PackageConfig setDao(String repository) {
        this.dao = repository;
        return this;
    }
    public String getDaoImpl() {
        return daoImpl;
    }
    public PackageConfig setDaoImpl(String daoImpl) {
        this.daoImpl = daoImpl;
        return this;
    }
    public String getService() {
        return service;
    }
    public PackageConfig setService(String service) {
        this.service = service;
        return this;
    }
    public String getServiceImpl() {
        return serviceImpl;
    }
    public PackageConfig setServiceImpl(String serviceImpl) {
        this.serviceImpl = serviceImpl;
        return this;
    }
    public String getController() {
        return controller;
    }
    public PackageConfig setController(String controller) {
        this.controller = controller;
        return this;
    }
    public Map<String, String> getPathInfo() {
        return pathInfo;
    }
    public PackageConfig setPathInfo(Map<String, String> pathInfo) {
        this.pathInfo = pathInfo;
        return this;
    }
}

TemplateConfig

package com.qiyin.base.generator.config;
/**
 * 模板路径配置
 **/
public class TemplateConfig {
    private String entity = ConstVal.TEMPLATE_ENTITY;
    private String dao = ConstVal.TEMPLATE_DAO;
    private String daoImpl = ConstVal.TEMPLATE_DAO_IMPL;
    private String service = ConstVal.TEMPLATE_SERVICE;
    private String serviceImpl = ConstVal.TEMPLATE_SERVICE_IMPL;
    private String controller = ConstVal.TEMPLATE_CONTROLLER;
    public String getEntity() {
        return entity;
    }
    public void setEntity(String entity) {
        this.entity = entity;
    }
    public String getDao() {
        return dao;
    }
    public void setDao(String dao) {
        this.dao = dao;
    }
    public String getDaoImpl() {
        return daoImpl;
    }
    public void setDaoImpl(String daoImpl) {
        this.daoImpl = daoImpl;
    }
    public String getService() {
        return service;
    }
    public void setService(String service) {
        this.service = service;
    }
    public String getServiceImpl() {
        return serviceImpl;
    }
    public void setServiceImpl(String serviceImpl) {
        this.serviceImpl = serviceImpl;
    }
    public String getController() {
        return controller;
    }
    public void setController(String controller) {
        this.controller = controller;
    }
}

# 临时表

新建包名 com.qiyin.base.generator.dto,当前下的所有类都放在这个包下面。

TableInfo

package com.qiyin.base.generator.dto;
import java.util.HashSet;
import java.util.Set;
/**
 * 表信息,关联到当前字段信息
 */
public class TableInfo {
    private Set<String> importPackages = new HashSet<>();
    private String name;
    private String entityName;
    private String daoName;
    private String daoImplName;
    private String serviceName;
    private String serviceImplName;
    private String controllerName;
    /**
     * 数据库模式
     */
    private String schema;
    /**
     * 数据库
     */
    private String tableName;
    /**
     * 字段前缀
     */
    private String tablePrefix;
    public void setImportPackages(String pkg) {
        importPackages.add(pkg);
    }
    public Set<String> getImportPackages() {
        return importPackages;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEntityName() {
        return entityName;
    }
    public void setEntityName(String entityName) {
        this.entityName = entityName;
    }
    public String getDaoName() {
        return daoName;
    }
    public void setDaoName(String daoName) {
        this.daoName = daoName;
    }
    public String getDaoImplName() {
        return daoImplName;
    }
    public void setDaoImplName(String daoImplName) {
        this.daoImplName = daoImplName;
    }
    public String getServiceName() {
        return serviceName;
    }
    public void setServiceName(String serviceName) {
        this.serviceName = serviceName;
    }
    public String getServiceImplName() {
        return serviceImplName;
    }
    public void setServiceImplName(String serviceImplName) {
        this.serviceImplName = serviceImplName;
    }
    public String getControllerName() {
        return controllerName;
    }
    public void setControllerName(String controllerName) {
        this.controllerName = controllerName;
    }
    public String getSchema() {
        return schema;
    }
    public void setSchema(String schema) {
        this.schema = schema;
    }
    public String getTableName() {
        return tableName;
    }
    public void setTableName(String tableName) {
        this.tableName = tableName;
    }
    public String getTablePrefix() {
        return tablePrefix;
    }
    public void setTablePrefix(String tablePrefix) {
        this.tablePrefix = tablePrefix;
    }
}

# 配置汇总

新建包名 com.qiyin.base.generator.builder,当前下的所有类都放在这个包下面。

ConfigBuilder

package com.qiyin.base.generator.builder;
import com.qiyin.base.controller.AbstractController;
import com.qiyin.base.dao.AbstractDao;
import com.qiyin.base.dao.AbstractDaoImpl;
import com.qiyin.base.entity.AbstractEntity;
import com.qiyin.base.generator.config.ConstVal;
import com.qiyin.base.generator.config.GlobalConfig;
import com.qiyin.base.generator.config.PackageConfig;
import com.qiyin.base.generator.config.StringVal;
import com.qiyin.base.generator.config.TemplateConfig;
import com.qiyin.base.generator.dto.TableInfo;
import com.qiyin.base.service.AbstractService;
import com.qiyin.base.service.AbstractServiceImpl;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 配置汇总 传递给文件生成工具
 **/
public class ConfigBuilder {
    /**
     * 模板路径配置信息
     */
    private final TemplateConfig template;
    private String superEntityClass;
    private String superDaoClass;
    private String superDaoImplClass;
    private String superServiceClass;
    private String superServiceImplClass;
    private String superControllerClass;
    /**
     * 全局配置信息
     */
    private GlobalConfig globalConfig;
    /**
     * 包配置详情
     */
    private Map<String, String> packageInfo;
    /**
     * 路径配置信息
     */
    private Map<String, String> pathInfo;
    /**
     * 数据库表信息
     */
    private List<TableInfo> tableInfoList;
    /**
     * 在构造器中处理配置
     *
     * @param packageConfig    包配置
     * @param template         模板配置
     * @param globalConfig     全局配置
     */
    public ConfigBuilder(PackageConfig packageConfig,
                         TemplateConfig template, GlobalConfig globalConfig) {
        this.globalConfig = globalConfig == null ? new GlobalConfig() :globalConfig;
        this.template = template == null ? new TemplateConfig() : template;
        handlerPackage(packageConfig == null ? new PackageConfig() : packageConfig);
        handlerTable();
        handlerSuperClass();
    }
    /**
     * 处理包配置
     *
     * @param config 包配置
     */
    private void handlerPackage(PackageConfig config) {
        if (StringUtils.isBlank(config.getParent())){
            String parent = "com.example." + this.globalConfig.getProject().replace("qiyin-", ""); //
            config.setParent(parent);
        }
        String moduleName = config.getPackageName();
        packageInfo = new HashMap<>(8);
        packageInfo.put(ConstVal.MODULE_NAME, moduleName);
        packageInfo.put(ConstVal.ENTITY, joinPackage(config.getParent() + "." + config.getEntity(), moduleName));
        packageInfo.put(ConstVal.DAO, joinPackage(config.getParent() + "." + config.getDao(), moduleName));
        packageInfo.put(ConstVal.DAO_IMPL, joinPackage(config.getParent() + "." + config.getDaoImpl(), moduleName));
        packageInfo.put(ConstVal.SERVICE, joinPackage(config.getParent() + "." + config.getService(), moduleName));
        packageInfo.put(ConstVal.SERVICE_IMPL, joinPackage(config.getParent() + "." + config.getServiceImpl(), moduleName)); //
        packageInfo.put(ConstVal.CONTROLLER, joinPackage(config.getParent() + "." + config.getController(), moduleName));
        // 自定义路径
        Map<String, String> configPathInfo = config.getPathInfo();
        if (configPathInfo != null){
            pathInfo = configPathInfo;
            return;
        }
        String outputDir = this.globalConfig.getOutputDir();
        // 生成路径信息
        pathInfo = new HashMap<>(8);
        setPathInfo(pathInfo, outputDir, ConstVal.ENTITY_PATH, ConstVal.ENTITY);
        setPathInfo(pathInfo, outputDir, ConstVal.DAO_PATH, ConstVal.DAO);
        setPathInfo(pathInfo, outputDir, ConstVal.DAO_IMPL_PATH, ConstVal.DAO_IMPL);
        setPathInfo(pathInfo, outputDir, ConstVal.SERVICE_PATH, ConstVal.SERVICE);
        setPathInfo(pathInfo, outputDir, ConstVal.SERVICE_IMPL_PATH, ConstVal.SERVICE_IMPL);
        setPathInfo(pathInfo, outputDir, ConstVal.CONTROLLER_PATH, ConstVal.CONTROLLER);
    }
    /**
     * 处理表相关类名称
     */
    private void handlerTable() {
        tableInfoList = new ArrayList<>();
        String[] tables = StringUtils.split(this.globalConfig.getTableName(), StringVal.COMMA);
        for (String table : tables){
            TableInfo tableInfo = new TableInfo();
            String entityName = table + "Entity";
            tableInfo.setName(table);
            tableInfo.setEntityName(entityName);
            tableInfo.setDaoName(table + ConstVal.DAO);
            tableInfo.setDaoImplName(table + ConstVal.DAO_IMPL);
            tableInfo.setServiceName(table + ConstVal.SERVICE);
            tableInfo.setServiceImplName(table + ConstVal.SERVICE_IMPL);
            tableInfo.setControllerName(table + ConstVal.CONTROLLER);
            tableInfoList.add(tableInfo);
        }
    }
    /**
     * 处理父类
     */
    private void handlerSuperClass() {
        switch (globalConfig.getClassType()){
            case ConstVal.MODEL_NORMAL:
                this.superEntityClass = AbstractEntity.class.getName();
                this.superDaoClass = AbstractDao.class.getName();
                this.superDaoImplClass = AbstractDaoImpl.class.getName();
                this.superServiceClass = AbstractService.class.getName();
                this.superServiceImplClass = AbstractServiceImpl.class.getName();
                this.superControllerClass = AbstractController.class.getName();
                break;
            case ConstVal.MODEL_OTHER:
                this.superEntityClass = null;
                this.superDaoClass = null;
                this.superDaoImplClass = null;
                this.superServiceClass = null;
                this.superServiceImplClass = null;
                this.superControllerClass = null;
                break;
            default:
                break;
        }
    }
    private void setPathInfo(Map<String, String> pathInfo, String outputDir, String path, String classPath) {
        String tempOutputDir = outputDir + StringVal.BACK_SLASH + globalConfig.getProject() + StringVal.BACK_SLASH + globalConfig.getProject();
        switch (path){
            case ConstVal.ENTITY_PATH:
                tempOutputDir = tempOutputDir + "-entity";
                break;
            case ConstVal.DAO_PATH:
            case ConstVal.DAO_IMPL_PATH:
                tempOutputDir = tempOutputDir + "-dao";
                break;
            case ConstVal.SERVICE_PATH:
            case ConstVal.SERVICE_IMPL_PATH:
                tempOutputDir = tempOutputDir + "-service";
                break;
            case ConstVal.CONTROLLER_PATH:
                tempOutputDir = tempOutputDir + "-controller";
        }
        pathInfo.put(path, joinPath(tempOutputDir , "src.main.java." + packageInfo.get(classPath)));
    }
    /**
     * 连接路径字符串
     *
     * @param parentDir   父目录
     * @param packageName 包名
     * @return 连接后的路径
     */
    private String joinPath(String parentDir, String packageName) {
        if (StringUtils.isBlank(parentDir)) {
            parentDir = System.getProperty(ConstVal.JAVA_TMPDIR);
        }
        if (!StringUtils.endsWith(parentDir, File.separator)){
            parentDir += File.separator;
        }
        packageName = packageName.replaceAll("\\.", "\\" + File.separator);
        return parentDir + packageName;
    }
    /**
     * 连接父子包名
     *
     * @param parentPackage 父包名
     * @param subPackage 子包名
     * @return 连接后的包名
     */
    private String joinPackage(String parentPackage, String subPackage) {
        if (StringUtils.isBlank(parentPackage)){
            return subPackage;
        }
        return parentPackage + "." + subPackage;
    }
    /**
     * 所有包配置信息
     *
     * @return 包配置
     */
    public Map<String, String> getPackageInfo() {
        return packageInfo;
    }
    /**
     * 所有路径配置
     *
     * @return 路径配置
     */
    public Map<String, String> getPathInfo() {
        return pathInfo;
    }
    public String getSuperEntityClass() {
        return superEntityClass;
    }
    public String getSuperDaoClass() {
        return superDaoClass;
    }
    public String getSuperDaoImplClass() {
        return superDaoImplClass;
    }
    public String getSuperServiceClass() {
        return superServiceClass;
    }
    public String getSuperServiceImplClass() {
        return superServiceImplClass;
    }
    public String getSuperControllerClass() {
        return superControllerClass;
    }
    /**
     * 模板路径配置信息
     *
     * @return 所以模板路径配置信息
     */
    public TemplateConfig getTemplate() {
        return template == null ? new TemplateConfig() : template;
    }
    public GlobalConfig getGlobalConfig() {
        return globalConfig;
    }
    public List<TableInfo> getTableInfoList() {
        return tableInfoList;
    }
    public ConfigBuilder setTableInfoList(List<TableInfo> tableInfoList) {
        this.tableInfoList = tableInfoList;
        return this;
    }
}

# 模板引擎

新建包名 com.qiyin.base.generator.engine,当前下的所有类都放在这个包下面。

AbstractTemplateEngine

package com.qiyin.base.generator.engine;
import com.qiyin.base.generator.builder.ConfigBuilder;
import com.qiyin.base.generator.config.ConstVal;
import com.qiyin.base.generator.config.GlobalConfig;
import com.qiyin.base.generator.config.StringVal;
import com.qiyin.base.generator.config.TemplateConfig;
import com.qiyin.base.generator.dto.TableInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 模板引擎抽象类
 */
public abstract class AbstractTemplateEngine {
    protected static final Logger LOG = LoggerFactory.getLogger(AbstractTemplateEngine.class);
    /**
     * 配置信息
     */
    private ConfigBuilder configBuilder;
    /**
     * 模板引擎初始化
     */
    public AbstractTemplateEngine init(ConfigBuilder configBuilder) {
        this.configBuilder = configBuilder;
        return this;
    }
    /**
     * 输出 java xml 文件
     */
    public AbstractTemplateEngine batchOutput(){
        try {
            List<TableInfo> tables = getConfigBuilder().getTableInfoList();
            for (TableInfo table : tables){
                Map<String, Object> objectMap = getObjectMap(table);
                create(table, objectMap);
            }
        }catch (Exception e){
            LOG.error("无法创建文件,请检查配置信息是否正确!", e);
        }
        return this;
    }
    private Map<String, Object> getObjectMap(TableInfo table) {
        Map<String, Object> objectMap = new HashMap<>(32);
        ConfigBuilder config = getConfigBuilder();
        objectMap.put("config", config);
        objectMap.put("package", config.getPackageInfo());
        GlobalConfig globalConfig = config.getGlobalConfig();
        objectMap.put("author", globalConfig.getAuthor());
        objectMap.put("comment", globalConfig.getComment());
        objectMap.put("schema", globalConfig.getSchema());
        objectMap.put("tableName", globalConfig.getDataTableName());
        objectMap.put("tablePrefix", globalConfig.getDataTablePrefix());
        objectMap.put("kotlin", globalConfig.isKotlin());
        objectMap.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        objectMap.put("table", table);
        objectMap.put("entity", table.getEntityName());
        objectMap.put("superEntityClassPackage", config.getSuperEntityClass());
        objectMap.put("superEntityClass", getSuperClassName(config.getSuperEntityClass()));
        objectMap.put("superDaoClassPackage", config.getSuperDaoClass());
        objectMap.put("superDaoClass", getSuperClassName(config.getSuperDaoClass()));
        objectMap.put("superDaoImplClassPackage", config.getSuperDaoImplClass());
        objectMap.put("superDaoImplClass", getSuperClassName(config.getSuperDaoImplClass()));
        objectMap.put("superServiceClassPackage", config.getSuperServiceClass());
        objectMap.put("superServiceClass", getSuperClassName(config.getSuperServiceClass()));
        objectMap.put("superServiceImplClassPackage", config.getSuperServiceImplClass());
        objectMap.put("superServiceImplClass", getSuperClassName(config.getSuperServiceImplClass()));
        objectMap.put("superControllerClassPackage", config.getSuperControllerClass());
        objectMap.put("superControllerClass", getSuperClassName(config.getSuperControllerClass()));
        return objectMap;
    }
    private void create(TableInfo table, Map<String, Object> objectMap) throws Exception{
        Map<String, String> pathInfo = getConfigBuilder().getPathInfo();
        TemplateConfig template = getConfigBuilder().getTemplate();
        // Entity.java
        String entityName = table.getEntityName();
        if (entityName != null && pathInfo.get(ConstVal.ENTITY_PATH) != null){
            String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + suffixJavaOrKt()), entityName);
            if (isCreate(entityFile)){
                writer(objectMap, templateFilePath(template.getEntity()), entityFile);
            }
        }
        // Dao.java
        if (null != table.getDaoName() && null != pathInfo.get(ConstVal.DAO_PATH)) {
            String daoFile = String.format((pathInfo.get(ConstVal.DAO_PATH) + File.separator + table.getDaoName() + suffixJavaOrKt()), entityName);
            if (isCreate(daoFile)) {
                writer(objectMap, templateFilePath(template.getDao()), daoFile);
            }
        }
        // DaoImpl.java
        if (null != table.getDaoImplName() && null != pathInfo.get(ConstVal.DAO_IMPL_PATH)) {
            String daoImplFile = String.format((pathInfo.get(ConstVal.DAO_IMPL_PATH) + File.separator + table.getDaoImplName() + suffixJavaOrKt()), entityName);
            if (isCreate(daoImplFile)) {
                writer(objectMap, templateFilePath(template.getDaoImpl()), daoImplFile);
            }
        }
        // Service.java
        if (null != table.getServiceName() && null != pathInfo.get(ConstVal.SERVICE_PATH)) {
            String serviceFile = String.format((pathInfo.get(ConstVal.SERVICE_PATH) + File.separator + table.getServiceName() + suffixJavaOrKt()), entityName);
            if (isCreate(serviceFile)) {
                writer(objectMap, templateFilePath(template.getService()), serviceFile);
            }
        }
        // ServiceImpl.java
        if (null != table.getServiceImplName() && null != pathInfo.get(ConstVal.SERVICE_IMPL_PATH)) {
            String serviceImplFile = String.format((pathInfo.get(ConstVal.SERVICE_IMPL_PATH) + File.separator + table.getServiceImplName() + suffixJavaOrKt()), entityName);
            if (isCreate(serviceImplFile)) {
                writer(objectMap, templateFilePath(template.getServiceImpl()), serviceImplFile);
            }
        }
        // Controller.java
        if (null != table.getServiceImplName() && null != pathInfo.get(ConstVal.CONTROLLER_PATH)) {
            String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + table.getControllerName() + suffixJavaOrKt()), entityName);
            if (isCreate(controllerFile)) {
                writer(objectMap, templateFilePath(template.getController()), controllerFile);
            }
        }
    }
    /**
     * 检查文件是否存在
     *
     * @param filePath 文件路径
     * @return 是否存在
     */
    private boolean isCreate(String filePath) {
        ConfigBuilder config = getConfigBuilder();
        // TODO 自定义判断
        // 全局判断【默认】
        File file = new File(filePath);
        boolean exists = file.exists();
        if (!exists){
            file.getParentFile().mkdirs();
        }
        return !exists || getConfigBuilder().getGlobalConfig().isFileOverride();
    }
    public abstract String templateFilePath(String filePath);
    protected abstract void writer(Map<String, Object> objectMap, String templateFilePath, String entityFile) throws Exception;
    public AbstractTemplateEngine mkdirs(){
        getConfigBuilder().getPathInfo().forEach((key, value) -> {
            File file = new File(value);
            if (!file.exists()){
                boolean result = file.mkdirs();
                if (result){
                    LOG.info("创建目录:[" + value + "]");
                }
            }
        });
        return this;
    }
    private String getSuperClassName(String classPath) {
        if (StringUtils.isBlank(classPath)){
            return null;
        }
        return classPath.substring(classPath.lastIndexOf(StringVal.DOT) + 1);
    }
    private String suffixJavaOrKt() {
        return getConfigBuilder().getGlobalConfig().isKotlin() ? ConstVal.KT_SUFFIX : ConstVal.JAVA_SUFFIX;
    }
    public ConfigBuilder getConfigBuilder() {
        return configBuilder;
    }
}

FreemarkerTemplateEngine

package com.qiyin.base.generator.engine;
import com.qiyin.base.generator.builder.ConfigBuilder;
import freemarker.template.Configuration;
import freemarker.template.Template;
import com.qiyin.base.generator.config.ConstVal;
import com.qiyin.base.generator.config.StringVal;
import java.io.FileOutputStream;
import java.io.OutputStreamWriter;
import java.util.Map;
/**
 * Freemarker 模板引擎实现文件输出
 */
public class FreemarkerTemplateEngine extends AbstractTemplateEngine {
    private Configuration configuration;
    @Override
    public AbstractTemplateEngine init(ConfigBuilder configBuilder) {
        super.init(configBuilder);
        configuration = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
        configuration.setDefaultEncoding(ConstVal.UTF8);
        configuration.setClassForTemplateLoading(FreemarkerTemplateEngine.class, StringVal.SLASH);
        return this;
    }
    @Override
    public String templateFilePath(String filePath) {
        return filePath + ".ftl";
    }
    @Override
    protected void writer(Map<String, Object> objectMap, String templateFilePath, String outputFile) throws Exception {
        Template template = configuration.getTemplate(templateFilePath);
        try(FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {
            template.process(objectMap, new OutputStreamWriter(fileOutputStream, ConstVal.UTF8));
        }
        LOG.debug("模板:" + templateFilePath + ";  文件:" + outputFile);
    }
}

# 模板代码

在 resources 下面新建包名 templates,以下文件均放在此包下。

entity.java.ftl

package ${package.Entity};
<#if superEntityClassPackage??>
import ${superEntityClassPackage};
<#else>
import javax.persistence.Id;
</#if>
import io.swagger.annotations.ApiModel;
import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;
/**
 * ${comment} 实体类
 *
 * @author ${author}
 * @date ${date}
 */
@Entity
@Table(schema = "${schema}", name = "${tableName}")
<#if superEntityClass??>
@AttributeOverrides({
        @AttributeOverride(name = "id", column = @Column(name = "${tablePrefix}_id", updatable = false, length = 40))
})
</#if>
@ApiModel(description = "${comment}")
<#if superEntityClass??>
public class ${table.entityName} extends ${superEntityClass} {
<#else>
public class ${table.entityName} {
    @Id
    private String id;
</#if>
}

dao.java.ftl

package ${package.Dao};
import org.springframework.stereotype.Repository;
import ${package.Entity}.${table.entityName};
<#if superDaoClassPackage??>
import ${superDaoClassPackage};
</#if>
/**
 * ${comment} 数据仓库
 *
 * @author ${author}
 * @date ${date}
 */
<#if superDaoClass??>
@Repository
public interface ${table.daoName} extends ${superDaoClass}<${table.entityName}, String> {
<#else>
public interface ${table.daoName} {
</#if>
}

daoImpl.java.ftl

package ${package.DaoImpl};
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ${package.Entity}.${table.entityName};
<#if superDaoImplClassPackage??>
import ${superDaoImplClassPackage};
<#else>
import org.springframework.stereotype.Repository;
</#if>
/**
 * ${comment} 数据仓库实现
 *
 * @author ${author}
 * @date ${date}
 */
<#if superDaoImplClass??>
public class ${table.daoImplName} extends ${superDaoImplClass}<${table.entityName}> {
    private static final Logger LOG = LoggerFactory.getLogger(${table.daoImplName}.class);
    public ${table.daoImplName}() {
        super(${table.entityName}.class);
    }
<#else>
@Repository
public class ${table.daoImplName} implements ${table.daoName}{
</#if>
}

service.java.ftl

package ${package.Service};
import ${package.Entity}.${table.entityName};
<#if superServiceClassPackage??>
import ${superServiceClassPackage};
</#if>
/**
 * ${comment} DAO 接口
 *
 * @author ${author}
 * @date ${date}
 */
<#if superEntityClass??>
public interface ${table.serviceName} extends ${superServiceClass}<${table.entityName}> {
<#else>
public interface ${table.serviceName} {
</#if>
}

serviceImpl.java.ftl

package ${package.ServiceImpl};
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ${package.Entity}.${table.entityName};
import ${package.Dao}.${table.daoName};
import ${package.Service}.${table.serviceName};
<#if superServiceImplClassPackage??>
import ${superServiceImplClassPackage};
</#if>
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * ${comment} DAO 实现
 *
 * @author ${author}
 * @date ${date}
 */
<#if superServiceImplClass??>
@Component
public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.entityName}>
 implements ${table.serviceName} {
    private static final Logger LOG = LoggerFactory.getLogger(${table.serviceImplName}.class);
    @Autowired
    private ${table.daoName} ${table.daoName?uncap_first};
    public ${table.serviceImplName}() {
	    super(${table.entityName}.class);
    }
    @Override
    public ${table.daoName} getBaseDao() {
	    return ${table.daoName?uncap_first};
    }
<#else>
@Component
public class ${table.serviceImplName} implements ${table.serviceName}{
    private static final Logger LOG = LoggerFactory.getLogger(${table.serviceImplName}.class);
    @Autowired
    private ${table.daoName} ${table.daoName?uncap_first};
</#if>
}

controller.java.ftl

package ${package.Controller};
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import ${package.Entity}.${table.entityName};
import ${package.Service}.${table.serviceName};
<#if superControllerClassPackage??>
import ${superControllerClassPackage};
</#if>
import org.springframework.beans.factory.annotation.Autowired;
/**
 * ${comment} DAO 实现
 *
 * @author ${author}
 * @date ${date}
 */
<#if superControllerClass??>
@RestController
@RequestMapping(value = "/${tableName}")
public class ${table.controllerName} extends ${superControllerClass}<${table.entityName}>{
    private static final Logger LOG = LoggerFactory.getLogger(${table.controllerName}.class);
    @Autowired
    private ${table.serviceName} ${table.serviceName?uncap_first};
    @Override
    public ${table.serviceName} getBaseService() {
	    return ${table.serviceName?uncap_first};
    }
<#else>
@RestController
@RequestMapping(value = "/${tableName}")
public class ${table.controllerName} {
    private static final Logger LOG = LoggerFactory.getLogger(${table.controllerName}.class);
    @Autowired
    private ${table.serviceName} ${table.serviceName?uncap_first};
</#if>
}

# 自动生成类

放在包 com.qiyin.base.generator 下面。

AutoGenerator

package com.qiyin.base.generator;
import com.qiyin.base.generator.builder.ConfigBuilder;
import com.qiyin.base.generator.config.GlobalConfig;
import com.qiyin.base.generator.config.PackageConfig;
import com.qiyin.base.generator.config.TemplateConfig;
import com.qiyin.base.generator.dto.TableInfo;
import com.qiyin.base.generator.engine.AbstractTemplateEngine;
import com.qiyin.base.generator.engine.FreemarkerTemplateEngine;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
 * 自动生成
 */
public class AutoGenerator {
    private static final Logger LOG = LoggerFactory.getLogger(AutoGenerator.class);
    /**
     * 配置信息
     */
    protected ConfigBuilder config;
    /**
     * 包 相关配置
     */
    private PackageConfig packageInfo;
    /**
     * 模板 相关配置
     */
    private TemplateConfig template;
    /**
     * 全局 相关配置
     */
    private GlobalConfig globalConfig;
    /**
     * 模板引擎
     */
    private AbstractTemplateEngine templateEngine;
    public void execute(){
        LOG.info("=================准备生成文件...=================");
        if (config == null){
            config = new ConfigBuilder(packageInfo, template, globalConfig);
        }
        if (templateEngine == null){
            // 默认采用 Velocity 引擎
            templateEngine = new FreemarkerTemplateEngine();
        }
        // 模板引擎初始化执行文件输出
        templateEngine.init(pretreatmentConfigBuilder(config)).mkdirs().batchOutput();
        LOG.info("=================文件生成完成...=================");
    }
    /**
     * 预处理配置
     *
     * @param config 总配置信息
     * @return 解析数据结果集
     */
    private ConfigBuilder pretreatmentConfigBuilder(ConfigBuilder config) {
        // 表信息列表
        List<TableInfo> tables = getAllTableInfoList(config);
        for (TableInfo table : tables){
            boolean importSerializable = true;
            if (StringUtils.isNotBlank(config.getSuperEntityClass())) {
                // 父实体
                table.setImportPackages(config.getSuperEntityClass());
                importSerializable = false;
            }
        }
        return config.setTableInfoList(tables);
    }
    /**
     * 开放表信息、预留子类重写
     *
     * @param config 配置信息
     * @return ignore
     */
    protected List<TableInfo> getAllTableInfoList(ConfigBuilder config) {
        return config.getTableInfoList();
    }
    public AutoGenerator setPackageInfo(PackageConfig packageInfo) {
        this.packageInfo = packageInfo;
        return this;
    }
    public AutoGenerator setTemplate(TemplateConfig template) {
        this.template = template;
        return this;
    }
    public AutoGenerator setGlobalConfig(GlobalConfig globalConfig) {
        this.globalConfig = globalConfig;
        return this;
    }
}

Main

package com.qiyin.base.generator;
import com.qiyin.base.generator.config.ConstVal;
import com.qiyin.base.generator.config.GlobalConfig;
import com.qiyin.base.generator.config.PackageConfig;
import java.util.ArrayList;
import java.util.List;
public class Main {
    public static void main(String[] args) {
        List<Table> tables = new ArrayList<>();
        tables.add(new Table("goods", "Goods", "学生实体", "qiyin", "goods", "goods", "g"));
        createTables(tables);
    }
    private static void createTables(List<Table> tables) {
        tables.forEach(table ->
                new AutoGenerator().
                        setGlobalConfig(
                                new GlobalConfig()
                            		// 作者
                                    .setAuthor(table.getAuthor())
                            		// 生成的代码在哪个模块里
                                    .setProject("business")
                            		// 实体描述信息
                                    .setComment(table.getComment())
                            		// 实体名
                                    .setTableName(table.getName())
                            		// 生成类的样式
                                    .setClassType(ConstVal.MODEL_OTHER)
                            		// 当前项目所在的文件目录
                                    .setOutputDir("D:\\code\\project")
                            		// 表模式
                                    .setSchema(table.getSchema())
                            		// 数据表名
                                    .setDataTableName(table.getTableName())
                            		// 数据表字段前缀
                                    .setDataTablePrefix(table.getTablePrefix())
                        )
            .setPackageInfo(new PackageConfig().setPackageName(table.getModel())).execute());
    }
}
class Table {
    public Table(String model, String name, String comment, String author, String schema, String tableName, String tablePrefix) {
        this.model = model;
        this.comment = comment;
        this.name = name;
        this.author = author;
        this.schema = schema;
        this.tableName = tableName;
        this.tablePrefix = tablePrefix;
    }
    // 模块分包名
    private String model;
    // 描述信息
    private String comment;
    // 表名
    private String name;
    // 作者
    private String author;
    // 数据库模式
    private String schema;
    // 数据库
    private String tableName;
    // 字段前缀
    private String tablePrefix;
    //get/set 省略
}

到此自动生成相关的实现已经结束。

# 扩展

在 base 模块下,新建 entity、dao、daoImpl、service、serviceImpl 和 controller 基类。

AbstactEntity

package com.qiyin.base.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;
import java.time.LocalDate;
@MappedSuperclass
@ApiModel(value = "基类实体")
public abstract class AbstractEntity implements Serializable {
    @ApiModelProperty(value = "主键")
    @Id
    private String id;
    @ApiModelProperty(value = "创建时间")
    @Column(name = "insert")
    private LocalDate insert;
    @ApiModelProperty(value = "数据状态")
    @Column(name = "status")
    private String status;
    //get/set 省略...
}

AbstractDao

package com.qiyin.base.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import java.util.List;
/**
 * 抽象实体数据层
 *
 * @param <T> 实体
 * @param <ID>
 */
public interface AbstractDao<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
    List<T> queryAll();
}

AbstractDaoImpl

package com.qiyin.base.dao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import java.util.List;
/**
 * 抽象实体数据实现层
 *
 * @param <T> 实体
 */
public abstract class AbstractDaoImpl<T>{
    protected static final Logger LOG = LoggerFactory.getLogger(AbstractDaoImpl.class);
    @PersistenceContext
    protected EntityManager em;
    protected Class<T> entityClass;
    public AbstractDaoImpl(Class<T> entityClass) {
        this.entityClass = entityClass;
    }
    /**
     * 查询所有实体数据.
     *
     * @return 实体列表
     */
    public List<T> queryAll() {
        CriteriaBuilder builder = this.em.getCriteriaBuilder();
        CriteriaQuery<T> query = builder.createQuery(entityClass);
        Root<T> root = query.from(entityClass);
        query.select(root);
        return em.createQuery(query).getResultList();
    }
}

AbstractService

package com.qiyin.base.service;
import com.qiyin.base.entity.AbstractEntity;
import java.util.List;
/**
 * 抽象实体服务层
 *
 * @param <T> 实体类
 */
public interface AbstractService<T extends AbstractEntity> {
    List<T> queryAll();
}

AbstractServiceImpl

package com.qiyin.base.service;
import com.qiyin.base.dao.AbstractDao;
import com.qiyin.base.entity.AbstractEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
 * 抽象实体服务实现层
 */
public abstract class AbstractServiceImpl<T extends AbstractEntity> implements AbstractService<T>{
    private static final Logger LOG = LoggerFactory.getLogger(AbstractServiceImpl.class);
    /**
     * 主实体类.
     */
    protected Class<T> entityClass;
    public AbstractServiceImpl(Class<T> entityClass) {
        this.entityClass = entityClass;
    }
    /**
     * 获取实体数据层对象.
     *
     * @return 实体数据层对象
     */
    protected abstract AbstractDao<T, String> getBaseDao();
    @Override
    public List<T> queryAll() {
        return this.getBaseDao().queryAll();
    }
}

AbstractController

package com.qiyin.base.controller;
import com.qiyin.base.entity.AbstractEntity;
import com.qiyin.base.service.AbstractService;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
/**
 * 抽象 REST 服务层
 */
public abstract class AbstractController<T extends AbstractEntity> {
    private static final Logger LOG = LoggerFactory.getLogger(AbstractController.class);
    /**
     * 获取抽象业务接口.
     *
     * @return 抽象业务接口
     */
    public abstract AbstractService<T> getBaseService();
    @ApiOperation(value = "获取所有实体数据")
    @GetMapping(value = "/queryAll")
    public List<T> queryAll() {
        return this.getBaseService().queryAll();
    }
}

Main 类中的 setClassType,设置为 MODEL_NORMAL,即可将所有自动生成的类继承至基类。

# 测试

  1. 在 PostgreSQL 数据库中新建 goods 模式,在此模式下新建数据表 goods,字段任意。(也可以使用这篇文章自动生成建表 SQL,根据实体自动生成建表 SQL 语句。)

  2. 启动 main 方法,将会在 business 模块下的四个子模块分别生成对应的代码。

  3. 可以新建一个启动模块用来启动 business 模块中的项目,也可以直接在 controller 层下的新建一个 MainApplication 启动类。

    package com.example.business;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.domain.EntityScan;
    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
    @EntityScan({
            "com.example.business.entity"
    })
    @EnableJpaRepositories({
            "com.example.business.dao"
    })
    @ComponentScan({
            "com.example.business.dao",
            "com.example.business.service",
            "com.example.business.controller"
    })
    @SpringBootApplication
    public class MainApplication {
        public static void main(String[] args) {
            SpringApplication.run(MainApplication.class, args);
        }
    }
  4. 在对应的启动类下面的 resources 里面新建 application.yml 文件。

    spring:
        datasource:
          driver-class-name: org.postgresql.Driver
          url: jdbc:postgresql://localhost:5432/test
          username: postgres
          password: 123456
    server:
      port: 8080
  5. 启动 MainApplication

  6. 如果生成的类样式设置的是 MODEL_OTHER,则需要手动在生成的代码中编写对应的接口以及实现,在浏览器中输入 http://localhost:8888/goods/ 接口名,出现与自己所写的结果一致,即成功!

  7. 如果生成的类样式设置的是 MODEL_NORMAL,在浏览器中输入 http://localhost:8888/goods/queryAll,出现数据即成功!

更新于

请我喝[茶]~( ̄▽ ̄)~*

七音 微信支付

微信支付

七音 支付宝

支付宝