package com.xjrsoft.module.generator.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.db.Db;
import cn.hutool.db.DbUtil;
import cn.hutool.db.meta.Column;
import cn.hutool.db.meta.MetaUtil;
import cn.hutool.db.meta.Table;
import cn.hutool.extra.pinyin.PinyinUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xjrsoft.common.constant.GlobalConstant;
import com.xjrsoft.common.enums.FormTemplateType;
import com.xjrsoft.common.enums.MenuType;
import com.xjrsoft.common.enums.TsColumnType;
import com.xjrsoft.common.enums.YesOrNoEnum;
import com.xjrsoft.common.exception.MyException;
import com.xjrsoft.common.model.datasource.MyColumnInfo;
import com.xjrsoft.common.model.datasource.MyTableInfo;
import com.xjrsoft.common.model.generator.ComponentConfig;
import com.xjrsoft.common.utils.DatasourceUtil;
import com.xjrsoft.common.utils.JdbcToJavaUtil;
import com.xjrsoft.common.utils.RedisUtil;
import com.xjrsoft.config.GeneratePathConfig;
import com.xjrsoft.module.authority.service.IDataAuthTableRelationService;
import com.xjrsoft.module.form.entity.FormDesignConfig;
import com.xjrsoft.module.form.entity.FormTemplate;
import com.xjrsoft.module.form.service.IFormTemplateService;
import com.xjrsoft.module.form.utils.FromTemplateUtil;
import com.xjrsoft.module.generator.constant.ComponentTypeConstant;
import com.xjrsoft.module.generator.dto.BatchGeneratorDto;
import com.xjrsoft.module.generator.dto.CodeFirstGeneratorDto;
import com.xjrsoft.module.generator.dto.CodeFirstPreviewDto;
import com.xjrsoft.module.generator.dto.DataFirstGeneratorDto;
import com.xjrsoft.module.generator.dto.DataFirstPreviewDto;
import com.xjrsoft.module.generator.dto.GeneratorAppDto;
import com.xjrsoft.module.generator.dto.TableInfoDto;
import com.xjrsoft.module.generator.entity.ButtonConfig;
import com.xjrsoft.module.generator.entity.ColumnConfig;
import com.xjrsoft.module.generator.entity.FrontCode;
import com.xjrsoft.module.generator.entity.GeneratorConfig;
import com.xjrsoft.module.generator.entity.MenuConfig;
import com.xjrsoft.module.generator.entity.OutputConfig;
import com.xjrsoft.module.generator.entity.TableConfig;
import com.xjrsoft.module.generator.entity.TableStructureConfig;
import com.xjrsoft.module.generator.service.IGeneratorService;
import com.xjrsoft.module.generator.utils.GeneratorUtil;
import com.xjrsoft.module.generator.utils.SqlUtil;
import com.xjrsoft.module.generator.vo.ColumnInfoVo;
import com.xjrsoft.module.generator.vo.GeneratorCodeVo;
import com.xjrsoft.module.generator.vo.TableInfoVo;
import com.xjrsoft.module.system.entity.CodeSchema;
import com.xjrsoft.module.system.entity.Menu;
import com.xjrsoft.module.system.entity.MenuButton;
import com.xjrsoft.module.system.entity.MenuColumn;
import com.xjrsoft.module.system.entity.MenuForm;
import com.xjrsoft.module.system.mapper.MenuMapper;
import com.xjrsoft.module.system.service.ICodeSchemaService;
import com.xjrsoft.module.system.service.IDatabaselinkService;
import com.xjrsoft.module.system.service.IMenuButtonService;
import com.xjrsoft.module.system.service.IMenuColumnService;
import com.xjrsoft.module.system.service.IMenuFormService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import javax.sql.DataSource;
import java.io.FileNotFoundException;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @title: GeneratorServiceImpl
 * @Author tzx
 * @Date: 2022/4/16 23:16
 * @Version 1.0
 */
@Service
@AllArgsConstructor
public class GeneratorServiceImpl implements IGeneratorService {

    private static final String TEMPLATE_PATH = "src/main/resources/template";

    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 static final List<Class> EQUALS_TYPE_CLASS = Arrays.asList(Integer.class, Long.class, Double.class, Float.class, Boolean.class);

    private final MenuMapper menuMapper;

    private final IMenuButtonService menuButtonService;

    private final IMenuColumnService menuColumnService;

    private final IMenuFormService menuFormService;

    private final GeneratePathConfig generatePathConfig;

    private final IFormTemplateService formTemplateService;

    private final IDataAuthTableRelationService dataAuthTableRelationService;

    private final ICodeSchemaService codeSchemaService;

    private final FreeMarkerConfigurer freeMarkerConfigurer;

    private final IDatabaselinkService databaselinkService;

    private final RedisUtil redisUtil;


