fanxp 1 year ago
parent
commit
134f58f69a

+ 15 - 0
src/main/java/com/xjrsoft/module/generator/service/IApiGeneratorService.java

@@ -0,0 +1,15 @@
+package com.xjrsoft.module.generator.service;
+
+import com.xjrsoft.module.generator.dto.ApiGenerateCodesDto;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+
+public interface IApiGeneratorService {
+    /**
+     * 生成代码
+     *
+     * @return
+     */
+    Boolean generateCodes(ApiGenerateCodesDto dto) throws IOException;
+}

+ 924 - 0
src/main/java/com/xjrsoft/module/generator/service/impl/ApiGeneratorServiceImpl.java

@@ -0,0 +1,924 @@
+package com.xjrsoft.module.generator.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.db.meta.Column;
+import cn.hutool.db.meta.JdbcType;
+import cn.hutool.db.meta.MetaUtil;
+import cn.hutool.db.meta.Table;
+import com.baomidou.mybatisplus.core.toolkit.StringPool;
+import com.xjrsoft.common.constant.GlobalConstant;
+import com.xjrsoft.common.exception.MyException;
+import com.xjrsoft.common.model.generator.ComponentConfig;
+import com.xjrsoft.common.utils.DatasourceUtil;
+import com.xjrsoft.common.utils.JdbcToJavaUtil;
+import com.xjrsoft.common.utils.LocalDateTimeUtil;
+import com.xjrsoft.module.generator.constant.ComponentTypeConstant;
+import com.xjrsoft.module.generator.constant.EntityConstant;
+import com.xjrsoft.module.generator.dto.ApiGenerateCodesDto;
+import com.xjrsoft.module.generator.entity.*;
+import com.xjrsoft.module.generator.service.IApiGeneratorService;
+import com.xjrsoft.module.generator.utils.GeneratorUtil;
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import lombok.AllArgsConstructor;
+import lombok.SneakyThrows;
+import org.apache.commons.collections.MapUtils;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.lang.Nullable;
+import org.springframework.stereotype.Service;
+import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
+import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
+
+import javax.sql.DataSource;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class ApiGeneratorServiceImpl implements IApiGeneratorService {
+
+    private static final String TEMPLATE_PATH = "src/main/resources/apiTemplates";
+
+    private static final String ENTITY_TEMPLATE_NAME = "entity.java.ftl";
+
+    private static final String ADD_DTO_TEMPLATE_NAME = "add.dto.java.ftl";
+
+    private static final String UPDATE_DTO_TEMPLATE_NAME = "update.dto.java.ftl";
+
+    private static final String PAGE_DTO_TEMPLATE_NAME = "page.list.dto.java.ftl";
+
+    private static final String PAGE_VO_TEMPLATE_NAME = "page.list.vo.java.ftl";
+
+    private static final String INFO_VO_TEMPLATE_NAME = "vo.java.ftl";
+
+    private static final String MAPPPER_TEMPLATE_NAME = "mapper.java.ftl";
+
+    private static final String SERVICE_TEMPLATE_NAME = "service.java.ftl";
+
+    private static final String SERVICE_IMPL_TEMPLATE_NAME = "service.impl.java.ftl";
+
+    private static final String CONTROLLER_TEMPLATE_NAME = "controller.java.ftl";
+
+    private Configuration cfg;
+
+    /**
+     * 生成代码
+     *
+     * @return
+     */
+    @Override
+    public Boolean generateCodes(ApiGenerateCodesDto dto) throws IOException {
+        //主表
+        TableConfig mainTable = getMainTable(dto.getTableConfigs());
+
+        cfg = new Configuration();
+        cfg.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
+        cfg.setDefaultEncoding("UTF-8");
+
+        GeneratorConfig generatorConfig = new GeneratorConfig();
+        generatorConfig.setTableConfigs(dto.getTableConfigs());
+
+        List<Table> tableInfos = getTableInfos(dto.getDs(), generatorConfig);
+
+
+        //---------------------------------------生成entity开始----------------------------------------------------
+        {
+            Map<String, String> entityCodeMap = getEntityCode(dto, tableInfos);
+
+            for (Map.Entry<String, String> entry : entityCodeMap.entrySet()) {
+                writeFile(getEntityOutputDir(dto), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
+            }
+        }
+        //---------------------------------------生成dto开始---------------------------------------
+        {
+            Map<String, String> dtoMap = new HashMap<>(3);
+            dtoMap.putAll(getAddDtoCode(dto, tableInfos));
+            dtoMap.putAll(getUpdateDtoCode(dto, tableInfos));
+            dtoMap.putAll(getPageDtoCode(dto, tableInfos, mainTable));
+
+            for (Map.Entry<String, String> entry : dtoMap.entrySet()) {
+                writeFile(getDtoOutputDir(dto), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
+            }
+        }
+        //---------------------------------------生成Vo开始---------------------------------------
+        {
+            Map<String, String> voMap = new HashMap<>(2);
+            voMap.putAll(getPageVoCode(dto, tableInfos, mainTable));
+            voMap.putAll(getInfoVoCode(dto, tableInfos, mainTable));
+
+            for (Map.Entry<String, String> entry : voMap.entrySet()) {
+                writeFile(getVoOutputDir(dto), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
+            }
+        }
+
+        //---------------------------------------生成三层代码开始----------------------------------------------------
+        {
+            Map<String, String> mapperCode = getMapperCode(dto, tableInfos);
+
+            for (Map.Entry<String, String> entry : mapperCode.entrySet()) {
+                writeFile(getMapperOutputDir(dto), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
+            }
+        }
+
+        {
+            Map<String, String> serviceCode = getServiceCode(dto, tableInfos, mainTable, tableInfos.size() > 1);
+
+            for (Map.Entry<String, String> entry : serviceCode.entrySet()) {
+                writeFile(getServiceOutputDir(dto), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
+            }
+        }
+
+        {
+            Map<String, String> serviceImplCode = getServiceImplCode(dto, tableInfos, mainTable, tableInfos.size() > 1);
+            for (Map.Entry<String, String> entry : serviceImplCode.entrySet()) {
+                writeFile(getServiceImplOutputDir(dto), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
+            }
+        }
+
+        {
+            Map<String, String> controllerCode = getControllerCode(dto, tableInfos, mainTable);
+            for (Map.Entry<String, String> entry : controllerCode.entrySet()) {
+                writeFile(getControllerOutputDir(dto), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * 根据配置生成实体类代码
+     *
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getEntityCode(ApiGenerateCodesDto dto, List<Table> tableInfos) {
+        Map<String, String> entityCodeMap = new HashMap<>(tableInfos.size());
+        // 遍历数据表配置 根据表明搜索表信息  然后生成代码
+        for (Table tableInfo : tableInfos) {
+            //获取表的所有字段
+            Collection<Column> columns = tableInfo.getColumns();
+            List<FieldConfig> fieldConfigList = new ArrayList<>();
+
+            for (Column column : columns) {
+                FieldConfig fieldConfig = new FieldConfig();
+
+                if (GlobalConstant.AUTO_INSERT.contains(column.getName())) {
+                    fieldConfig.setAutoInsert(true);
+                }
+
+                if (GlobalConstant.AUTO_UPDATE.contains(column.getName())) {
+                    fieldConfig.setAutoUpdate(true);
+                }
+
+                if (StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK)) {
+                    fieldConfig.setDeleteMark(true);
+                }
+                fieldConfig.setFieldComment(column.getComment());
+                fieldConfig.setPk(column.isPk());
+                fieldConfig.setFieldType(JdbcToJavaUtil.getClassName(column.getTypeEnum()));
+                fieldConfig.setFieldName(StrUtil.toCamelCase(column.getName()));
+
+                fieldConfigList.add(fieldConfig);
+
+            }
+
+
+            //如果有子表  每多一个子表  多加1个长度
+            Map<String, Object> entityMap = new HashMap<>(8);
+            entityMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "entity");
+            entityMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+            entityMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            entityMap.put(EntityConstant.TABLE_NAME, tableInfo.getTableName());
+            entityMap.put(EntityConstant.TABLE_COMMENT, tableInfo.getComment());
+            //先将表明转换为驼峰命名 然后在转换为首字母大写
+            entityMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
+            entityMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);
+
+            //如果是多表关联 则需要添加关联表的信息  判断数据表配置是否大于1  并且  是主表
+            boolean isMainTable = dto.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
+            if (tableInfos.size() > 1 && isMainTable) {
+                List<TableConfig> childTables = dto.getTableConfigs().stream()
+                        .filter(x -> !x.getIsMain())
+                        .collect(Collectors.toList());
+
+                List<TableConfig> newChildTables = new ArrayList<>();
+                for (TableConfig childTable : childTables) {
+                    TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);
+
+                    newTableConfig.setRelationField(StrUtil.toCamelCase(childTable.getRelationField()));
+                    newTableConfig.setRelationTableField(StrUtil.toCamelCase(childTable.getRelationTableField()));
+                    newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));
+
+                    newChildTables.add(newTableConfig);
+                }
+//                Optional<TableConfig> parentTable = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
+                entityMap.put(EntityConstant.CHILD_TABLES, newChildTables);
+//                parentTable.ifPresent(x -> entityMap.put(EntityConstant.PARENT_RELATION_FIELD_KEY, x.getRelationTableField()));
+            }
+
+            Template template = cfg.getTemplate(ENTITY_TEMPLATE_NAME);
+            String entityContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, entityMap);
+
+            entityCodeMap.put(StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())), entityContent);
+        }
+
+        return entityCodeMap;
+    }
+
+    /**
+     * 根据配置生成mapper文件
+     *
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getMapperCode(ApiGenerateCodesDto dto, List<Table> tableInfos) {
+
+
+        Map<String, String> map = new HashMap<>(1 + tableInfos.size() - 1);
+
+        for (Table tableInfo : tableInfos) {
+
+            Map<String, Object> mapperMap = new HashMap<>(7);
+            mapperMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "mapper");
+            mapperMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+            mapperMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            mapperMap.put(EntityConstant.TABLE_COMMENT, tableInfo.getComment());
+            //先将表明转换为驼峰命名 然后在转换为首字母大写
+            mapperMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
+//            mapperMap.put(EntityConstant.FUNCTION_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(generatorConfig.getOutputConfig().getClassName())));
+            mapperMap.put(EntityConstant.OUTPUT_AREA, dto.getPackageName());
+
+            mapperMap.put(EntityConstant.IS_MULTI, tableInfos.size() > 1);
+
+            Template template = cfg.getTemplate(MAPPPER_TEMPLATE_NAME);
+
+            String mapperContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, mapperMap);
+
+            map.put(StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())) + "Mapper", mapperContent);
+
+        }
+
+
+        return map;
+    }
+
+    /**
+     * 根据配置生成service文件
+     *
+     * @param mainTableConfig 主表配置
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getServiceCode(ApiGenerateCodesDto dto, List<Table> tableInfos, TableConfig mainTableConfig, Boolean isMulti) {
+        Optional<Table> mainTable = tableInfos.stream().filter(x -> x.getTableName().equals(mainTableConfig.getTableName())).findFirst();
+        if (!mainTable.isPresent()) {
+            throw new MyException("未设置主表!");
+        }
+
+        Map<String, Object> serviceMap = new HashMap<>(7);
+        serviceMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "service");
+        serviceMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+        serviceMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+        serviceMap.put(EntityConstant.TABLE_COMMENT, mainTable.get().getComment());
+        //先将表明转换为驼峰命名 然后在转换为首字母大写
+        serviceMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
+        serviceMap.put(EntityConstant.OUTPUT_AREA, dto.getPackageName());
+        serviceMap.put(EntityConstant.FUNCTION_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
+        serviceMap.put(EntityConstant.IS_MULTI, isMulti);
+
+        Template template = cfg.getTemplate(SERVICE_TEMPLATE_NAME);
+
+        String serviceContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, serviceMap);
+
+        Map<String, String> map = new HashMap<>(1);
+        map.put("I" + StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())) + "Service", serviceContent);
+        return map;
+    }
+
+    /**
+     * 根据配置生成service impl代码
+     *
+     * @param mainTableConfig 主表配置
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getServiceImplCode(ApiGenerateCodesDto dto, List<Table> tableInfos, TableConfig mainTableConfig, Boolean isMulti) {
+        Optional<TableConfig> first = dto.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
+        if (!first.isPresent()) {
+            throw new MyException("未设置主表!");
+        }
+        Optional<Table> mainTable = tableInfos.stream().filter(x -> x.getTableName().equals(mainTableConfig.getTableName())).findFirst();
+        if (!mainTable.isPresent()) {
+            throw new MyException("未设置主表!");
+        }
+
+        Map<String, Object> serviceMap = new HashMap<>(8);
+        serviceMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "service.impl");
+        serviceMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+        serviceMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+        serviceMap.put(EntityConstant.TABLE_COMMENT, mainTable.get().getComment());
+        serviceMap.put(EntityConstant.PARENT_TABLE_KEY, first.get().getPkField());
+        //先将表明转换为驼峰命名 然后在转换为首字母大写
+        serviceMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
+        serviceMap.put(EntityConstant.OUTPUT_AREA, dto.getPackageName());
+        serviceMap.put(EntityConstant.FUNCTION_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
+
+        serviceMap.put(EntityConstant.IS_MULTI, isMulti);
+        serviceMap.put(EntityConstant.DATASOURCE_ID, "master");
+
+        //传入所有子表
+        List<TableConfig> childTables = dto.getTableConfigs().stream().filter(x -> !x.getIsMain()).collect(Collectors.toList());
+
+        List<TableConfig> newChildTables = new ArrayList<>();
+        for (TableConfig childTable : childTables) {
+            TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);
+
+            newTableConfig.setRelationField(StrUtil.toCamelCase(childTable.getRelationField()));
+            newTableConfig.setRelationTableField(StrUtil.toCamelCase(childTable.getRelationTableField()));
+            newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));
+            newTableConfig.setPkField(StrUtil.toCamelCase(childTable.getPkField()));
+            newTableConfig.setPkType(childTable.getPkType());
+
+            newChildTables.add(newTableConfig);
+        }
+
+        serviceMap.put(EntityConstant.CHILD_TABLES, newChildTables);
+
+        Template template = cfg.getTemplate(SERVICE_IMPL_TEMPLATE_NAME);
+
+        String serviceImplContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, serviceMap);
+
+        Map<String, String> map = new HashMap<>(1);
+        map.put(StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())) + "ServiceImpl", serviceImplContent);
+        return map;
+    }
+
+    /**
+     * 根据配置生成控制器代码
+     *
+     * @param mainTableConfig 主表配置
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getControllerCode(ApiGenerateCodesDto dto, List<Table> tableInfos, TableConfig mainTableConfig) {
+        List<FieldConfig> queryFieldConfigList = new ArrayList<>();
+
+        Optional<Table> mainTable = tableInfos.stream().filter(x -> x.getTableName().equals(mainTableConfig.getTableName())).findFirst();
+        if (!mainTable.isPresent()) {
+            throw new MyException("未设置主表!");
+        }
+
+        Map<String, Object> controllerMap = new HashMap<>(12);
+        controllerMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "controller");
+        controllerMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+        controllerMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+        controllerMap.put(EntityConstant.TABLE_COMMENT, mainTable.get().getComment());
+        controllerMap.put(EntityConstant.IS_PAGE, dto.isPage());
+        //先将表名转换为驼峰命名 然后在转换为首字母大写
+        controllerMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
+        controllerMap.put(EntityConstant.OUTPUT_AREA, dto.getPackageName());
+        controllerMap.put(EntityConstant.TABLE_FIELDS, queryFieldConfigList);
+        controllerMap.put(EntityConstant.PK_FIELD, StrUtil.toCamelCase(mainTableConfig.getPkField()));
+        controllerMap.put(EntityConstant.IS_MULTI, tableInfos.size() > 1);
+        controllerMap.put(EntityConstant.CODE_RULES, "");
+
+        controllerMap.put(EntityConstant.FUNCTION_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
+
+        String orderType = "desc";
+        String orderField = StrUtil.toCamelCase(mainTableConfig.getPkField());
+
+        controllerMap.put(EntityConstant.ORDER_TYPE, StrUtil.equalsIgnoreCase(orderType, "desc"));
+        controllerMap.put(EntityConstant.ORDER_FIELD, StrUtil.upperFirst(orderField));
+        controllerMap.put(EntityConstant.IS_DATA_AUTH, false);
+        // 导入导出
+        controllerMap.put(EntityConstant.IS_IMPORT, dto.isImport());
+        controllerMap.put(EntityConstant.IS_EXPORT, dto.isExport());
+
+        Template template = cfg.getTemplate(CONTROLLER_TEMPLATE_NAME);
+
+        String controllerContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, controllerMap);
+
+        Map<String, String> map = new HashMap<>(1);
+        map.put(StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())) + "Controller", controllerContent);
+        return map;
+    }
+
+    /**
+     * 根据配置新增dto代码
+     *
+     * @param tableInfos 表信息
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getAddDtoCode(ApiGenerateCodesDto dto, List<Table> tableInfos) {
+        Map<String, String> addCodeMap = new HashMap<>(tableInfos.size());
+        // 遍历数据表配置 根据表明搜索表信息  然后生成代码
+        for (Table tableInfo : tableInfos) {
+            //获取表的所有字段
+            Collection<Column> columnList = tableInfo.getColumns();
+
+            List<FieldConfig> fieldConfigList = new ArrayList<>();
+
+            for (Column column : columnList) {
+                FieldConfig fieldConfig = new FieldConfig();
+
+                //因为是新增Dto  不需要主键
+                if (column.isPk()) {
+                    continue;
+                }
+
+                //不属于 固定的审计字段 都需要生成
+                if (
+                        !GlobalConstant.AUTO_INSERT.contains(column.getName()) &&
+                                !GlobalConstant.AUTO_UPDATE.contains(column.getName()) &&
+                                !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK) &&
+                                !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK)
+                ) {
+                    String fieldType = JdbcToJavaUtil.getClassName(column.getTypeEnum());
+                    fieldConfig.setFieldComment(column.getComment());
+                    fieldConfig.setPk(false);
+                    fieldConfig.setFieldType(fieldType);
+                    fieldConfig.setFieldName(StrUtil.toCamelCase(column.getName()));
+
+                    fieldConfigList.add(fieldConfig);
+
+                }
+
+            }
+
+
+            //如果有子表  每多一个子表  多加2个长度
+            Map<String, Object> entityMap = new HashMap<>(8 + (tableInfos.size() - 1) * 2);
+            entityMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "dto");
+            entityMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+            entityMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            entityMap.put(EntityConstant.TABLE_NAME, tableInfo.getTableName());
+            entityMap.put(EntityConstant.TABLE_COMMENT, tableInfo.getComment());
+            //先将表明转换为驼峰命名 然后在转换为首字母大写
+            entityMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
+            entityMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);
+            entityMap.put(EntityConstant.OUTPUT_AREA, dto.getPackageName());
+
+            //如果是多表关联 则需要添加关联表的信息  判断数据表配置是否大于1  并且  是主表
+            boolean isMainTable = dto.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
+            if (tableInfos.size() > 1 && isMainTable) {
+                List<TableConfig> childTables = dto.getTableConfigs().stream()
+                        .filter(x -> !x.getIsMain())
+                        .collect(Collectors.toList());
+                List<TableConfig> newChildTables = new ArrayList<>();
+                for (TableConfig childTable : childTables) {
+                    TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);
+
+                    newTableConfig.setRelationField(StrUtil.toCamelCase(childTable.getRelationField()));
+                    newTableConfig.setRelationTableField(StrUtil.toCamelCase(childTable.getRelationTableField()));
+                    newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));
+
+                    newChildTables.add(newTableConfig);
+                }
+//                Optional<TableConfig> parentTable = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
+                entityMap.put(EntityConstant.CHILD_TABLES, newChildTables);
+//                parentTable.ifPresent(x -> entityMap.put(EntityConstant.PARENT_RELATION_FIELD_KEY, x.getRelationTableField()));
+            }
+
+
+            //生产目标代码
+            Template template = cfg.getTemplate(ADD_DTO_TEMPLATE_NAME);
+            String entityContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, entityMap);
+
+            addCodeMap.put("Add" + StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())) + "Dto", entityContent);
+        }
+
+        return addCodeMap;
+    }
+
+    /**
+     * 根据配置修改dto代码
+     *
+     * @param tableInfos 表信息
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getUpdateDtoCode(ApiGenerateCodesDto dto, List<Table> tableInfos) {
+        Optional<TableConfig> first = dto.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
+        if (!first.isPresent()) {
+            throw new MyException("未设置主表!");
+        }
+
+        Map<String, String> updateCodeMap = new HashMap<>(tableInfos.size());
+        // 遍历数据表配置 根据表明搜索表信息  然后生成代码
+        for (Table tableInfo : tableInfos) {
+
+            if (!first.get().getTableName().equals(tableInfo.getTableName())) {
+                continue;
+            }
+
+            //获取表的所有字段
+            Collection<Column> columns = tableInfo.getColumns();
+            List<FieldConfig> fieldConfigList = new ArrayList<>();
+
+            for (Column column : columns) {
+                FieldConfig fieldConfig = new FieldConfig();
+
+                if (!column.isPk()) {
+                    continue;
+                }
+
+                //不属于 固定的审计字段 都需要生成
+                if (
+                        !GlobalConstant.AUTO_INSERT.contains(column.getName()) &&
+                                !GlobalConstant.AUTO_UPDATE.contains(column.getName()) &&
+                                !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK) &&
+                                !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK)
+                ) {
+                    String fieldType = JdbcToJavaUtil.getClassName(column.getTypeEnum());
+                    fieldConfig.setFieldComment(column.getComment());
+                    fieldConfig.setPk(false);
+                    fieldConfig.setFieldType(fieldType);
+                    fieldConfig.setFieldName(StrUtil.toCamelCase(column.getName()));
+
+                    fieldConfigList.add(fieldConfig);
+                }
+            }
+
+            //如果有子表  每多一个子表  多加2个长度
+            Map<String, Object> entityMap = new HashMap<>(8 + (tableInfos.size() - 1) * 2);
+            entityMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "dto");
+            entityMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+            entityMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            entityMap.put(EntityConstant.TABLE_NAME, tableInfo.getTableName());
+            entityMap.put(EntityConstant.TABLE_COMMENT, tableInfo.getComment());
+            //先将表明转换为驼峰命名 然后在转换为首字母大写
+            entityMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
+            entityMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);
+
+            entityMap.put(EntityConstant.OUTPUT_AREA, dto.getPackageName());
+
+            //如果是多表关联 则需要添加关联表的信息  判断数据表配置是否大于1  并且  是主表
+            boolean isMainTable = dto.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
+            if (tableInfos.size() > 1 && isMainTable) {
+                List<TableConfig> childTables = dto.getTableConfigs().stream()
+                        .filter(x -> !x.getIsMain())
+                        .collect(Collectors.toList());
+                List<TableConfig> newChildTables = new ArrayList<>();
+                for (TableConfig childTable : childTables) {
+                    TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);
+
+                    newTableConfig.setRelationField(StrUtil.toCamelCase(childTable.getRelationField()));
+                    newTableConfig.setRelationTableField(StrUtil.toCamelCase(childTable.getRelationTableField()));
+                    newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));
+
+                    newChildTables.add(newTableConfig);
+                }
+//                Optional<TableConfig> parentTable = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
+                entityMap.put(EntityConstant.CHILD_TABLES, newChildTables);
+//                parentTable.ifPresent(x -> entityMap.put(EntityConstant.PARENT_RELATION_FIELD_KEY, x.getRelationTableField()));
+            }
+
+            //生产目标代码
+            Template template = cfg.getTemplate(UPDATE_DTO_TEMPLATE_NAME);
+            String entityContent = FreeMarkerTemplateUtils.processTemplateIntoString(template, entityMap);
+
+            updateCodeMap.put("Update" + StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())) + "Dto", entityContent);
+        }
+
+        return updateCodeMap;
+    }
+
+    /**
+     * 根据配置生成 表单Vo代码
+     *
+     * @param tableInfos      表信息
+     * @param mainTableConfig 主表配置
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getInfoVoCode(ApiGenerateCodesDto dto, List<Table> tableInfos, TableConfig mainTableConfig) {
+        //获取表的所有字段
+        Optional<Table> mainTableOp = tableInfos.stream().filter(x -> StrUtil.equalsIgnoreCase(x.getTableName(), mainTableConfig.getTableName())).findFirst();
+
+        Table mainTable;
+        if (mainTableOp.isPresent()) {
+            mainTable = mainTableOp.get();
+        } else {
+            throw new MyException("没有主表");
+        }
+
+        Map<String, String> infoVoMap = new HashMap<>(1);
+        // 遍历数据表配置 根据表明搜索表信息  然后生成代码
+        for (Table tableInfo : tableInfos) {
+            //获取表的所有字段
+            Collection<Column> columns = tableInfo.getColumns();
+
+
+            List<FieldConfig> fieldConfigList = new ArrayList<>();
+
+            for (Column column : columns) {
+                FieldConfig fieldConfig = new FieldConfig();
+
+                //只要不是审计字段都返回去
+                if (!GlobalConstant.AUTO_INSERT.contains(column.getName()) &&
+                        !GlobalConstant.AUTO_UPDATE.contains(column.getName()) &&
+                        !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK) &&
+                        !StrUtil.equalsIgnoreCase(column.getName(), GlobalConstant.DELETE_MARK)) {
+
+                    fieldConfig.setFieldComment(column.getComment());
+                    fieldConfig.setPk(false);
+                    fieldConfig.setFieldType(JdbcToJavaUtil.getClassName(column.getTypeEnum()));
+                    fieldConfig.setFieldName(StrUtil.toCamelCase(column.getName()));
+
+                    fieldConfigList.add(fieldConfig);
+
+                }
+            }
+
+
+            Map<String, Object> columnMap = new HashMap<>(7 + (tableInfos.size() - 1) * 1);
+            columnMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "vo");
+            columnMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+            columnMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+            columnMap.put(EntityConstant.TABLE_COMMENT, tableInfo.getComment() + "表单出参");
+            //先将表明转换为驼峰命名 然后在转换为首字母大写
+            columnMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())));
+            columnMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);
+
+            columnMap.put(EntityConstant.OUTPUT_AREA, dto.getPackageName());
+
+            //如果是多表关联 则需要添加关联表的信息  判断数据表配置是否大于1  并且  是主表
+            boolean isMainTable = dto.getTableConfigs().stream().anyMatch(x -> StrUtil.equals(x.getTableName(), tableInfo.getTableName()) && x.getIsMain());
+            if (tableInfos.size() > 1 && isMainTable) {
+                List<TableConfig> childTables = dto.getTableConfigs().stream()
+                        .filter(x -> !x.getIsMain())
+                        .collect(Collectors.toList());
+                List<TableConfig> newChildTables = new ArrayList<>();
+                for (TableConfig childTable : childTables) {
+                    TableConfig newTableConfig = BeanUtil.toBean(childTable, TableConfig.class);
+
+                    newTableConfig.setRelationField(StrUtil.toCamelCase(childTable.getRelationField()));
+                    newTableConfig.setRelationTableField(StrUtil.toCamelCase(childTable.getRelationTableField()));
+                    newTableConfig.setTableName(StrUtil.toCamelCase(childTable.getTableName()));
+
+                    newChildTables.add(newTableConfig);
+                }
+//                Optional<TableConfig> parentTable = generatorConfig.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
+                columnMap.put(EntityConstant.CHILD_TABLES, newChildTables);
+//                parentTable.ifPresent(x -> columnMap.put(EntityConstant.PARENT_RELATION_FIELD_KEY, x.getRelationTableField()));
+            }
+            //生产目标代码
+
+            Template template = cfg.getTemplate(INFO_VO_TEMPLATE_NAME);
+
+            String infoVoConent = FreeMarkerTemplateUtils.processTemplateIntoString(template, columnMap);
+
+
+            infoVoMap.put(StrUtil.upperFirst(StrUtil.toCamelCase(tableInfo.getTableName())) + "Vo", infoVoConent);
+
+        }
+
+        return infoVoMap;
+    }
+
+    /**
+     * 根据配置生成 分页入参dto代码
+     *
+     * @param tableInfos      表信息
+     * @param mainTableConfig 主表配置
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getPageDtoCode(ApiGenerateCodesDto dto, List<Table> tableInfos, TableConfig mainTableConfig) {
+
+        //获取表的所有字段
+        Optional<Table> mainTableOp = tableInfos.stream().filter(x -> StrUtil.equalsIgnoreCase(x.getTableName(), mainTableConfig.getTableName())).findFirst();
+
+        Table mainTable;
+        if (mainTableOp.isPresent()) {
+            mainTable = mainTableOp.get();
+        } else {
+            throw new MyException("没有主表");
+        }
+
+
+        List<FieldConfig> queryFieldConfigList = new ArrayList<>();
+
+        Map<String, Object> queryMap = new HashMap<>(7);
+        queryMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "dto");
+        queryMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+        queryMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+        queryMap.put(EntityConstant.TABLE_COMMENT, mainTable.getComment() + (dto.isPage() ? "分页查询入参" : "列表查询入参"));
+        queryMap.put(EntityConstant.IS_PAGE, dto.isPage());
+        //先将表明转换为驼峰命名 然后在转换为首字母大写
+        queryMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())));
+        queryMap.put(EntityConstant.TABLE_FIELDS, queryFieldConfigList);
+
+        //生产目标代码
+        Template template = cfg.getTemplate(PAGE_DTO_TEMPLATE_NAME);
+
+        String pageDtoConent = FreeMarkerTemplateUtils.processTemplateIntoString(template, queryMap);
+
+        Map<String, String> map = new HashMap<>(1);
+        map.put(StrUtil.upperFirst(StrUtil.toCamelCase(mainTableConfig.getTableName())) + (dto.isPage() ? "Page" : "List") + "Dto", pageDtoConent);
+
+        return map;
+    }
+
+    /**
+     * 根据配置生成 列表页Vo代码
+     *
+     * @param tableInfos      表信息
+     * @param mainTableConfig 主表配置
+     * @return 代码
+     */
+    @SneakyThrows
+    private Map<String, String> getPageVoCode(ApiGenerateCodesDto dto, List<Table> tableInfos, TableConfig mainTableConfig) {
+        //获取表的所有字段
+        Optional<Table> mainTableOp = tableInfos.stream().filter(x -> StrUtil.equalsIgnoreCase(x.getTableName(), mainTableConfig.getTableName())).findFirst();
+
+        Table mainTable;
+        if (mainTableOp.isPresent()) {
+            mainTable = mainTableOp.get();
+        } else {
+            throw new MyException("没有主表");
+        }
+
+        Collection<Column> columns = mainTable.getColumns();
+
+
+        List<FieldConfig> fieldConfigList = new ArrayList<>();
+
+        for (Column column : columns) {
+
+            FieldConfig fieldConfig = new FieldConfig();
+            fieldConfig.setFieldComment(column.getComment());
+            fieldConfig.setLabel(column.getComment());
+            fieldConfig.setPk(false);
+            //如果是主键 就默认使用字符串类型 前端无法识别long类型的精度
+            fieldConfig.setFieldType(column.isPk() ? "String" : JdbcToJavaUtil.getClassName(column.getTypeEnum()));
+            fieldConfig.setFieldName(StrUtil.toCamelCase(column.getName()));
+            fieldConfigList.add(fieldConfig);
+        }
+
+
+        Map<String, Object> columnMap = new HashMap<>(7);
+        columnMap.put(EntityConstant.PACKAGE, GlobalConstant.GENERATOR_DEFAULT_PATH + StringPool.DOT + dto.getPackageName() + StringPool.DOT + "vo");
+        columnMap.put(EntityConstant.AUTH_NAME, dto.getAuthor());
+        columnMap.put(EntityConstant.DATE, LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
+        columnMap.put(EntityConstant.TABLE_COMMENT, mainTable.getComment() + (dto.isPage() ? "分页列表出参" : "列表列表入参"));
+        columnMap.put(EntityConstant.IS_PAGE, dto.isPage());
+        //先将表明转换为驼峰命名 然后在转换为首字母大写
+        columnMap.put(EntityConstant.ENTITY_CLASS_NAME, StrUtil.upperFirst(StrUtil.toCamelCase(mainTable.getTableName())));
+        columnMap.put(EntityConstant.TABLE_FIELDS, fieldConfigList);
+        // 导入导出
+        columnMap.put(EntityConstant.IS_IMPORT, dto.isImport());
+        columnMap.put(EntityConstant.IS_EXPORT, dto.isExport());
+
+
+        //生产目标代码
+        Template template = cfg.getTemplate(PAGE_VO_TEMPLATE_NAME);
+
+        String pageVoConent = FreeMarkerTemplateUtils.processTemplateIntoString(template, columnMap);
+
+        Map<String, String> map = new HashMap<>(1);
+        map.put(StrUtil.upperFirst(StrUtil.toCamelCase(mainTable.getTableName())) + (dto.isPage() ? "Page" : "List") + "Vo", pageVoConent);
+
+        return map;
+    }
+
+    /**
+     * 获取表结构信息
+     *
+     * @return
+     */
+    private List<Table> getTableInfos(DataSource ds, GeneratorConfig generatorConfig) {
+        List<Table> tableInfos = new ArrayList<>();
+        for (TableConfig tableConfig : generatorConfig.getTableConfigs()) {
+            tableInfos.add(MetaUtil.getTableMeta(ds, tableConfig.getTableName()));
+        }
+        return tableInfos;
+    }
+
+    private void writeFile(String dirPath, String fileName, String content) throws FileNotFoundException {
+        File dir = new File(dirPath);
+        if (!dir.exists()) {
+            boolean mkdirs = dir.mkdirs();
+        }
+        String filePath = dirPath + StringPool.SLASH + fileName;
+        File javaFile = new File(filePath);
+        if (javaFile.exists()) {
+            javaFile.renameTo(new File(dirPath + StringPool.SLASH + fileName + StringPool.DOT + System.currentTimeMillis() + ".bak"));
+        }
+        FileOutputStream voFile = new FileOutputStream(filePath);
+        IoUtil.write(voFile, true, content.getBytes(StandardCharsets.UTF_8));
+    }
+
+    /**
+     * 获取生成目录 默认生成到generator/main/java/com/xjrsoft/module
+     *
+     * @return
+     */
+    private String getOutputDir(ApiGenerateCodesDto dto) {
+        if (dto.isOutMainDir()) {
+            return System.getProperty("user.dir") + StringPool.SLASH + "src" + StringPool.SLASH + "main" + StringPool.SLASH + "java" + StringPool.SLASH + "com" + StringPool.SLASH + "xjrsoft" + StringPool.SLASH + "module";
+        } else {
+            return System.getProperty("user.dir") + StringPool.SLASH + "generator" + StringPool.SLASH + "main" + StringPool.SLASH + "java" + StringPool.SLASH + "com" + StringPool.SLASH + "xjrsoft" + StringPool.SLASH + "module";
+        }
+    }
+
+    /**
+     * 获取实体类生成目录
+     *
+     * @param dto
+     * @return
+     */
+    private String getEntityOutputDir(ApiGenerateCodesDto dto) {
+        return getOutputDir(dto) + StringPool.SLASH + dto.getPackageName().toLowerCase() + StringPool.SLASH + "entity";
+    }
+
+    /**
+     * 获取mapper的输出目录
+     *
+     * @param dto
+     * @return
+     */
+    private String getMapperOutputDir(ApiGenerateCodesDto dto) {
+        return getOutputDir(dto) + StringPool.SLASH + dto.getPackageName().toLowerCase() + StringPool.SLASH + "mapper";
+    }
+
+    /**
+     * 获取service的生成目录
+     *
+     * @param dto
+     * @return
+     */
+    private String getServiceOutputDir(ApiGenerateCodesDto dto) {
+        return getOutputDir(dto) + StringPool.SLASH + dto.getPackageName().toLowerCase() + StringPool.SLASH + "service";
+    }
+
+    /**
+     * 获取serviceImpl的生成目录
+     *
+     * @param dto
+     * @return
+     */
+    private String getServiceImplOutputDir(ApiGenerateCodesDto dto) {
+        return getOutputDir(dto) + StringPool.SLASH + dto.getPackageName().toLowerCase() + StringPool.SLASH + "service" + StringPool.SLASH + "impl";
+    }
+
+    /**
+     * 获取控制器生成目录
+     *
+     * @param dto
+     * @return
+     */
+    private String getControllerOutputDir(ApiGenerateCodesDto dto) {
+        return getOutputDir(dto) + StringPool.SLASH + dto.getPackageName().toLowerCase() + StringPool.SLASH + "controller";
+    }
+
+    /**
+     * 获取dto的生成目录
+     *
+     * @param dto
+     * @return
+     */
+    private String getDtoOutputDir(ApiGenerateCodesDto dto) {
+        return getOutputDir(dto) + StringPool.SLASH + dto.getPackageName().toLowerCase() + StringPool.SLASH + "dto";
+    }
+
+    /**
+     * 获取vo的输出目录
+     *
+     * @param dto
+     * @return
+     */
+    private String getVoOutputDir(ApiGenerateCodesDto dto) {
+        return getOutputDir(dto) + StringPool.SLASH + dto.getPackageName().toLowerCase() + StringPool.SLASH + "vo";
+    }
+
+    /**
+     * 获取主表
+     *
+     * @param tableConfigs
+     * @return
+     */
+    private TableConfig getMainTable(List<TableConfig> tableConfigs) {
+        Optional<TableConfig> tableConfigOptional = tableConfigs.stream().filter(TableConfig::getIsMain).findFirst();
+        //主表
+        TableConfig mainTable;
+        if (tableConfigOptional.isPresent()) {
+            mainTable = tableConfigOptional.get();
+        } else {
+            throw new MyException("请选择主表");
+        }
+        return mainTable;
+    }
+
+}