/** * Copyright (c) 2011-2020, hubin (jobob@qq.com). * <p> * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * <p> * http://www.apache.org/licenses/LICENSE-2.0 * <p> * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.baomidou.mybatisplus.generator.config.builder; import com.baomidou.mybatisplus.generator.config.*; import com.baomidou.mybatisplus.generator.config.po.TableField; import com.baomidou.mybatisplus.generator.config.po.TableInfo; import com.baomidou.mybatisplus.generator.config.rules.DbType; import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy; import com.baomidou.mybatisplus.generator.config.rules.QuerySQL; import com.baomidou.mybatisplus.toolkit.StringUtils; import java.io.File; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.*; /** * 配置汇总 传递给文件生成工具 * * @author YangHu, tangguo, hubin * @since 2016-08-30 */ public class ConfigBuilder { /** * 模板路径配置信息 */ private final TemplateConfig template; /** * 数据库配置 */ private final DataSourceConfig dataSourceConfig; /** * SQL连接 */ private Connection connection; /** * SQL语句类型 */ private QuerySQL querySQL; private String superEntityClass; private String superMapperClass; /** * service超类定义 */ private String superServiceClass; private String superServiceImplClass; private String superControllerClass; /** * 数据库表信息 */ private List<TableInfo> tableInfoList; /** * 包配置详情 */ private Map<String, String> packageInfo; /** * 路径配置信息 */ private Map<String, String> pathInfo; /** * 策略配置 */ private StrategyConfig strategyConfig; /** * 全局配置信息 */ private GlobalConfig globalConfig; /** * 在构造器中处理配置 * * @param packageConfig 包配置 * @param dataSourceConfig 数据源配置 * @param strategyConfig 表配置 * @param template 模板配置 * @param globalConfig 全局配置 */ public ConfigBuilder(PackageConfig packageConfig, DataSourceConfig dataSourceConfig, StrategyConfig strategyConfig, TemplateConfig template, GlobalConfig globalConfig) { // 全局配置 if (null == globalConfig) { this.globalConfig = new GlobalConfig(); } else { this.globalConfig = globalConfig; } // 模板配置 if (null == template) { this.template = new TemplateConfig(); } else { this.template = template; } // 包配置 if (null == packageConfig) { handlerPackage(this.template, this.globalConfig.getOutputDir(), new PackageConfig()); } else { handlerPackage(this.template, this.globalConfig.getOutputDir(), packageConfig); } this.dataSourceConfig = dataSourceConfig; handlerDataSource(dataSourceConfig); // 策略配置 if (null == strategyConfig) { this.strategyConfig = new StrategyConfig(); } else { this.strategyConfig = strategyConfig; } handlerStrategy(this.strategyConfig); } // ************************ 曝露方法 BEGIN***************************** /** * 所有包配置信息 * * @return 包配置 */ public Map<String, String> getPackageInfo() { return packageInfo; } /** * 所有路径配置 * * @return 路径配置 */ public Map<String, String> getPathInfo() { return pathInfo; } public String getSuperEntityClass() { return superEntityClass; } public String getSuperMapperClass() { return superMapperClass; } /** * 获取超类定义 * * @return 完整超类名称 */ public String getSuperServiceClass() { return superServiceClass; } public String getSuperServiceImplClass() { return superServiceImplClass; } public String getSuperControllerClass() { return superControllerClass; } /** * 表信息 * * @return 所有表信息 */ public List<TableInfo> getTableInfoList() { return tableInfoList; } /** * 模板路径配置信息 * * @return 所以模板路径配置信息 */ public TemplateConfig getTemplate() { return template == null ? new TemplateConfig() : template; } // ****************************** 曝露方法 END********************************** /** * 处理包配置 * * @param template TemplateConfig * @param outputDir * @param config PackageConfig */ private void handlerPackage(TemplateConfig template, String outputDir, PackageConfig config) { packageInfo = new HashMap<>(); packageInfo.put(ConstVal.MODULENAME, config.getModuleName()); packageInfo.put(ConstVal.ENTITY, joinPackage(config.getParent(), config.getEntity())); packageInfo.put(ConstVal.MAPPER, joinPackage(config.getParent(), config.getMapper())); packageInfo.put(ConstVal.XML, joinPackage(config.getParent(), config.getXml())); packageInfo.put(ConstVal.SERIVCE, joinPackage(config.getParent(), config.getService())); packageInfo.put(ConstVal.SERVICEIMPL, joinPackage(config.getParent(), config.getServiceImpl())); packageInfo.put(ConstVal.CONTROLLER, joinPackage(config.getParent(), config.getController())); // 生成路径信息 pathInfo = new HashMap<>(); if (StringUtils.isNotEmpty(template.getEntity())) { pathInfo.put(ConstVal.ENTITY_PATH, joinPath(outputDir, packageInfo.get(ConstVal.ENTITY))); } if (StringUtils.isNotEmpty(template.getMapper())) { pathInfo.put(ConstVal.MAPPER_PATH, joinPath(outputDir, packageInfo.get(ConstVal.MAPPER))); } if (StringUtils.isNotEmpty(template.getXml())) { pathInfo.put(ConstVal.XML_PATH, joinPath(outputDir, packageInfo.get(ConstVal.XML))); } if (StringUtils.isNotEmpty(template.getService())) { pathInfo.put(ConstVal.SERIVCE_PATH, joinPath(outputDir, packageInfo.get(ConstVal.SERIVCE))); } if (StringUtils.isNotEmpty(template.getServiceImpl())) { pathInfo.put(ConstVal.SERVICEIMPL_PATH, joinPath(outputDir, packageInfo.get(ConstVal.SERVICEIMPL))); } if (StringUtils.isNotEmpty(template.getController())) { pathInfo.put(ConstVal.CONTROLLER_PATH, joinPath(outputDir, packageInfo.get(ConstVal.CONTROLLER))); } } /** * 处理数据源配置 * * @param config DataSourceConfig */ private void handlerDataSource(DataSourceConfig config) { connection = config.getConn(); querySQL = getQuerySQL(config.getDbType()); } /** * 处理数据库表 加载数据库表、列、注释相关数据集 * * @param config StrategyConfig */ private void handlerStrategy(StrategyConfig config) { processTypes(config); tableInfoList = getTablesInfo(config); } /** * 处理superClassName,IdClassType,IdStrategy配置 * * @param config 策略配置 */ private void processTypes(StrategyConfig config) { if (StringUtils.isEmpty(config.getSuperServiceClass())) { superServiceClass = ConstVal.SUPERD_SERVICE_CLASS; } else { superServiceClass = config.getSuperServiceClass(); } if (StringUtils.isEmpty(config.getSuperServiceImplClass())) { superServiceImplClass = ConstVal.SUPERD_SERVICEIMPL_CLASS; } else { superServiceImplClass = config.getSuperServiceImplClass(); } if (StringUtils.isEmpty(config.getSuperMapperClass())) { superMapperClass = ConstVal.SUPERD_MAPPER_CLASS; } else { superMapperClass = config.getSuperMapperClass(); } superEntityClass = config.getSuperEntityClass(); superControllerClass = config.getSuperControllerClass(); } /** * 处理表对应的类名称 * * @param tableList 表名称 * @param strategy 命名策略 * @param tablePrefix * @return 补充完整信息后的表 */ private List<TableInfo> processTable(List<TableInfo> tableList, NamingStrategy strategy, String[] tablePrefix) { for (TableInfo tableInfo : tableList) { tableInfo.setEntityName(strategyConfig, NamingStrategy.capitalFirst(processName(tableInfo.getName(), strategy, tablePrefix))); if (StringUtils.isNotEmpty(globalConfig.getMapperName())) { tableInfo.setMapperName(String.format(globalConfig.getMapperName(), tableInfo.getEntityName())); } else { tableInfo.setMapperName(tableInfo.getEntityName() + ConstVal.MAPPER); } if (StringUtils.isNotEmpty(globalConfig.getXmlName())) { tableInfo.setXmlName(String.format(globalConfig.getXmlName(), tableInfo.getEntityName())); } else { tableInfo.setXmlName(tableInfo.getEntityName() + ConstVal.MAPPER); } if (StringUtils.isNotEmpty(globalConfig.getServiceName())) { tableInfo.setServiceName(String.format(globalConfig.getServiceName(), tableInfo.getEntityName())); } else { tableInfo.setServiceName("I" + tableInfo.getEntityName() + ConstVal.SERIVCE); } if (StringUtils.isNotEmpty(globalConfig.getServiceImplName())) { tableInfo.setServiceImplName(String.format(globalConfig.getServiceImplName(), tableInfo.getEntityName())); } else { tableInfo.setServiceImplName(tableInfo.getEntityName() + ConstVal.SERVICEIMPL); } if (StringUtils.isNotEmpty(globalConfig.getControllerName())) { tableInfo.setControllerName(String.format(globalConfig.getControllerName(), tableInfo.getEntityName())); } else { tableInfo.setControllerName(tableInfo.getEntityName() + ConstVal.CONTROLLER); } } return tableList; } /** * 获取所有的数据库表信息 * * @return 表信息 */ private List<TableInfo> getTablesInfo(StrategyConfig config) { boolean isInclude = (null != config.getInclude() && config.getInclude().length > 0); boolean isExclude = (null != config.getExclude() && config.getExclude().length > 0); if (isInclude && isExclude) { throw new RuntimeException("<strategy> 标签中 <include> 与 <exclude> 只能配置一项!"); } //所有的表信息 List<TableInfo> tableList = new ArrayList<>(); //需要反向生成或排除的表信息 List<TableInfo> includeTableList = new ArrayList<>(); List<TableInfo> excludeTableList = new ArrayList<>(); //不存在的表名 Set<String> notExistTables = new HashSet<>(); NamingStrategy strategy = config.getNaming(); PreparedStatement preparedStatement = null; try { preparedStatement = connection.prepareStatement(querySQL.getTableCommentsSql()); ResultSet results = preparedStatement.executeQuery(); TableInfo tableInfo; while (results.next()) { String tableName = results.getString(querySQL.getTableName()); if (StringUtils.isNotEmpty(tableName)) { String tableComment = results.getString(querySQL.getTableComment()); tableInfo = new TableInfo(); tableInfo.setName(tableName); tableInfo.setComment(tableComment); if (isInclude) { for (String includeTab : config.getInclude()) { if (includeTab.equalsIgnoreCase(tableName)) { includeTableList.add(tableInfo); } else { notExistTables.add(includeTab); } } } else if (isExclude) { for (String excludeTab : config.getExclude()) { if (excludeTab.equalsIgnoreCase(tableName)) { excludeTableList.add(tableInfo); } else { notExistTables.add(excludeTab); } } } tableList.add(this.convertTableFields(tableInfo, strategy)); } else { System.err.println("当前数据库为空!!!"); } } // 将已经存在的表移除,获取配置中数据库不存在的表 for (TableInfo tabInfo : tableList) { notExistTables.remove(tabInfo.getName()); } if (notExistTables.size() > 0) { System.err.println("表 " + notExistTables + " 在数据库中不存在!!!"); } // 需要反向生成的表信息 if (isExclude) { tableList.removeAll(excludeTableList); includeTableList = tableList; } if (!isInclude && !isExclude) { includeTableList = tableList; } } catch (SQLException e) { e.printStackTrace(); } finally { // 释放资源 try { if (preparedStatement != null) { preparedStatement.close(); } if (connection != null) { connection.close(); } } catch (SQLException e) { e.printStackTrace(); } } return processTable(includeTableList, strategy, config.getTablePrefix()); } /** * 判断主键是否为identity,目前仅对mysql进行检查 * * @param results ResultSet * @return 主键是否为identity * @throws SQLException */ private boolean isKeyIdentity(ResultSet results) throws SQLException { if (QuerySQL.MYSQL == this.querySQL) { String extra = results.getString("Extra"); if ("auto_increment".equals(extra)) { return true; } } return false; } /** * <p> * 将字段信息与表信息关联 * </p> * * @param tableInfo 表信息 * @param strategy 命名策略 * @return */ private TableInfo convertTableFields(TableInfo tableInfo, NamingStrategy strategy) { boolean haveId = false; List<TableField> fieldList = new ArrayList<>(); List<TableField> commonFieldList = new ArrayList<>(); try { PreparedStatement preparedStatement = connection.prepareStatement(String.format(querySQL.getTableFieldsSql(), tableInfo.getName())); ResultSet results = preparedStatement.executeQuery(); while (results.next()) { TableField field = new TableField(); String key = results.getString(querySQL.getFieldKey()); // 避免多重主键设置,目前只取第一个找到ID,并放到list中的索引为0的位置 boolean isId = StringUtils.isNotEmpty(key) && key.toUpperCase().equals("PRI"); // 处理ID if (isId && !haveId) { field.setKeyFlag(true); if (isKeyIdentity(results)) { field.setKeyIdentityFlag(true); } haveId = true; } else { field.setKeyFlag(false); } // 处理其它信息 field.setName(results.getString(querySQL.getFieldName())); field.setType(results.getString(querySQL.getFieldType())); field.setPropertyName(strategyConfig, processName(field.getName(), strategy)); field.setColumnType(dataSourceConfig.getTypeConvert().processTypeConvert(field.getType())); field.setComment(results.getString(querySQL.getFieldComment())); if (strategyConfig.includeSuperEntityColumns(field.getName())) { // 跳过公共字段 commonFieldList.add(field); continue; } fieldList.add(field); } } catch (SQLException e) { System.err.println("SQL Exception:" + e.getMessage()); } tableInfo.setFields(fieldList); tableInfo.setCommonFields(commonFieldList); return tableInfo; } /** * 连接路径字符串 * * @param parentDir 路径常量字符串 * @param packageName 包名 * @return 连接后的路径 */ private String joinPath(String parentDir, String packageName) { if (StringUtils.isEmpty(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 parent 父包名 * @param subPackage 子包名 * @return 连接后的包名 */ private String joinPackage(String parent, String subPackage) { if (StringUtils.isEmpty(parent)) { return subPackage; } return parent + "." + subPackage; } /** * 处理字段名称 * * @return 根据策略返回处理后的名称 */ private String processName(String name, NamingStrategy strategy) { return processName(name, strategy, null); } /** * 处理字段名称 * * @param name * @param strategy * @param tablePrefix * @return 根据策略返回处理后的名称 */ private String processName(String name, NamingStrategy strategy, String[] tablePrefix) { boolean removePrefix = false; if (tablePrefix != null && tablePrefix.length >= 1) { removePrefix = true; } String propertyName; if (removePrefix) { if (strategy == NamingStrategy.underline_to_camel) { // 删除前缀、下划线转驼峰 propertyName = NamingStrategy.removePrefixAndCamel(name, tablePrefix); } else { // 删除前缀 propertyName = NamingStrategy.removePrefix(name, tablePrefix); } } else if (strategy == NamingStrategy.underline_to_camel) { // 下划线转驼峰 propertyName = NamingStrategy.underlineToCamel(name); } else { // 不处理 propertyName = name; } return propertyName; } /** * 获取当前的SQL类型 * * @return DB类型 */ private QuerySQL getQuerySQL(DbType dbType) { for (QuerySQL qs : QuerySQL.values()) { if (qs.getDbType().equals(dbType.getValue())) { return qs; } } return QuerySQL.MYSQL; } public StrategyConfig getStrategyConfig() { return strategyConfig; } public void setStrategyConfig(StrategyConfig strategyConfig) { this.strategyConfig = strategyConfig; } public GlobalConfig getGlobalConfig() { return globalConfig; } public void setGlobalConfig(GlobalConfig globalConfig) { this.globalConfig = globalConfig; } }