    @Override
    @SneakyThrows
    public GeneratorCodeVo getPreviewCodes(DataFirstPreviewDto dto) {

        GeneratorConfig generatorConfig = BeanUtil.toBean(dto, GeneratorConfig.class);

        Optional<TableConfig> tableConfigOptional = dto.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
        //主表
        TableConfig mainTable;
        if (tableConfigOptional.isPresent()) {
            mainTable = tableConfigOptional.get();
        } else {
            throw new MyException("请选择主表");
        }
        List<Table> tableInfos = getTableInfos(generatorConfig);

        return getGeneratorCodeVo(generatorConfig, mainTable, tableInfos);
    }


    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean generateCodes(DataFirstGeneratorDto dto) {
        GeneratorConfig generatorConfig = BeanUtil.toBean(dto, GeneratorConfig.class);

        Optional<TableConfig> tableConfigOptional = dto.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
        //主表
        TableConfig mainTable;
        if (tableConfigOptional.isPresent()) {
            mainTable = tableConfigOptional.get();
        } else {
            throw new MyException("请选择主表");
        }

        OutputConfig outputConfig = dto.getOutputConfig();
        String databaseId = dto.getDatabaseId();
        if (BooleanUtils.isTrue(outputConfig.getIsDataAuth())) {
            // 添加权限字段 rule_user_id
            DataSource dataSource = DatasourceUtil.getDataSource(databaseId);
            String[] columnNames = MetaUtil.getColumnNames(dataSource, mainTable.getTableName());
            if (!ArrayUtils.contains(columnNames, GlobalConstant.AUTH_USER_ID)) {
                DbType dbType = databaselinkService.getDbType(databaseId);
                Db.use(dataSource).executeBatch(SqlUtil.buildAddDataAuthFieldSqls(dbType, mainTable.getTableName()));
            }
        }

        //修改 getTableInfos  也记得修改 FromTemplateServiceImpl 的同名方法
        List<Table> tableInfos = getTableInfos(generatorConfig);

        createCodeFile(generatorConfig, mainTable, tableInfos, dto.getFrontCode());


        //生成代码的同时 新增代码模板数据
        FormTemplate template = new FormTemplate();
        template.setFormType(FormTemplateType.SYSTEM.getCode());
        template.setCategory(dto.getCategoryId());
        template.setName(StrUtil.isNotBlank(outputConfig.getComment()) ? outputConfig.getComment() : dto.getName());

        FormDesignConfig formDesignConfig = new FormDesignConfig();
        formDesignConfig.setDatabaseId(databaseId);
        formDesignConfig.setTableConfigs(dto.getTableConfigs());
        formDesignConfig.setFormEventConfig(dto.getFormEventConfig());

        List<TableStructureConfig> tableStructureConfigs = FromTemplateUtil.wrapperTableStructureConfig(dto.getFormJson().getList(), mainTable);
        formDesignConfig.setTableStructureConfigs(tableStructureConfigs);
        formDesignConfig.setFormJson(dto.getFormJson());

        template.setFormJson(JSONUtil.toJsonStr(formDesignConfig));
        template.setConfigJson(JSONUtil.toJsonStr(dto.getListConfig()));


        //保存菜单、权限数据、
        if (generatorConfig.getOutputConfig().getIsMenu()) {
            Menu menu = insertMenuConfig(generatorConfig);
            template.setId(menu.getFormId());
        }
        //如果有传入id  就证明是编辑代码模板  需要默认修改
        if(ObjectUtil.isNotNull(dto.getId()) && dto.getId() > 0){
            CodeSchema codeSchema = codeSchemaService.getById(dto.getId());
//            template.setId(codeSchema.getFormId());
        }
        // 保存表单设计需要在保存菜单之后
        formTemplateService.save(template);
        // 保存数据权限关系
        if (BooleanUtils.isTrue(outputConfig.getIsDataAuth())) {
            dataAuthTableRelationService.saveDataAuthTableRelations(mainTable.getTableName(), outputConfig.getDataAuthList().stream().map(Long::parseLong).collect(Collectors.toList()));
        }
        // 保存代码模板
        saveCodeSchema(dto.getId(), outputConfig, JSONUtil.toJsonStr(dto), template.getId());
        return true;
    }


    @Override
    @SneakyThrows
    public GeneratorCodeVo getCodeFirstPreviewCodes(CodeFirstPreviewDto dto) {

        GeneratorConfig generatorConfig = BeanUtil.toBean(dto, GeneratorConfig.class);

        // 默认将表结构 表名  字段名 改为全小写 蛇形 例如  XjrParent -> xjr_parent   XjrChild -> xjr_child
        // 全转未小写后 如果是oracle、达梦 数据库 也会自动变成全大写 无需关心
//        for (TableStructureConfig tableStructureConfig : generatorConfig.getTableStructureConfigs()) {
//            tableStructureConfig.setTableName(StrUtil.toUnderlineCase(tableStructureConfig.getTableName()));
//            for (TableFieldConfig tableFieldConfig : tableStructureConfig.getTableFieldConfigs()) {
//                tableFieldConfig.setFieldName(StrUtil.toUnderlineCase(tableFieldConfig.getFieldName()));
//            }
//        }


        Optional<TableStructureConfig> mainTableOp = dto.getTableStructureConfigs().stream().filter(TableStructureConfig::getIsMain).findFirst();
        //主表
        TableConfig mainTable = new TableConfig();
        if (mainTableOp.isPresent()) {
            mainTable.setIsMain(true);
            mainTable.setTableName(mainTableOp.get().getTableName());
            mainTable.setPkField(GlobalConstant.DEFAULT_PK);
            mainTable.setPkType(GlobalConstant.DEFAULT_PK_TYPE);
        } else {
            throw new MyException("主表不存在");
        }

        //创建数据库表。  子表默认多创建一个 主表id 的字段 用于关联
        createTable(generatorConfig);

        List<Table> tableInfos = new ArrayList<>();
        // 默认拼接主表
        generatorConfig.setTableConfigs(new ArrayList<>());
        for (TableStructureConfig tableStructureConfig : dto.getTableStructureConfigs()) {
            //判断是否为默认数据源
            DataSource dataSource = null;
            if (StrUtil.equalsIgnoreCase(dto.getDatabaseId(), GlobalConstant.DEFAULT_DATASOURCE_KEY)) {
                dataSource = DatasourceUtil.getDatasourceMaster();
            } else {
                dataSource = DatasourceUtil.getDataSource(dto.getDatabaseId());

            }
            tableInfos.add(MetaUtil.getTableMeta(dataSource, tableStructureConfig.getTableName()));

            Integer operator = tableStructureConfig.getOperator();
            if (operator == null || operator == 2 || operator == 4) {
                //因为是预览代码 并不一定会生成功能 所以新创建的表必须得删掉。
                String dropSql = DatasourceUtil.wrapperDropSql(tableStructureConfig.getTableName());
                DbUtil.use(dataSource).execute(dropSql);
            }

            TableConfig tableConfig = new TableConfig();
            tableConfig.setTableName(tableStructureConfig.getTableName());
            tableConfig.setIsMain(tableStructureConfig.getIsMain());

            //子表 的关联字段默认使用 parent_id
            if (!tableStructureConfig.getIsMain()) {
                tableConfig.setRelationField(GlobalConstant.DEFAULT_FK);
                tableConfig.setRelationTableField(GlobalConstant.DEFAULT_PK);
            }

            tableConfig.setPkField(GlobalConstant.DEFAULT_PK);
            tableConfig.setPkType(GlobalConstant.DEFAULT_PK_TYPE);

            generatorConfig.getTableConfigs().add(tableConfig);


        }
        return getGeneratorCodeVo(generatorConfig, mainTable, tableInfos);
    }


