Ruoyi-vue-plus-5.x第二篇MyBatis-Plus核心功能:2.4 代码生成器深度定制

👋 大家好,我是 阿问学长!专注于分享优质开源项目解析、毕业设计项目指导支持、幼小初高教辅资料推荐等,欢迎关注交流!🚀

代码生成器深度定制

前言

代码生成器是提高开发效率的重要工具,MyBatis-Plus提供了强大的代码生成器功能。RuoYi-Vue-Plus在此基础上进行了深度定制,支持多数据源代码生成、自定义模板、业务逻辑扩展等高级功能。本文将详细介绍如何使用和定制MyBatis-Plus代码生成器,实现高效的代码自动化生成。

AutoGenerator代码生成器配置

基础配置

/**
 * 代码生成器配置
 */
@Configuration
public class GeneratorConfig {
    
    /**
     * 代码生成器
     */
    public void generateCode(GenTableBo genTable) {
        // 创建代码生成器
        AutoGenerator generator = new AutoGenerator(getDataSourceConfig(genTable.getDataName()));
        
        // 全局配置
        generator.global(getGlobalConfig(genTable));
        
        // 包配置
        generator.packageInfo(getPackageConfig(genTable));
        
        // 策略配置
        generator.strategy(getStrategyConfig(genTable));
        
        // 模板配置
        generator.template(getTemplateConfig(genTable));
        
        // 注入配置
        generator.injection(getInjectionConfig(genTable));
        
        // 执行生成
        generator.execute();
    }
    
    /**
     * 数据源配置
     */
    private DataSourceConfig getDataSourceConfig(String dataName) {
        DataSourceProperty dataSourceProperty = DynamicDataSourceContextHolder.getDataSourceProperty(dataName);
        
        return new DataSourceConfig.Builder(
            dataSourceProperty.getUrl(),
            dataSourceProperty.getUsername(),
            dataSourceProperty.getPassword()
        )
        .dbQuery(new MySqlQuery())
        .schema(dataSourceProperty.getSchema())
        .typeConvert(new MySqlTypeConvert())
        .keyWordsHandler(new MySqlKeyWordsHandler())
        .build();
    }
    
    /**
     * 全局配置
     */
    private GlobalConfig getGlobalConfig(GenTableBo genTable) {
        return new GlobalConfig.Builder()
            .outputDir(getOutputDir()) // 输出目录
            .author(genTable.getFunctionAuthor()) // 作者
            .enableSwagger() // 开启Swagger注解
            .commentDate("yyyy-MM-dd") // 注释日期格式
            .disableOpenDir() // 禁止打开输出目录
            .build();
    }
    
    /**
     * 包配置
     */
    private PackageConfig getPackageConfig(GenTableBo genTable) {
        return new PackageConfig.Builder()
            .parent(genTable.getPackageName()) // 父包名
            .moduleName(genTable.getModuleName()) // 模块名
            .entity("domain") // 实体类包名
            .service("service") // Service包名
            .serviceImpl("service.impl") // ServiceImpl包名
            .mapper("mapper") // Mapper包名
            .xml("mapper.xml") // Mapper XML包名
            .controller("controller") // Controller包名
            .build();
    }
    
    /**
     * 策略配置
     */
    private StrategyConfig getStrategyConfig(GenTableBo genTable) {
        StrategyConfig.Builder builder = new StrategyConfig.Builder();
        
        // 表配置
        builder.addInclude(genTable.getTableName())
               .addTablePrefix(genTable.getTablePrefix());
        
        // 实体策略配置
        builder.entityBuilder()
               .enableLombok() // 启用Lombok
               .enableTableFieldAnnotation() // 启用字段注解
               .enableActiveRecord() // 启用ActiveRecord模式
               .versionColumnName("version") // 乐观锁字段
               .logicDeleteColumnName("del_flag") // 逻辑删除字段
               .naming(NamingStrategy.underline_to_camel) // 数据库表映射到实体的命名策略
               .columnNaming(NamingStrategy.underline_to_camel) // 数据库表字段映射到实体的命名策略
               .addSuperEntityColumns("create_by", "create_time", "update_by", "update_time") // 父类公共字段
               .formatFileName("%s"); // 实体类文件名格式
        
        // Service策略配置
        builder.serviceBuilder()
               .formatServiceFileName("I%sService") // Service接口文件名格式
               .formatServiceImplFileName("%sServiceImpl"); // ServiceImpl文件名格式
        
        // Controller策略配置
        builder.controllerBuilder()
               .enableRestStyle() // 启用REST风格
               .enableHyphenStyle() // 启用连字符风格
               .formatFileName("%sController"); // Controller文件名格式
        
        // Mapper策略配置
        builder.mapperBuilder()
               .enableMapperAnnotation() // 启用@Mapper注解
               .enableBaseResultMap() // 启用BaseResultMap
               .enableBaseColumnList() // 启用BaseColumnList
               .formatMapperFileName("%sMapper") // Mapper文件名格式
               .formatXmlFileName("%sMapper"); // Mapper XML文件名格式
        
        return builder.build();
    }
    
