👋 大家好,我是 阿问学长
!专注于分享优质开源项目
解析、毕业设计项目指导
支持、幼小初高
的教辅资料
推荐等,欢迎关注交流!🚀
代码生成器深度定制
前言
代码生成器是提高开发效率的重要工具,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代码生成器的深度定制,包括:
- AutoGenerator配置:全局配置、包配置、策略配置等
- 自定义模板引擎:扩展模板变量和业务逻辑
- 自定义代码模板:实体类、Service、Controller等模板定制
- 多数据源支持:支持多个数据源的代码生成
- 业务逻辑扩展:BO、VO对象和前端Vue模板生成
通过这些定制功能,可以大大提高开发效率,生成符合项目规范的高质量代码。
至此,第二篇MyBatis-Plus数据持久层技术的内容就完成了。在下一篇文章中,我们将探讨Redis缓存与分布式技术。