    @Override
    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean generateCodeFirstCodes(CodeFirstGeneratorDto dto) {
        GeneratorConfig generatorConfig = BeanUtil.toBean(dto, GeneratorConfig.class);
        // 默认将表结构 表名  字段名 改为全小写 蛇形 例如  XjrParent -> xjr_parent   XjrChild -> xjr_child
        // 全转未小写后 如果是oracle、达梦 数据库 也会自动变成全大写 无需关心
//        for (TableStructureConfig tableStructureConfig : generatorConfig.getTableStructureConfigs()) {
//            tableStructureConfig.setTableName(StrUtil.toUnderlineCase(tableStructureConfig.getTableName()));
//            for (TableFieldConfig tableFieldConfig : tableStructureConfig.getTableFieldConfigs()) {
//                tableFieldConfig.setFieldName(StrUtil.toUnderlineCase(tableFieldConfig.getFieldName()));
//            }
//        }

        //保存菜单、权限数据
        Long formId = null;
        if (generatorConfig.getOutputConfig().getIsMenu()) {
            Menu menu = insertMenuConfig(generatorConfig);
            formId = menu.getFormId();
        }

        Optional<TableStructureConfig> mainTableOp = dto.getTableStructureConfigs().stream().filter(TableStructureConfig::getIsMain).findFirst();
        //主表
        TableConfig mainTable = null;
        dto.setTableConfigs(new ArrayList<>(dto.getTableStructureConfigs().size()));
        for (TableStructureConfig tableStructureConfig : dto.getTableStructureConfigs()) {
            if (BooleanUtils.isTrue(tableStructureConfig.getIsMain())) {
                mainTable =  new TableConfig();
                mainTable.setIsMain(true);
                mainTable.setTableName(mainTableOp.get().getTableName());
                mainTable.setPkField(GlobalConstant.DEFAULT_PK);
                mainTable.setPkType(GlobalConstant.DEFAULT_PK_TYPE);
                dto.getTableConfigs().add(0, mainTable);
            } else {
                TableConfig tableConfig = new TableConfig();
                tableConfig.setIsMain(false);
                tableConfig.setTableName(mainTableOp.get().getTableName());
                tableConfig.setRelationField(GlobalConstant.DEFAULT_FK);
                tableConfig.setRelationTableField(GlobalConstant.DEFAULT_PK);
                tableConfig.setPkField(GlobalConstant.DEFAULT_PK);
                tableConfig.setPkType(GlobalConstant.DEFAULT_PK_TYPE);
                dto.getTableConfigs().add(tableConfig);
            }
        }
        if (mainTable == null) {
            throw new MyException("主表不存在");
        }

        createTable(generatorConfig);

        List<Table> tableInfos = new ArrayList<>();

        // 默认拼接主表
        generatorConfig.setTableConfigs(new ArrayList<>());
        String databaseId = dto.getDatabaseId();
        for (TableStructureConfig tableStructureConfig : generatorConfig.getTableStructureConfigs()) {
            //判断是否为默认数据源
            if (StrUtil.equalsIgnoreCase(databaseId, GlobalConstant.DEFAULT_DATASOURCE_KEY)) {
                DataSource datasourceMaster = DatasourceUtil.getDatasourceMaster();
                tableInfos.add(MetaUtil.getTableMeta(datasourceMaster, tableStructureConfig.getTableName()));
            } else {
                DataSource dataSource = DatasourceUtil.getDataSource(databaseId);
                tableInfos.add(MetaUtil.getTableMeta(dataSource, tableStructureConfig.getTableName()));
            }
            TableConfig tableConfig = new TableConfig();
            tableConfig.setTableName(tableStructureConfig.getTableName());
            tableConfig.setIsMain(tableStructureConfig.getIsMain());

            //子表 的关联字段默认使用 parent_id
            if (!tableStructureConfig.getIsMain()) {
                tableConfig.setRelationField(GlobalConstant.DEFAULT_FK);
                tableConfig.setRelationTableField(GlobalConstant.DEFAULT_PK);
            }

            tableConfig.setPkField(GlobalConstant.DEFAULT_PK);
            tableConfig.setPkType(GlobalConstant.DEFAULT_PK_TYPE);

            generatorConfig.getTableConfigs().add(tableConfig);


        }

        createCodeFile(generatorConfig, mainTable, tableInfos, dto.getFrontCode());

        //生成代码的同时 新增代码模板数据
        FormTemplate template = new FormTemplate();
        template.setId(formId);
        template.setFormType(FormTemplateType.SYSTEM.getCode());
        template.setCategory(dto.getCategoryId());
        OutputConfig outputConfig = dto.getOutputConfig();
        template.setName(StrUtil.isNotBlank(outputConfig.getComment()) ? outputConfig.getComment() : dto.getName());

        FormDesignConfig formDesignConfig = new FormDesignConfig();
        formDesignConfig.setDatabaseId(databaseId);

        List<TableConfig> tableConfigs = FromTemplateUtil.wrapperTableConfig(databaseId, dto.getTableStructureConfigs());

        formDesignConfig.setTableConfigs(tableConfigs);
        formDesignConfig.setTableStructureConfigs(dto.getTableStructureConfigs());
        formDesignConfig.setFormJson(dto.getFormJson());
        formDesignConfig.setFormEventConfig(dto.getFormEventConfig());
        template.setFormJson(JSONUtil.toJsonStr(formDesignConfig));
        template.setConfigJson(JSONUtil.toJsonStr(dto.getListConfig()));



        //如果有传入id  就证明是编辑代码模板  需要默认修改
        if(ObjectUtil.isNotNull(dto.getId()) && dto.getId() > 0){
            CodeSchema codeSchema = codeSchemaService.getById(dto.getId());
//            template.setId(codeSchema.getFormId());
        }
        // 保存表单设计需要在保存菜单之后
        formTemplateService.save(template);
        // 保存数据权限关系
        if (BooleanUtils.isTrue(outputConfig.getIsDataAuth())) {
            dataAuthTableRelationService.saveDataAuthTableRelations(mainTable.getTableName(), outputConfig.getDataAuthList().stream().map(Long::parseLong).collect(Collectors.toList()));
        }
        // 保存代码模板
        saveCodeSchema(dto.getId(), outputConfig, JSONUtil.toJsonStr(dto), template.getId());
        return true;
    }