    /**
     * 模板配置
     */
    private TemplateConfig getTemplateConfig(GenTableBo genTable) {
        return new TemplateConfig.Builder()
            .entity("/templates/entity.java") // 实体类模板
            .service("/templates/service.java") // Service接口模板
            .serviceImpl("/templates/serviceImpl.java") // ServiceImpl模板
            .mapper("/templates/mapper.java") // Mapper接口模板
            .xml("/templates/mapper.xml") // Mapper XML模板
            .controller("/templates/controller.java") // Controller模板
            .build();
    }
}

自定义模板引擎

/**
 * 自定义模板引擎
 */
@Component
public class CustomTemplateEngine extends VelocityTemplateEngine {
    
    @Override
    protected void outputCustomFile(Map<String, String> customFile, TableInfo tableInfo, Map<String, Object> objectMap) {
        String entityName = tableInfo.getEntityName();
        String otherPath = this.getPathInfo(OutputFile.other);
        
        customFile.forEach((key, value) -> {
            String fileName = String.format(otherPath + File.separator + entityName + "%s", key);
            this.outputFile(new File(fileName), objectMap, value);
        });
    }
    
    @Override
    public Map<String, Object> getObjectMap(ConfigBuilder configBuilder, TableInfo tableInfo) {
        Map<String, Object> objectMap = super.getObjectMap(configBuilder, tableInfo);
        
        // 添加自定义变量
        objectMap.put("datetime", DateUtil.now());
        objectMap.put("author", configBuilder.getGlobalConfig().getAuthor());
        objectMap.put("package", configBuilder.getPackageConfig());
        objectMap.put("table", tableInfo);
        objectMap.put("entity", tableInfo.getEntityName());
        objectMap.put("entityLowerCase", tableInfo.getEntityName().toLowerCase());
        objectMap.put("columns", tableInfo.getFields());
        
        // 添加业务相关变量
        addBusinessVariables(objectMap, tableInfo);
        
        return objectMap;
    }
    
    /**
     * 添加业务相关变量
     */
    private void addBusinessVariables(Map<String, Object> objectMap, TableInfo tableInfo) {
        // 主键信息
        TableField keyColumn = tableInfo.getFields().stream()
            .filter(TableField::isKeyFlag)
            .findFirst()
            .orElse(null);
        
        if (keyColumn != null) {
            objectMap.put("pkColumn", keyColumn);
            objectMap.put("pkJavaField", keyColumn.getPropertyName());
            objectMap.put("pkJavaType", keyColumn.getPropertyType());
        }
        
        // 查询字段
        List<TableField> queryColumns = tableInfo.getFields().stream()
            .filter(field -> isQueryField(field))
            .collect(Collectors.toList());
        objectMap.put("queryColumns", queryColumns);
        
        // 必填字段
        List<TableField> requiredColumns = tableInfo.getFields().stream()
            .filter(field -> !field.isNullable() && !field.isKeyFlag())
            .collect(Collectors.toList());
        objectMap.put("requiredColumns", requiredColumns);
        
        // 字典字段
        List<TableField> dictColumns = tableInfo.getFields().stream()
            .filter(field -> isDictField(field))
            .collect(Collectors.toList());
        objectMap.put("dictColumns", dictColumns);
    }
    