    @SneakyThrows
    @Transactional(rollbackFor = Exception.class)
    public Boolean generatorCodeBatch(BatchGeneratorDto dto) {

        GeneratorConfig generatorConfig = BeanUtil.toBean(dto, GeneratorConfig.class);

        Optional<TableConfig> tableConfigOptional = dto.getTableConfigs().stream().filter(TableConfig::getIsMain).findFirst();
        //主表
        TableConfig mainTable;
        if (tableConfigOptional.isPresent()) {
            mainTable = tableConfigOptional.get();
        } else {
            throw new MyException("请选择主表");
        }

        OutputConfig outputConfig = dto.getOutputConfig();
        String databaseId = dto.getDatabaseId();
        if (BooleanUtils.isTrue(outputConfig.getIsDataAuth())) {
            // 添加权限字段 rule_user_id
            DataSource dataSource = DatasourceUtil.getDataSource(databaseId);
            String[] columnNames = MetaUtil.getColumnNames(dataSource, mainTable.getTableName());
            if (!ArrayUtils.contains(columnNames, GlobalConstant.AUTH_USER_ID)) {
                DbType dbType = databaselinkService.getDbType(databaseId);
                Db.use(dataSource).executeBatch(SqlUtil.buildAddDataAuthFieldSqls(dbType, mainTable.getTableName()));
            }
        }

        //修改 getTableInfos  也记得修改 FromTemplateServiceImpl 的同名方法
        List<Table> tableInfos = getTableInfos(generatorConfig);

        createCodeFile(generatorConfig, mainTable, tableInfos, dto.getFrontCode());


        //生成代码的同时 新增代码模板数据
        FormTemplate template = new FormTemplate();
        template.setFormType(FormTemplateType.SYSTEM.getCode());
        template.setCategory(dto.getCategoryId());
        template.setName(StrUtil.isNotBlank(outputConfig.getComment()) ? outputConfig.getComment() : dto.getName());

        FormDesignConfig formDesignConfig = new FormDesignConfig();
        formDesignConfig.setDatabaseId(databaseId);
        formDesignConfig.setTableConfigs(dto.getTableConfigs());
        formDesignConfig.setFormEventConfig(dto.getFormEventConfig());

        List<TableStructureConfig> tableStructureConfigs = FromTemplateUtil.wrapperTableStructureConfig(dto.getFormJson().getList(), mainTable);
        formDesignConfig.setTableStructureConfigs(tableStructureConfigs);
        formDesignConfig.setFormJson(dto.getFormJson());

        template.setFormJson(JSONUtil.toJsonStr(formDesignConfig));
        template.setConfigJson(JSONUtil.toJsonStr(dto.getListConfig()));

        //保存菜单、权限数据、
//        if (generatorConfig.getOutputConfig().getIsMenu()) {
//            Menu menu = insertMenuConfig(generatorConfig);
//            template.setId(menu.getFormId());
//        }
        //如果有传入id  就证明是编辑代码模板  需要默认修改
//        if(ObjectUtil.isNotNull(dto.getId()) && dto.getId() > 0){
//            CodeSchema codeSchema = codeSchemaService.getById(dto.getId());
//            template.setId(codeSchema.getFormId());
//        }
        // 保存表单设计需要在保存菜单之后
        formTemplateService.saveOrUpdate(template);
        // 保存数据权限关系
        if (BooleanUtils.isTrue(outputConfig.getIsDataAuth())) {
            dataAuthTableRelationService.saveDataAuthTableRelations(mainTable.getTableName(), outputConfig.getDataAuthList().stream().map(Long::parseLong).collect(Collectors.toList()));
        }
//        // 保存代码模板
//        saveCodeSchema(dto.getId(), outputConfig, JSONUtil.toJsonStr(dto), template.getId());
        return true;
    }

    @Override
    public List<TableInfoVo> getTableInfo(TableInfoDto dto) {
        return getTableInfoVos(dto);
    }

    @Override
    @SneakyThrows
    public Boolean generateAppCodes(GeneratorAppDto dto) {

        FrontCode frontCode = new FrontCode();
        frontCode.setApiCode(dto.getApiCode());
        frontCode.setListCode(dto.getListCode());
        frontCode.setFormCode(dto.getFormCode());
        frontCode.setConfigJsonCode(dto.getConfigJsonCode());
        createAppCodeFile(frontCode, dto.getClassName(), dto.getOutputValue());


        return Boolean.TRUE;
    }