    /**
     * 判断是否为查询字段
     */
    private boolean isQueryField(TableField field) {
        String fieldName = field.getColumnName().toLowerCase();
        return fieldName.contains("name") || 
               fieldName.contains("title") || 
               fieldName.contains("status") || 
               fieldName.contains("type");
    }
    
    /**
     * 判断是否为字典字段
     */
    private boolean isDictField(TableField field) {
        String fieldName = field.getColumnName().toLowerCase();
        return fieldName.contains("status") || 
               fieldName.contains("type") || 
               fieldName.contains("level");
    }
}

自定义代码模板

实体类模板

package ${package.Entity};

#foreach($pkg in ${table.importPackages})
import ${pkg};
#end
#if(${swagger})
import io.swagger.v3.oas.annotations.media.Schema;
#end
#if(${entityLombokModel})
import lombok.Data;
import lombok.EqualsAndHashCode;
#end

/**
 * ${table.comment!} 对象 ${table.name}
 *
 * @author ${author}
 * @date ${datetime}
 */
#if(${entityLombokModel})
@Data
#if(${superEntityClass})
@EqualsAndHashCode(callSuper = true)
#else
@EqualsAndHashCode(callSuper = false)
#end
#end
#if(${table.convert})
@TableName("${schemaName}${table.name}")
#end
#if(${swagger})
@Schema(name = "${entity}", description = "${table.comment!}")
#end
#if(${superEntityClass})
public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
#elseif(${activeRecord})
public class ${entity} extends Model<${entity}> {
#else
public class ${entity} implements Serializable {
#end

    private static final long serialVersionUID = 1L;

#foreach($field in ${table.fields})
#if(${field.keyFlag})
#set($keyPropertyName=${field.propertyName})
#end
#if("$!field.comment" != "")
    /**
     * ${field.comment}
     */
#end
#if(${field.keyFlag})
#if(${field.keyIdentityFlag})
    @TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
#elseif(!$null.isNull(${idType}) && "$!idType" != "")
    @TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
#elseif(${field.convert})
    @TableId("${field.annotationColumnName}")
#end
#elseif(${field.fill})
#if(${field.convert})
    @TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
#else
    @TableField(fill = FieldFill.${field.fill})
#end
#elseif(${field.convert})
    @TableField("${field.annotationColumnName}")
#end
#if(${field.versionField})
    @Version
#end
#if(${field.logicDeleteField})
    @TableLogic
#end
#if(${swagger})
    @Schema(description = "${field.comment}")
#end
    private ${field.propertyType} ${field.propertyName};

#end
#if(!${entityLombokModel})
#foreach($field in ${table.fields})
#if(${field.propertyType.equals("boolean")})
#set($getprefix="is")
#else
#set($getprefix="get")
#end

    public ${field.propertyType} ${getprefix}${field.capitalName}() {
        return ${field.propertyName};
    }

#if(${chainModel})
    public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#else
    public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
#end
        this.${field.propertyName} = ${field.propertyName};
#if(${chainModel})
        return this;
#end
    }
#end
#end

#if(${activeRecord})
    @Override
    public Serializable pkVal() {
#if(${keyPropertyName})
        return this.${keyPropertyName};
#else
        return null;
#end
    }

#end
#if(!${entityLombokModel})
    @Override
    public String toString() {
        return "${entity}{" +
#foreach($field in ${table.fields})
#if($!{foreach.index}==0)
        "${field.propertyName}=" + ${field.propertyName} +
#else
        ", ${field.propertyName}=" + ${field.propertyName} +
#end
#end
        "}";
    }
#end
}

Service接口模板

package ${package.Service};

import ${package.Entity}.${entity};
import ${superServiceClassPackage};
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;

/**
 * ${table.comment!}Service接口
 *
 * @author ${author}
 * @date ${datetime}
 */
#if(${kotlin})
interface ${table.serviceName} : ${superServiceClass}<${entity}>
#else
public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {

    /**
     * 查询${table.comment!}分页列表
     */
    TableDataInfo<${entity}Vo> queryPageList(${entity}Bo bo, PageQuery pageQuery);

    /**
     * 查询${table.comment!}列表
     */
    List<${entity}Vo> queryList(${entity}Bo bo);

    /**
     * 根据主键查询${table.comment!}
     */
    ${entity}Vo queryById(${pkJavaType} ${pkJavaField});

    /**
     * 新增${table.comment!}
     */
    Boolean insertByBo(${entity}Bo bo);

    /**
     * 修改${table.comment!}
     */
    Boolean updateByBo(${entity}Bo bo);

    /**
     * 校验并批量删除${table.comment!}信息
     */
    Boolean deleteWithValidByIds(Collection<${pkJavaType}> ids, Boolean isValid);
}
#end

Controller模板

package ${package.Controller};

import java.util.List;
import java.util.Arrays;

import lombok.RequiredArgsConstructor;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;
import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import ${package.Entity}.${entity};
import ${package.Service}.${table.serviceName};
import com.ruoyi.common.core.page.TableDataInfo;

/**
 * ${table.comment!}
 *
 * @author ${author}
 * @date ${datetime}
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/${entityLowerCase}")
public class ${table.controllerName} extends BaseController {

    private final ${table.serviceName} ${table.serviceName?uncap_first};

    /**
     * 查询${table.comment!}列表
     */
    @SaCheckPermission("${moduleName}:${entityLowerCase}:list")
    @GetMapping("/list")
    public TableDataInfo<${entity}Vo> list(${entity}Bo bo, PageQuery pageQuery) {
        return ${table.serviceName?uncap_first}.queryPageList(bo, pageQuery);
    }

    /**
     * 导出${table.comment!}列表
     */
    @SaCheckPermission("${moduleName}:${entityLowerCase}:export")
    @Log(title = "${table.comment!}", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(${entity}Bo bo, HttpServletResponse response) {
        List<${entity}Vo> list = ${table.serviceName?uncap_first}.queryList(bo);
        ExcelUtil.exportExcel(list, "${table.comment!}", ${entity}Vo.class, response);
    }

    /**
     * 获取${table.comment!}详细信息
     */
    @SaCheckPermission("${moduleName}:${entityLowerCase}:query")
    @GetMapping("/{${pkJavaField}}")
    public R<${entity}Vo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable ${pkJavaType} ${pkJavaField}) {
        return R.ok(${table.serviceName?uncap_first}.queryById(${pkJavaField}));
    }

    /**
     * 新增${table.comment!}
     */
    @SaCheckPermission("${moduleName}:${entityLowerCase}:add")
    @Log(title = "${table.comment!}", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody ${entity}Bo bo) {
        return toAjax(${table.serviceName?uncap_first}.insertByBo(bo));
    }

    /**
     * 修改${table.comment!}
     */
    @SaCheckPermission("${moduleName}:${entityLowerCase}:edit")
    @Log(title = "${table.comment!}", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody ${entity}Bo bo) {
        return toAjax(${table.serviceName?uncap_first}.updateByBo(bo));
    }

    /**
     * 删除${table.comment!}
     */
    @SaCheckPermission("${moduleName}:${entityLowerCase}:remove")
    @Log(title = "${table.comment!}", businessType = BusinessType.DELETE)
    @DeleteMapping("/{${pkJavaField}s}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable ${pkJavaType}[] ${pkJavaField}s) {
        return toAjax(${table.serviceName?uncap_first}.deleteWithValidByIds(Arrays.asList(${pkJavaField}s), true));
    }
}

多数据源代码生成

多数据源配置

/**
 * 多数据源代码生成配置
 */
@Service
public class MultiDataSourceGeneratorService {
    
    @Autowired
    private DynamicDataSourceProperties dynamicDataSourceProperties;
    
    /**
     * 获取所有数据源
     */
    public List<DataSourceInfo> getAllDataSources() {
        List<DataSourceInfo> dataSources = new ArrayList<>();
        
        Map<String, DataSourceProperty> datasourceMap = dynamicDataSourceProperties.getDatasource();
        for (Map.Entry<String, DataSourceProperty> entry : datasourceMap.entrySet()) {
            String dataSourceName = entry.getKey();
            DataSourceProperty property = entry.getValue();
            
            DataSourceInfo info = new DataSourceInfo();
            info.setName(dataSourceName);
            info.setUrl(property.getUrl());
            info.setUsername(property.getUsername());
            info.setDriverClassName(property.getDriverClassName());
            info.setType(getDataSourceType(property.getUrl()));
            
            dataSources.add(info);
        }
        
        return dataSources;
    }
    