    /**
     * 根据配置生成文件
     *
     * @param generatorConfig
     * @param mainTable
     * @param tableInfos
     * @throws FileNotFoundException
     */
    private void createCodeFile(GeneratorConfig generatorConfig, TableConfig mainTable, List<Table> tableInfos, FrontCode frontCode) throws FileNotFoundException {
        String className = generatorConfig.getOutputConfig().getClassName();
        String dirValue = generatorConfig.getOutputConfig().getOutputValue();

        //---------------------------------------生成entity开始----------------------------------------------------
        {
            Map<String, String> entityCodeMap = GeneratorUtil.getEntityCode(generatorConfig, tableInfos);

            for (Map.Entry<String, String> entry : entityCodeMap.entrySet()) {
                GeneratorUtil.writeFile(GeneratorUtil.getEntityOutputDir(dirValue), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
            }
        }
        //---------------------------------------生成entity结束----------------------------------------------------


        //********************************************生成dto开始************************************************
        {
            Map<String, String> dtoMap = new HashMap<>(3);
            dtoMap.putAll(GeneratorUtil.getAddDtoCode(generatorConfig, tableInfos));
            dtoMap.putAll(GeneratorUtil.getUpdateDtoCode(generatorConfig, tableInfos));
            dtoMap.putAll(GeneratorUtil.getPageDtoCode(generatorConfig, tableInfos, mainTable));

            for (Map.Entry<String, String> entry : dtoMap.entrySet()) {
                GeneratorUtil.writeFile(GeneratorUtil.getDtoOutputDir(dirValue), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
            }
        }
        //********************************************生成dto结束************************************************

        //###############################################生成Vo开始###############################################
        {
            Map<String, String> voMap = new HashMap<>(2);
            voMap.putAll(GeneratorUtil.getPageVoCode(generatorConfig, tableInfos, mainTable));
            voMap.putAll(GeneratorUtil.getInfoVoCode(generatorConfig, tableInfos, mainTable));

            for (Map.Entry<String, String> entry : voMap.entrySet()) {
                GeneratorUtil.writeFile(GeneratorUtil.getVoOutputDir(dirValue), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
            }
        }
        //###############################################生成Vo结束###############################################


        //---------------------------------------生成三层代码开始----------------------------------------------------
        {
            Map<String, String> mapperCode = GeneratorUtil.getMapperCode(generatorConfig, tableInfos);

            for (Map.Entry<String, String> entry : mapperCode.entrySet()) {
                GeneratorUtil.writeFile(GeneratorUtil.getMapperOutputDir(dirValue), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
            }
        }

        {
            Map<String, String> serviceCode = GeneratorUtil.getServiceCode(generatorConfig, mainTable, tableInfos.size() > 1);

            for (Map.Entry<String, String> entry : serviceCode.entrySet()) {
                GeneratorUtil.writeFile(GeneratorUtil.getServiceOutputDir(dirValue), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
            }
        }

        {
            Map<String, String> serviceImplCode = GeneratorUtil.getServiceImplCode(generatorConfig, mainTable, tableInfos.size() > 1);
            for (Map.Entry<String, String> entry : serviceImplCode.entrySet()) {
                GeneratorUtil.writeFile(GeneratorUtil.getServiceImplOutputDir(dirValue), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
            }
        }

        {
            Map<String, String> controllerCode = GeneratorUtil.getControllerCode(generatorConfig, tableInfos, mainTable);
            for (Map.Entry<String, String> entry : controllerCode.entrySet()) {
                GeneratorUtil.writeFile(GeneratorUtil.getControllerOutputDir(dirValue), entry.getKey() + StringPool.DOT_JAVA, entry.getValue());
            }
        }
        //---------------------------------------生成三层代码结束----------------------------------------------------


        //---------------------------------------生成页面代码开始----------------------------------------------------
        {
            String listFileName = "index.vue";
            GeneratorUtil.writeFile(getListOutputDir(dirValue, className), listFileName, frontCode.getListCode());
        }
        //---------------------------------------生成页面代码结束----------------------------------------------------

        //---------------------------------------生成表单代码开始----------------------------------------------------
        {
            String suffix = StrUtil.upperFirst(generatorConfig.getFormJson().getConfig().getFormType());
            String formFileName = StrUtil.upperFirst(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(className)) + suffix + ".vue";
            GeneratorUtil.writeFile(getFormOutputDir(dirValue, className), formFileName, frontCode.getFormCode());
        }
        //---------------------------------------生成表单代码开始----------------------------------------------------

        //---------------------------------------生成表单、列表 配置 json开始----------------------------------------------------
        {
            String configFileName = "config.ts";
            GeneratorUtil.writeFile(getFormOutputDir(dirValue, className), configFileName, frontCode.getConfigJsonCode());
        }
        //---------------------------------------生成表单、列表 配置 json开始----------------------------------------------------


        //---------------------------------------生成前端请求文件代码开始----------------------------------------------------
        {
            String apiFileName = "index.ts";
            GeneratorUtil.writeFile(getApiOutputDir(dirValue, className), apiFileName, frontCode.getApiCode());
        }
        //---------------------------------------生成前端请求文件代码开始----------------------------------------------------


        //---------------------------------------生成前端模型代码开始----------------------------------------------------
        {
            String modelFileName = StrUtil.upperFirst(StrUtil.toCamelCase(className)) + "Model.ts";
            GeneratorUtil.writeFile(getModelOutputDir(dirValue, className), modelFileName, frontCode.getModelCode());
        }
        //---------------------------------------生成前端模型代码开始----------------------------------------------------

    }


    /**
     * 根据前端传入参数 生成APP代码
     *
     * @param frontCode 前端代码
     * @param className 功能类名
     * @param dirValue  输出区域
     * @throws FileNotFoundException
     */
    private void createAppCodeFile(FrontCode frontCode, String className, String dirValue) throws FileNotFoundException {


        //---------------------------------------生成页面代码开始----------------------------------------------------
        {
            String listFileName = "list.vue";
            GeneratorUtil.writeFile(getAppListOutputDir(dirValue, className), listFileName, frontCode.getListCode());
        }
        //---------------------------------------生成页面代码结束----------------------------------------------------

        //---------------------------------------生成表单代码开始----------------------------------------------------
        {
            String formFileName = "form.vue";
            GeneratorUtil.writeFile(getAppFormOutputDir(dirValue, className), formFileName, frontCode.getFormCode());
        }
        //---------------------------------------生成表单代码开始----------------------------------------------------

        //---------------------------------------生成表单、列表 配置 json开始----------------------------------------------------
        {
            String configFileName = "index.js";
            GeneratorUtil.writeFile(getAppConfigOutputDir(dirValue, className), configFileName, frontCode.getConfigJsonCode());
        }
        //---------------------------------------生成表单、列表 配置 json开始----------------------------------------------------


        //---------------------------------------生成前端请求文件代码开始----------------------------------------------------
        {
            String apiFileName = "index.js";
            GeneratorUtil.writeFile(getAppApiOutputDir(dirValue, className), apiFileName, frontCode.getApiCode());
        }
        //---------------------------------------生成前端请求文件代码开始----------------------------------------------------


    }

    /**
     * 根据配置预览代码
     *
     * @param generatorConfig
     * @param mainTable
     * @param tableInfos
     * @return
     */
    private GeneratorCodeVo getGeneratorCodeVo(GeneratorConfig generatorConfig, TableConfig mainTable, List<Table> tableInfos) {
        GeneratorCodeVo vo = new GeneratorCodeVo();

        //生成实体类
        vo.setEntityCode(GeneratorUtil.getEntityCode(generatorConfig, tableInfos));


        Map<String, String> dtoMap = new HashMap<>(3);
        dtoMap.putAll(GeneratorUtil.getAddDtoCode(generatorConfig, tableInfos));
        dtoMap.putAll(GeneratorUtil.getUpdateDtoCode(generatorConfig, tableInfos));
        dtoMap.putAll(GeneratorUtil.getPageDtoCode(generatorConfig, tableInfos, mainTable));
        vo.setDtoCode(dtoMap);


        Map<String, String> voMap = new HashMap<>(2);
        voMap.putAll(GeneratorUtil.getPageVoCode(generatorConfig, tableInfos, mainTable));
        voMap.putAll(GeneratorUtil.getInfoVoCode(generatorConfig, tableInfos, mainTable));
        vo.setVoCode(voMap);


        vo.setMapperCode(GeneratorUtil.getMapperCode(generatorConfig, tableInfos));
        vo.setServiceCode(GeneratorUtil.getServiceCode(generatorConfig, mainTable, tableInfos.size() > 1));
        vo.setImplCode(GeneratorUtil.getServiceImplCode(generatorConfig, mainTable, tableInfos.size() > 1));
        vo.setControllerCode(GeneratorUtil.getControllerCode(generatorConfig, tableInfos, mainTable));
        return vo;
    }

    /**
     * 创建表
     * 修改此方法逻辑，一定要对比一下 FromTemplateServiceImpl 中的 同名方法  是否 也需要修改！
     *
     * @param generatorConfig 配置
     */
    private void createTable(GeneratorConfig generatorConfig) throws SQLException {
        //------------------------------------根据配置建表开始------------------------------------------
        {
            //判断是否为默认数据源
            if (StrUtil.equalsIgnoreCase(generatorConfig.getDatabaseId(), GlobalConstant.DEFAULT_DATASOURCE_KEY)) {
                List<String> createTableSqls = DatasourceUtil.wrapperCreateTableSql(generatorConfig.getTableStructureConfigs(), DatasourceUtil.getDataSourceMasterDbType());

                for (String sql : createTableSqls) {
                    DbUtil.use(DatasourceUtil.getDatasourceMaster()).execute(sql);
                }
            } else {
                DataSource dataSource = DatasourceUtil.getDataSource(generatorConfig.getDatabaseId());
                if (dataSource == null) {
                    throw new RuntimeException("数据库连接不存在：" + generatorConfig.getDatabaseId());
                }
                DbType dbType = databaselinkService.getDbType(generatorConfig.getDatabaseId());
                List<String> createTableSqls = DatasourceUtil.wrapperCreateTableSql(generatorConfig.getTableStructureConfigs(), dbType);
                for (String sql : createTableSqls) {
                    DbUtil.use(dataSource).execute(sql);
                }
            }

        }
        //------------------------------------根据配置建表结束------------------------------------------
    }

    /**
     * 获取表结构信息
     *
     * @param generatorConfig
     * @return
     */
    private List<Table> getTableInfos(GeneratorConfig generatorConfig) {
        List<Table> tableInfos = new ArrayList<>();
        for (TableConfig tableConfig : generatorConfig.getTableConfigs()) {
            //判断是否为默认数据源
            if (StrUtil.equalsIgnoreCase(generatorConfig.getDatabaseId(), GlobalConstant.DEFAULT_DATASOURCE_KEY)) {
                tableInfos.add(MetaUtil.getTableMeta(DatasourceUtil.getDatasourceMaster(), tableConfig.getTableName()));
            } else {
                tableInfos.add(MetaUtil.getTableMeta(DatasourceUtil.getDataSource(generatorConfig.getDatabaseId()), tableConfig.getTableName()));
            }
        }
        return tableInfos;
    }

    /**
     * 获取表结构信息
     *
     * @param dto
     * @return
     */
    private List<TableInfoVo> getTableInfoVos(TableInfoDto dto) {
        List<TableInfoVo> tableInfoVos = new ArrayList<>();

        List<String> numberList = Arrays.asList("Integer", "Short", "Long", "Double", "Float", "BigDecimal", "Byte");
        String booleanStr = "Boolean";

        for (TableConfig tableConfig : dto.getTableConfigs()) {
            //判断是否为默认数据源
            DataSource dataSource = DatasourceUtil.getDataSource(dto.getDatabaseId());
            Table tableMeta = MetaUtil.getTableMeta(dataSource, tableConfig.getTableName());
            TableInfoVo vo = new TableInfoVo();
            vo.setTableName(tableMeta.getTableName());
            vo.setTableComment(tableMeta.getComment());
            vo.setColumnInfos(new ArrayList<>());
            Collection<Column> columns = tableMeta.getColumns();
            for (Column column : columns) {
                ColumnInfoVo columnInfoVo = new ColumnInfoVo();
                columnInfoVo.setColumnName(column.getName());
                columnInfoVo.setColumnLength(column.getSize());
                columnInfoVo.setIsPrimaryKey(column.isPk());
                columnInfoVo.setIsNullable(column.isNullable());

                String className = JdbcToJavaUtil.getClassName(column);

                if (numberList.contains(className)) {
                    columnInfoVo.setColumnType(TsColumnType.NUMBER.getCode());
                } else if (StrUtil.equals(className, booleanStr)) {
                    columnInfoVo.setColumnType(TsColumnType.BOOL.getCode());
                } else {
                    columnInfoVo.setColumnType(TsColumnType.STRING.getCode());
                }
                vo.getColumnInfos().add(columnInfoVo);

            }
            tableInfoVos.add(vo);

        }
        return tableInfoVos;
    }






    /**
     * 获取列表页面生成路径
     *
     * @param outputArea
     * @return
     */
    private String getListOutputDir(String outputArea, String className) {
        return generatePathConfig.getWebPath() + StringPool.SLASH + "src" + StringPool.SLASH + "views" + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + className.toLowerCase();
    }

    /**
     * 获取APP列表页面生成路径
     *
     * @param outputArea
     * @return
     */
    private String getAppListOutputDir(String outputArea, String className) {
        return generatePathConfig.getAppPath() + StringPool.SLASH + "pages" + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + className.toLowerCase();
    }

    /**
     * 获取表单页面生成路径（表单前端是一个组件 所以 多了一层components）
     *
     * @param outputArea
     * @return
     */
    private String getFormOutputDir(String outputArea, String className) {
        return generatePathConfig.getWebPath() + StringPool.SLASH + "src" + StringPool.SLASH + "views" + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + className.toLowerCase() + StringPool.SLASH + "components";
    }

    /**
     * 获取APP表单页生成路劲
     *
     * @param outputArea
     * @return
     */
    private String getAppFormOutputDir(String outputArea, String className) {
        return generatePathConfig.getAppPath() + StringPool.SLASH + "pages" + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + className.toLowerCase();
    }

    /**
     * 获取前端模型生成路径
     *
     * @param outputArea
     * @return
     */
    private String getModelOutputDir(String outputArea, String className) {
        return generatePathConfig.getWebPath() + StringPool.SLASH + "src" + StringPool.SLASH + "api" + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + className.toLowerCase() + StringPool.SLASH + "model";
    }

    /**
     * 获取前端请求生成路径
     *
     * @param outputArea
     * @return
     */
    private String getApiOutputDir(String outputArea, String className) {
        return generatePathConfig.getWebPath() + StringPool.SLASH + "src" + StringPool.SLASH + "api" + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + className.toLowerCase();
    }

    /**
     * 获取APP请求生成路径
     *
     * @param outputArea
     * @return
     */
    private String getAppApiOutputDir(String outputArea, String className) {
        return generatePathConfig.getAppPath() + StringPool.SLASH + "common" + StringPool.SLASH + "api" + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + className.toLowerCase();
    }


    /**
     * 获取APP配置请求生成路径
     *
     * @param outputArea
     * @return
     */
    private String getAppConfigOutputDir(String outputArea, String className) {
        return generatePathConfig.getAppPath() + StringPool.SLASH + "pages" + StringPool.SLASH + outputArea.toLowerCase() + StringPool.SLASH + className.toLowerCase() + StringPool.SLASH + "config";
    }


    /**
     * 默认插入菜单
     *
     * @param generatorConfig
     */
    private Menu insertMenuConfig(GeneratorConfig generatorConfig) {
        MenuConfig menuConfig = generatorConfig.getMenuConfig();
        Long count = menuMapper.selectCount(Wrappers.lambdaQuery(Menu.class).eq(Menu::getTitle, menuConfig.getName()));
        if (count > 0L) {
            throw new RuntimeException("菜单名已存在！");
        }
        Menu menu = BeanUtil.toBean(menuConfig, Menu.class);
//        if (oldMenu != null) {
//            menu.setId(oldMenu.getId());
//            menu.setFormId(oldMenu.getFormId());
//        } else {
        menu.setFormId(IdUtil.getSnowflakeNextId());
//        }
        menu.setName(menuConfig.getName() + RandomUtil.randomNumbers(4));
        menu.setTitle(menuConfig.getName());
        menu.setComponent(StringPool.SLASH + generatorConfig.getOutputConfig().getOutputValue().toLowerCase() + StringPool.SLASH + generatorConfig.getOutputConfig().getClassName().toLowerCase() + StringPool.SLASH + "index");
        menu.setMenuType(MenuType.FUNCTION.getCode());
        menu.setDisplay(1);
        menu.setAllowDelete(1);
        menu.setAllowModify(1);
        menu.setOutLink(0);
        menu.setKeepAlive(0);
        menu.setSortCode(menuConfig.getSortCode());
        menu.setPath(PinyinUtil.getPinyin(menuConfig.getName(), StringPool.EMPTY).toLowerCase());
        //保存菜单
//        if (oldMenu != null) {
//            menuMapper.updateById(menu);
//        } else {
            menuMapper.insert(menu);
//        }

        Long menuId = menu.getId();
        List<ButtonConfig> buttonConfigs = generatorConfig.getListConfig().getButtonConfigs();
        List<MenuButton> oldBtnList = menuButtonService.list(Wrappers.lambdaQuery(MenuButton.class)
                .select(MenuButton::getId, MenuButton::getCode).eq(MenuButton::getMenuId, menuId));
        Map<String, Long> btnCodeIdMap = oldBtnList.stream().collect(Collectors.toMap(m ->
                StringUtils.defaultIfBlank(StringUtils.substringAfterLast(m.getCode(), StringPool.COLON), m.getCode()), MenuButton::getId));
        List<MenuButton> btnList = new ArrayList<>();
        buttonConfigs.forEach(buttonConfig -> {
            if (BooleanUtils.isTrue(buttonConfig.getIsUse())) {
                String code = generatorConfig.getOutputConfig().getClassName().toLowerCase() + StringPool.COLON + buttonConfig.getCode();
                MenuButton menuButton = new MenuButton();
                menuButton.setId(btnCodeIdMap.get(StringUtils.defaultIfBlank(StringUtils.substringAfterLast(code, StringPool.COLON), code)));
                menuButton.setMenuId(menuId);
                menuButton.setName(buttonConfig.getName());
                menuButton.setCode(code);
                menuButton.setIcon(buttonConfig.getIcon());
                btnList.add(menuButton);
            }
        });

        List<ColumnConfig> columnConfigs = generatorConfig.getListConfig().getColumnConfigs();
        List<MenuColumn> oldColList = menuColumnService.list(Wrappers.lambdaQuery(MenuColumn.class)
                .select(MenuColumn::getId, MenuColumn::getCode).eq(MenuColumn::getMenuId, menuId));
        Map<String, Long> colCodeIdMap = oldColList.stream().collect(Collectors.toMap(MenuColumn::getCode, MenuColumn::getId));
        List<MenuColumn> colList = new ArrayList<>();
        for (ColumnConfig columnConfig : columnConfigs) {
            MenuColumn menuColumn = new MenuColumn();
            menuColumn.setId(colCodeIdMap.get(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(columnConfig.getColumnName())));
            menuColumn.setMenuId(menuId);
            menuColumn.setName(columnConfig.getLabel());
            menuColumn.setCode(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(columnConfig.getColumnName()));
            colList.add(menuColumn);
        }
        List<ComponentConfig> componentConfigList = GeneratorUtil.getFormComponentListWithoutLayout(generatorConfig.getFormJson().getList());
        List<MenuForm> oldFormList = menuFormService.list(Wrappers.lambdaQuery(MenuForm.class)
                .select(MenuForm::getId, MenuForm::getCode).eq(MenuForm::getMenuId, menuId));
        Map<String, Long> formCodeIdMap = oldFormList.stream().collect(Collectors.toMap(m -> m.getParentId() + StringPool.AMPERSAND + m.getCode(), MenuForm::getId));
        List<MenuForm> formList = new ArrayList<>();
        for (ComponentConfig componentConfig : componentConfigList) {
            String type = componentConfig.getType();
            if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.SUB_FORM) || StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.ONE_FOR_ONE_FORM)) {
                Long oldId = formCodeIdMap.get(StringPool.ZERO + StringPool.AMPERSAND + StrUtil.toCamelCase(componentConfig.getBindTable()));
                long id = oldId == null ? IdUtil.getSnowflakeNextId() : oldId;
                IdWorker.getId();
                MenuForm menuForm = new MenuForm();
                menuForm.setId(id);
                menuForm.setMenuId(menuId);
                menuForm.setCode(StrUtil.toCamelCase(componentConfig.getBindTable()));
                menuForm.setName(componentConfig.getLabel());
                formList.add(menuForm);
                for (ComponentConfig subConfig : componentConfig.getChildren()) {
                    MenuForm form = buildMenuForm(id, menuId, subConfig);
                    form.setId(formCodeIdMap.get(id + StringPool.AMPERSAND + form.getCode()));
                    formList.add(form);
                }
            } else {
                MenuForm form = buildMenuForm(0L, menuId, componentConfig);
                form.setId(formCodeIdMap.get(StringPool.ZERO + StringPool.AMPERSAND + form.getCode()));
                formList.add(form);
            }
        }
        menuButtonService.remove(Wrappers.lambdaQuery(MenuButton.class).eq(MenuButton::getMenuId, menuId));
        menuButtonService.saveBatch(btnList);
        menuColumnService.remove(Wrappers.lambdaQuery(MenuColumn.class).eq(MenuColumn::getMenuId, menuId));
        menuColumnService.saveBatch(colList);
        menuFormService.remove(Wrappers.lambdaQuery(MenuForm.class).eq(MenuForm::getMenuId, menuId));
        menuFormService.saveBatch(formList);
        return menu;
    }

    private MenuForm buildMenuForm(Long parentId, Long menuId, ComponentConfig componentConfig) {
        String field = null;
        String type = componentConfig.getType();
        if (StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.DATE_RANGE)
                || StrUtil.equalsIgnoreCase(type, ComponentTypeConstant.TIME_RANGE)) {
            field = com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(componentConfig.getBindStartTime()) + StringPool.COMMA + com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(componentConfig.getBindEndTime());
        } else {
            field = StrUtil.isEmpty(componentConfig.getBindField()) ? componentConfig.getKey() : com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(componentConfig.getBindField());
        }
        Boolean isRequired = MapUtils.getBoolean(componentConfig.getOptions(), "required", Boolean.FALSE);
        MenuForm subMenuForm = new MenuForm();
        subMenuForm.setParentId(parentId);
        subMenuForm.setMenuId(menuId);
        subMenuForm.setCode(field);
        subMenuForm.setName(componentConfig.getLabel());
        subMenuForm.setIsRequired(isRequired ? YesOrNoEnum.YES.getCode() : YesOrNoEnum.NO.getCode());
        return subMenuForm;
    }

    /**
     * 获取所有表
     *
     * @return
     */
    private MyTableInfo getTableInfo(String id, String tableName) {
        Connection connection = null;
        ResultSet resultSet = null;
        try {
            DataSource dataSource = DatasourceUtil.getDataSource(id);
            connection = dataSource.getConnection();
            DatabaseMetaData metaData = connection.getMetaData();
            resultSet = metaData.getTables(null, null, tableName, new String[]{"TABLE"});

            MyTableInfo myTableInfo = null;
            //可能会返回重复的表名  mysql 5.5 以后的驱动url都必须设置参数  &nullCatalogMeansCurrent=true  可以解决返回重复表问题
            while (resultSet.next()) {
                myTableInfo = new MyTableInfo();

                myTableInfo.setTableName(resultSet.getString("TABLE_NAME"));
                myTableInfo.setTableComment(resultSet.getString("REMARKS"));

                ResultSet columns = metaData.getColumns(null, null, tableName, null);
                ResultSet primaryKeys = metaData.getPrimaryKeys(null, null, tableName);

                //获取所有主键
                List<String> primaryKeysList = new ArrayList<>();
                while (primaryKeys.next()) {
                    primaryKeysList.add(primaryKeys.getString("PK_NAME"));
                }


                List<MyColumnInfo> columnInfoList = new ArrayList<>();
                while (columns.next()) {
                    String columnName = columns.getString("COLUMN_NAME");
                    //可能会有重复的返回值，所以需要去重
                    if (columnInfoList.stream().noneMatch(x -> StrUtil.equals(x.getColumn(), columnName))) {
                        MyColumnInfo myColumnInfo = new MyColumnInfo();
                        myColumnInfo.setColumn(columns.getString("COLUMN_NAME"));
                        myColumnInfo.setProperty(com.baomidou.mybatisplus.core.toolkit.StringUtils.underlineToCamel(columns.getString("COLUMN_NAME")));
                        myColumnInfo.setDataType(columns.getString("DATA_TYPE"));
                        myColumnInfo.setColumnComment(columns.getString("REMARKS"));
                        myColumnInfo.setNullable(columns.getBoolean("NULLABLE"));
                        myColumnInfo.setAutoIncrement(columns.getBoolean("IS_AUTOINCREMENT"));
                        myColumnInfo.setDataLength(columns.getInt("COLUMN_SIZE"));
                        myColumnInfo.setPrimaryKey(primaryKeysList.stream().anyMatch(x -> StrUtil.equals(x, columnName)));

                        columnInfoList.add(myColumnInfo);
                    }


                }

            }
            return myTableInfo;

        } catch (SQLException e) {
            throw new MyException("获取数据源所有表失败");
        } finally {
            DatasourceUtil.close(connection, resultSet);
        }
    }

    private boolean saveCodeSchema(Long id, OutputConfig outputConfig, String content, Long formId) {
        CodeSchema codeSchema = new CodeSchema();
        codeSchema.setId(id);
        codeSchema.setCategory(Long.parseLong(outputConfig.getOutputArea()));
        codeSchema.setContent(content);
        codeSchema.setFormId(formId);
        codeSchema.setDescription(outputConfig.getComment());
        codeSchema.setRemark(outputConfig.getRemarks());
        codeSchema.setName(outputConfig.getClassName());
        codeSchema.setStatus(1);
        codeSchema.setType(outputConfig.getType());
        return codeSchemaService.saveOrUpdate(codeSchema);
    }


}