    /**
     * 根据数据源生成代码
     */
    public void generateByDataSource(String dataSourceName, GenTableBo genTable) {
        DataSourceProperty property = dynamicDataSourceProperties.getDatasource().get(dataSourceName);
        if (property == null) {
            throw new ServiceException("数据源不存在: " + dataSourceName);
        }
        
        // 创建数据源配置
        DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(
            property.getUrl(),
            property.getUsername(),
            property.getPassword()
        ).build();
        
        // 执行代码生成
        executeGeneration(dataSourceConfig, genTable);
    }
    
    /**
     * 批量生成多个数据源的代码
     */
    public void batchGenerate(List<String> dataSourceNames, GenTableBo genTable) {
        for (String dataSourceName : dataSourceNames) {
            try {
                generateByDataSource(dataSourceName, genTable);
                log.info("数据源 {} 代码生成成功", dataSourceName);
            } catch (Exception e) {
                log.error("数据源 {} 代码生成失败", dataSourceName, e);
            }
        }
    }
    
    /**
     * 获取数据源类型
     */
    private String getDataSourceType(String url) {
        if (url.contains("mysql")) {
            return "MySQL";
        } else if (url.contains("oracle")) {
            return "Oracle";
        } else if (url.contains("postgresql")) {
            return "PostgreSQL";
        } else if (url.contains("sqlserver")) {
            return "SQL Server";
        } else {
            return "Unknown";
        }
    }
}

数据库表信息获取

/**
 * 数据库表信息服务
 */
@Service
public class DatabaseTableService {
    
    /**
     * 获取数据库表列表
     */
    public List<GenTableVo> selectDbTableList(String dataSourceName, GenTableBo genTable) {
        return DynamicDataSourceContextHolder.poll(dataSourceName, () -> {
            return genTableMapper.selectDbTableList(genTable);
        });
    }
    
    /**
     * 获取数据库表字段
     */
    public List<GenTableColumnVo> selectDbTableColumnsByName(String dataSourceName, String tableName) {
        return DynamicDataSourceContextHolder.poll(dataSourceName, () -> {
            return genTableColumnMapper.selectDbTableColumnsByName(tableName);
        });
    }
    
    /**
     * 导入表结构
     */
    @Transactional(rollbackFor = Exception.class)
    public void importGenTable(String dataSourceName, List<String> tableNames, String operName) {
        for (String tableName : tableNames) {
            // 查询表信息
            GenTableBo genTable = DynamicDataSourceContextHolder.poll(dataSourceName, () -> {
                return genTableMapper.selectDbTableByName(tableName);
            });
            
            if (genTable != null) {
                // 设置数据源名称
                genTable.setDataName(dataSourceName);
                
                // 初始化表信息
                initTable(genTable);
                
                // 保存表信息
                genTableMapper.insert(BeanUtil.toBean(genTable, GenTable.class));
                
                // 查询列信息
                List<GenTableColumnBo> columns = DynamicDataSourceContextHolder.poll(dataSourceName, () -> {
                    return genTableColumnMapper.selectDbTableColumnsByName(tableName);
                });
                
                // 初始化列信息
                initColumnField(genTable, columns);
                
                // 保存列信息
                for (GenTableColumnBo column : columns) {
                    column.setTableId(genTable.getTableId());
                    genTableColumnMapper.insert(BeanUtil.toBean(column, GenTableColumn.class));
                }
            }
        }
    }
    
    /**
     * 初始化表信息
     */
    private void initTable(GenTableBo genTable) {
        genTable.setClassName(convertClassName(genTable.getTableName()));
        genTable.setPackageName(GenConstants.DEFAULT_PACKAGE_NAME);
        genTable.setModuleName(getModuleName(genTable.getTableName()));
        genTable.setBusinessName(getBusinessName(genTable.getTableName()));
        genTable.setFunctionName(replaceText(genTable.getTableComment()));
        genTable.setFunctionAuthor(GenConstants.DEFAULT_AUTHOR);
        genTable.setGenType(GenConstants.TPL_CRUD);
        genTable.setTplCategory(GenConstants.TPL_CRUD);
    }
    
    /**
     * 初始化列字段信息
     */
    private void initColumnField(GenTableBo genTable, List<GenTableColumnBo> columns) {
        for (GenTableColumnBo column : columns) {
            String dataType = getDbType(column.getColumnType());
            String columnName = column.getColumnName();
            
            column.setTableId(genTable.getTableId());
            column.setJavaField(StringUtils.toCamelCase(columnName));
            column.setJavaType(GenUtils.getJavaType(dataType));
            column.setQueryType(GenConstants.QUERY_EQ);
            
            if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) {
                Integer columnLength = getColumnLength(column.getColumnType());
                String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
                column.setHtmlType(htmlType);
            } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) {
                column.setHtmlType(GenConstants.HTML_DATETIME);
            } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
                column.setHtmlType(GenConstants.HTML_INPUT);
            }
            
            // 插入字段(默认所有字段都需要插入)
            column.setIsInsert(GenConstants.REQUIRE);
            
            // 编辑字段
            if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk()) {
                column.setIsEdit(GenConstants.REQUIRE);
            }
            
            // 列表字段
            if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk()) {
                column.setIsList(GenConstants.REQUIRE);
            }
            
            // 查询字段
            if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) {
                column.setIsQuery(GenConstants.REQUIRE);
            }
            
            // 查询字段类型
            if (StringUtils.endsWithIgnoreCase(columnName, "name")) {
                column.setQueryType(GenConstants.QUERY_LIKE);
            }
            
            // 状态字段设置单选框
            if (StringUtils.endsWithIgnoreCase(columnName, "status")) {
                column.setHtmlType(GenConstants.HTML_RADIO);
            }
            
            // 类型&性别字段设置下拉框
            if (StringUtils.endsWithIgnoreCase(columnName, "type") || StringUtils.endsWithIgnoreCase(columnName, "sex")) {
                column.setHtmlType(GenConstants.HTML_SELECT);
            }
            
            // 图片字段设置上传控件
            if (StringUtils.endsWithIgnoreCase(columnName, "image")) {
                column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
            }
            
            // 文件字段设置上传控件
            if (StringUtils.endsWithIgnoreCase(columnName, "file")) {
                column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
            }
            
            // 内容字段设置富文本控件
            if (StringUtils.endsWithIgnoreCase(columnName, "content")) {
                column.setHtmlType(GenConstants.HTML_EDITOR);
            }
        }
    }
}

业务逻辑模板扩展

BO和VO模板

## BO (Business Object) 模板
package ${package.Entity};

import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.validation.constraints.*;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.domain.BaseEntity;

/**
 * ${table.comment!}业务对象 ${table.name}
 *
 * @author ${author}
 * @date ${datetime}
 */
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = ${entity}.class, reverseConvertGenerate = false)
public class ${entity}Bo extends BaseEntity {

#foreach($field in ${table.fields})
#if(!${field.superColumn})
    /**
     * ${field.comment}
     */
#if(${field.required})
    @NotNull(message = "${field.comment}不能为空", groups = { AddGroup.class, EditGroup.class })
#end
#if(${field.javaType} == "String")
#if(${field.required})
    @NotBlank(message = "${field.comment}不能为空", groups = { AddGroup.class, EditGroup.class })
#end
#end
    private ${field.propertyType} ${field.propertyName};

#end
#end
}

## VO (View Object) 模板
package ${package.Entity};

import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;

/**
 * ${table.comment!}视图对象 ${table.name}
 *
 * @author ${author}
 * @date ${datetime}
 */
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = ${entity}.class)
public class ${entity}Vo implements Serializable {

    private static final long serialVersionUID = 1L;

#foreach($field in ${table.fields})
    /**
     * ${field.comment}
     */
#if(${field.list})
#if(${field.dictType} && ${field.dictType} != "")
    @ExcelProperty(value = "${field.comment}", converter = ExcelDictConvert.class)
    @ExcelDictFormat(dictType = "${field.dictType}")
#else
    @ExcelProperty(value = "${field.comment}")
#end
#end
    private ${field.propertyType} ${field.propertyName};

#end
}

前端Vue模板

<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
#foreach($column in $columns)
#if($column.query)
#set($dictType=$column.dictType)
#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.htmlType == "input")
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-input
          v-model="queryParams.${column.javaField}"
          placeholder="请输入${comment}"
          clearable
          @keyup.enter="handleQuery"
        />
      </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
          <el-option
            v-for="dict in ${dictType}"
            :key="dict.value"
            :label="dict.label"
            :value="dict.value"
          />
        </el-select>
      </el-form-item>
#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
      <el-form-item label="${comment}" prop="${column.javaField}">
        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
          <el-option label="请选择字典生成" value="" />
        </el-select>
      </el-form-item>
#elseif($column.htmlType == "datetime")
      <el-form-item label="${comment}" style="width: 308px">
        <el-date-picker
          v-model="daterange${AttrName}"
          value-format="YYYY-MM-DD"
          type="daterange"
          range-separator="-"
          start-placeholder="开始日期"
          end-placeholder="结束日期"
        ></el-date-picker>
      </el-form-item>
#end
#end
#end
      <el-form-item>
        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>

    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button
          type="primary"
          plain
          icon="Plus"
          @click="handleAdd"
          v-hasPermi="['${moduleName}:${businessName}:add']"
        >新增</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="success"
          plain
          icon="Edit"
          :disabled="single"
          @click="handleUpdate"
          v-hasPermi="['${moduleName}:${businessName}:edit']"
        >修改</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="danger"
          plain
          icon="Delete"
          :disabled="multiple"
          @click="handleDelete"
          v-hasPermi="['${moduleName}:${businessName}:remove']"
        >删除</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button
          type="warning"
          plain
          icon="Download"
          @click="handleExport"
          v-hasPermi="['${moduleName}:${businessName}:export']"
        >导出</el-button>
      </el-col>
      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
    </el-row>

    <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
      <el-table-column type="selection" width="55" align="center" />
#foreach($column in $columns)
#set($javaField=$column.javaField)
#set($parentheseIndex=$column.columnComment.indexOf("("))
#if($parentheseIndex != -1)
#set($comment=$column.columnComment.substring(0, $parentheseIndex))
#else
#set($comment=$column.columnComment)
#end
#if($column.pk)
      <el-table-column label="${comment}" align="center" prop="${javaField}" />
#elseif($column.list && $column.htmlType == "datetime")
      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
        <template #default="scope">
          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
        </template>
      </el-table-column>
#elseif($column.list && $column.htmlType == "imageUpload")
      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
        <template #default="scope">
          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
        </template>
      </el-table-column>
#elseif($column.list && "" != $column.dictType)
      <el-table-column label="${comment}" align="center" prop="${javaField}">
        <template #default="scope">
#if($column.htmlType == "checkbox")
          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
#else
          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
#end
        </template>
      </el-table-column>
#elseif($column.list && "" != $javaField)
      <el-table-column label="${comment}" align="center" prop="${javaField}" />
#end
#end
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template #default="scope">
          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">修改</el-button>
          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    
    <pagination
      v-show="total>0"
      :total="total"
      v-model:page="queryParams.pageNum"
      v-model:limit="queryParams.pageSize"
      @pagination="getList"
    />
  </div>
</template>

总结

本文详细介绍了MyBatis-Plus代码生成器的深度定制,包括:

  1. AutoGenerator配置:全局配置、包配置、策略配置等
  2. 自定义模板引擎:扩展模板变量和业务逻辑
  3. 自定义代码模板:实体类、Service、Controller等模板定制
  4. 多数据源支持:支持多个数据源的代码生成
  5. 业务逻辑扩展:BO、VO对象和前端Vue模板生成

通过这些定制功能,可以大大提高开发效率,生成符合项目规范的高质量代码。

至此,第二篇MyBatis-Plus数据持久层技术的内容就完成了。在下一篇文章中,我们将探讨Redis缓存与分布式技术。

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿问学长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值