代码生成
用于生成前端和后端的代码,生成步骤:
写SQL创表
请参考数据库设计
配置数据源
详细参考: 数据源维护

导入表结构
将需要生成的表,导入代码生成器。导入时,会读取数据库表结构的元数据,将表名、注释、字段名、字段注释、字段类型、字段长度、不能为空、是否主键等关键的表信息读取出来,存入代码生成表。

导入表结构时,会根据application.yml中配置的信息预设一些默认值,具体如下:
# 代码生成
lamp:
generator:
# 后端代码生成路径
outputDir: /Users/tangyh/gitlab/lamp-cloud-pro-datasource-column
# 前端代码生成路径
frontOutputDir: /Users/tangyh/gitlab/lamp-web-pro
# 作者
author: zuihou
# 表名转换为实体类类名时,是否去除表名前缀
tablePrefix:
- xxx_
# 字段名转换为实体类字段名时,是否去除字段前缀
fieldPrefix:
- xxx_
# 字段名转换为实体类字段名时,是否去除字段后缀
fieldSuffix:
- xxx_
# 项目前缀。 若你的项目改成了 alibaba-base-server,这里就填alibaba
projectPrefix: 'lamp'
# 父类
superClass: SUPER_CLASS
packageInfoConfig: # 其他配置建议保持PackageInfoConfig中的默认值
# 生成代码位于 src/main/java 下的基础包
parent: 'top.tangyh.lamp'
# lamp-util 项目的基础包
utilParent: 'top.tangyh.basic'
# 枚举 位于 src/main/java/{parent}/{moduleName} 下的 包名
enumeration: 'enumeration'
# saveVO 位于 src/main/java/{parent}/{moduleName} 下的 包名
saveVo: 'vo.save'
# updateVO 位于 src/main/java/{parent}/{moduleName} 下的 包名
updateVo: 'vo.update'
# query 位于 src/main/java/{parent}/{moduleName} 下的 包名
pageQuery: 'vo.query'
# resultVo src/main/java/{parent}/{moduleName} 下的 包名
resultVo: 'vo.result'
# 实体 位于 src/main/java/{parent}/{moduleName} 下的 包名
entity: 'entity'
# manager 位于 src/main/java/{parent}/{moduleName} 下的 包名
manager: 'manager'
# managerImpl 位于 src/main/java/{parent}/{moduleName} 下的 包名
managerImpl: 'manager.{}impl'
# service 位于 src/main/java/{parent}/{moduleName} 下的 包名
service: 'service'
# serviceImpl 位于 src/main/java/{parent}/{moduleName} 下的 包名
serviceImpl: 'service.{}impl'
# controller 位于 src/main/java/{parent}/{moduleName} 下的 包名
controller: 'controller'
# mapper 位于 src/main/java/{parent}/{moduleName} 下的 包名
mapper: 'mapper'
# Mapper XML 位于 src/main/resource 下的 包名
xml: 'mapper_{}/base'
entity-config: # 实体类配置
# 【实体、VO】时间类型对应策略 ONLY_DATE: java.util SQL_PACK:java.sql TIME_PACK: java.time
dateType: TIME_PACK
# 【实体】Entity类的父类
entitySuperClass: ENTITY
# 【实体】指定生成的主键的ID类型 (${superClass} == NONE 时,新生成的实体才生效)
idType: INPUT
# 【实体、VO】表字段转换为实体字段的命名策略
columnNaming: underline_to_camel
# 【实体、VO】生成实体类时,忽略的字段(字段名)
ignoreColumns:
- xxx
# 【实体】 是否生成字段常量
columnConstant: false
# 【实体、VO】是否为链式模型
chain: true
# 【实体、VO】 是否为lombok模型
lombok: true
# 【实体】乐观锁字段名称
versionColumnName: ''
# 【实体】乐观锁属性名称
versionPropertyName: ''
# 【实体】逻辑删除字段名称
logicDeleteColumnName: ''
# 【实体】逻辑删除属性名称
logicDeletePropertyName: ''
# 【实体】生成的@TableField注解上需要填充的字段和填充类型
fillColumnName:
- xxx: INSERT
# 【VO】格式化SaveVO文件名称
formatSaveVoFileName: ''
# 【VO】格式化UpdateVO文件名称
formatUpdateVoFileName: ''
# 【VO】格式化ResultVO文件名称
formatResultVoFileName: ''
# 【VO】格式化 PageQuery 文件名称
formatPageQueryFileName: ''
mapperConfig: # mapper类配置
# 格式化Mapper文件名称
formatMapperFileName: ''
# 格式化Xml文件名称
formatXmlFileName: ''
# 是否添加 @Mapper 注解(默认 false)
mapperAnnotation: false
# mapper类上是否添加忽略表结构 @InterceptorIgnore
columnAnnotationTablePrefix:
- 表的前缀
# 生成的xml中,是否包含BaseResultMap(默认 false)
baseResultMap: true
serviceConfig:
# 继承的Service类全称,带包名
superServiceClass: top.tangyh.basic.base.service.SuperService
# 继承的ServiceImpl类全称,带包名
superServiceImplClass: top.tangyh.basic.base.service.impl.SuperServiceImpl
# 格式化service接口文件名称
formatServiceFileName: '{}Service'
# 格式化service实现类文件名称
formatServiceImplFileName: ''
# 匹配到此前缀的表,生成的 serviceImpl 类上会自动添加切换数据源注解 @DS
dsTablePrefix:
- xxx
managerConfig:
# 继承的Manager类全称,带包名
superManagerClass: 'top.tangyh.basic.base.manager.SuperManager'
# 继承的ManagerImpl类全称,带包名
superManagerImplClass: 'top.tangyh.basic.base.manager.impl.SuperManagerImpl'
# 格式化Manager接口文件名称
formatManagerFileName: ''
# 格式化Manager实现类文件名称
formatManagerImplFileName: ''
controllerConfig:
# 生成 @RestController 控制器(默认 false)
restStyle: true
# 格式化文件名称
formatFileName: ''
# 驼峰转连字符
hyphenStyle: false
# 继承的Controller类全称,带包名
superClass: 'top.tangyh.basic.base.controller.SuperController'
webProConfig:
# 格式化菜单文件名称
formatMenuName: {}维护
# 前端生成页面样式模板
tpl: SIMPLE
fileOverrideStrategy: # 文件覆盖策略
entityFileOverride: OVERRIDE
sqlFileOverride: OVERRIDE
mapperFileOverride: EXIST_IGNORE
xmlFileOverride: OVERRIDE
managerFileOverride: EXIST_IGNORE
serviceFileOverride: EXIST_IGNORE
controllerFileOverride: EXIST_IGNORE
apiModelFileOverride: OVERRIDE
langFileOverride: OVERRIDE
indexEditTreeFileOverride: EXIST_IGNORE
dataFileOverride: EXIST_IGNORE
constantsPackage: # 公共枚举的完整类名,配置后自定义的枚举类才能正常 import
# 业务服务 后台手动改动过的枚举
FieldFill: com.baomidou.mybatisplus.annotation.FieldFill
SuperClassEnum: top.tangyh.lamp.generator.enumeration.SuperClassEnum
EntitySuperClassEnum: top.tangyh.lamp.generator.enumeration.EntitySuperClassEnum
# common 常量
EchoDictType: top.tangyh.lamp.model.constant.EchoDictType
EchoApi: top.tangyh.lamp.model.constant.EchoApi
# common 公共枚举
HttpMethod: top.tangyh.lamp.model.enumeration.HttpMethod
BooleanEnum: top.tangyh.lamp.model.enumeration.BooleanEnum
StateEnum: top.tangyh.lamp.model.enumeration.StateEnum
UserStatusEnum: top.tangyh.lamp.model.enumeration.base.UserStatusEnum
RoleCategoryEnum: top.tangyh.lamp.model.enumeration.base.RoleCategoryEnum
ActiveStatusEnum: top.tangyh.lamp.model.enumeration.base.ActiveStatusEnum
OrgTypeEnum: top.tangyh.lamp.model.enumeration.base.OrgTypeEnum
FileType: top.tangyh.lamp.model.enumeration.base.FileType
DateType: top.tangyh.lamp.model.enumeration.base.DateType
DictClassifyEnum: top.tangyh.lamp.model.enumeration.system.DictClassifyEnum
DefTenantStatusEnum: top.tangyh.lamp.model.enumeration.system.DefTenantStatusEnum
DataTypeEnum: top.tangyh.lamp.model.enumeration.system.DataTypeEnum
TenantConnectTypeEnum: top.tangyh.lamp.model.enumeration.system.TenantConnectTypeEnum
配置生成信息
用于配置生成的代码存放路径、文件名、代码结构等信息。

服务名
确保前端ServicePrefixEnum中的枚举值KEY 与 后端“服务名”和lamp-gateway-server.yml中“uri”保持一致
确保前端ServicePrefixEnum中的枚举值VALUE 与 后端lamp-gateway-server.yml中“predicates”配置一致
如: lamp-base、lamp-base-api、lamp-base-biz、lamp-base-controller、lamp-base-server 中的 base
如: lamp-system-server 中的 system
父包名
生成业务代码的基础包包名。如:"top.tangyh.lamp.base.dao.common" 中的 "top.tangyh.lamp"
模块名
建议跟{服务名}保持一致。如:
"top.tangyh.lamp.base.dao.common" 中的 "base"
"top.tangyh.lamp.file.dao" 中的 "file"
子包名
"top.tangyh.lamp.base.dao.common" 中的 "common"
"top.tangyh.lamp.base.dao.system" 中的 "system"
实体父类
实体类需要继承谁,参考:EntitySuperClassEnum
父类
Controller、Service、Manager、Mapper类需要继承谁,参考:SuperClassEnum
@DS
ServiceImpl类是否标记@DS注解,加上该注解后,sql操作会自动切换数据源。
datasource模式才会使用该参数,column、none模式请忽略。
数据源
@DS选是,ServiceImpl类标记的@DS注解具体值
@TenantLine
Mapper类是否标记@TenantLine注解,加上该注解sql操作不会自动拼接租户ID。
column模式才会使用该参数,datasource、none模式请忽略。
lombok
实体类是否使用Lombok注解
链式模型
实体类是否使用@Accessors(chain = true)注解
生成字段常量
实体类中是否生成字段常量
后端生成路径
前端生成路径
前端应用名
src/views/ 目录下的 basic 或 devOperation 或 “其他”
src/api/ 目录下的 basic 或 devOperation 或 “其他”
src/locales/lang/{语言}/ 目录下的 basic 或 devOperation 或 “其他”
“其他” 表示其他应用
前端模块名
src/api/{前端应用名} 目录下的文件夹名
src/views/{前端应用名} 目录下的文件夹名
src/locales/lang/{语言}/{前端应用名} 目录下的文件夹名
如: src/views/devOperation/ 下的 application、developer 等目录
如: src/api/devOperation/ 下的 application、developer 等目录
弹窗方式
前端代码index.vue页面点击新增或编辑时,弹窗的打开方式
生成模板
前端代码生成何种操作风格的页面
显示[新增|编辑|删除|复制|详情]按钮
生成的前端页面,是否包含新增、编辑、删除、复制、详情等按钮
[新增|编辑|删除|复制|详情]按钮权限
生成的前端页面,新增、编辑、删除、复制、详情等按钮是否控制按钮权限
菜单所属应用
当前功能生成后,菜单属于哪个应用?
上级菜单
当前功能生成后,显示在左侧菜单的位置
当前菜单名
当前功能生成后,显示在左侧的菜单名
菜单图标
当前功能生成后,显示在左侧的菜单图标
配置字段信息
用于配置生成的实体类字段的信息,默认值来源于导入时,读取表结构元数据信息。
列名称
字段的原始名称
提示
“原始”的意思是,数据库表结构中是什么这里就存什么。
列类型
字段的原始数据库类型
列描述
字段的原始注释。在生成代码时,会将列描述生成到字段的注释中。
文档描述
体现在Swagger注解上的注释。导入时,将列描述截取
;
前的字符作为文档描述。实现代码:/** * @param comment 列描述 */ private static String getSwaggerComment(String comment) { String swaggerComment = StrUtil.isBlank(comment) ? StrUtil.EMPTY : StrUtil.trim(comment); if (swaggerComment.contains(StrPool.SEMICOLON)) { swaggerComment = StrUtil.subBefore(swaggerComment, StrPool.SEMICOLON, false); } // 若含有换行符,替换为空格 // \n 是mysql注释中的换行符,其他数据库的换行符需要自己改这里代码适配下 swaggerComment = StrUtil.replace(swaggerComment, "\n", " "); return swaggerComment; }
JAVA类型
根据列类型自动映射的Java字段类型。
public static DefGenTableColumn initColumnField(GeneratorConfig generatorConfig, DbType dbType, DefGenTable genTable, Column column) { ITypeConvert typeConvert = TypeConverts.getTypeConvert(dbType); ColumnType columnType = typeConvert.processTypeConvert(entityConfig.getDateType(), column.getTypeName(), column.getSize(), column.getDigit()); // JAVA类型 tableColumn.setJavaType(columnType.getType()); // TS类型 tableColumn.setTsType(columnType.getTsType()); }
TS类型
根据列类型按照一定的规则转换为前端TS语法类型。
JAVA字段名
根据列名称按照一定的规则转换为Java实体类和VO类的字段名。
/** * @param name 列名称 * @param strategy 策略 * @param prefix 前缀 * @param suffix 后缀 * @return java.lang.String * @date 2023/4/16 10:45 PM */ private static String processName(String name, NamingStrategy strategy, List<String> prefix, List<String> suffix) { String propertyName = name; // 删除前缀 if (prefix.size() > 0) { propertyName = NamingStrategy.removePrefix(propertyName, prefix); } // 删除后缀 if (suffix.size() > 0) { propertyName = NamingStrategy.removeSuffix(propertyName, suffix); } if (StringUtils.isBlank(propertyName)) { throw new RuntimeException(String.format("%s 的名称转换结果为空,请检查是否配置问题", name)); } // 下划线转驼峰 if (NamingStrategy.underline_to_camel.equals(strategy)) { return NamingStrategy.underlineToCamel(propertyName); } return propertyName; }
必填
表示该字段是否必填字段,会在生成的SaveVO和UpdateVO中生成
@NotEmpty
或@NotNull
注解。长度
字段长度。字符串类型、SHORT、BYTE,会自动在SaveVO、UpdateVO的字段上标记
@Size(max={长度})
注解用于表单校验。<!-- saveVO.java.ftl、updateVO.java.ftl --> <#if field.javaType == "String"> @Size(max = ${field.size?string("##0")}, message = "${field.swaggerComment!}长度不能超过${r'{max}'}") <#else> <#if field.type?upper_case?starts_with("SHORT")> @Size(min = Short.MIN_VALUE, max = Short.MAX_VALUE, message = "${field.customMap.fieldComment!}大小不能超过${r'{max}'}") </#if> <#if field.type?upper_case?starts_with("BYTE")> @Size(min = Byte.MIN_VALUE, max = Byte.MAX_VALUE, message = "${field.customMap.fieldComment!}大小不能超过${r'{max}'}") </#if> </#if> private ${field.javaType} ${field.javaField};
主键
生成代码时,该字段是否为注解。
<!-- entity.java.ftl --> <#list fields as field> /** * ${field.comment!?replace("\n","\n * ")} */ <#if field.isPk> <#-- 主键: 使用 @TableId 自增: type = IdType.AUTO --> @TableId(value = "${field.name}"<#if field.isIncrement>, type = IdType.AUTO<#elseif entityConfig.idType??>, type = IdType.${entityConfig.idType}</#if>) <#else> @TableField(value = "${field.name}"<#if field.fill?? && field.fill?trim != ''>, fill = FieldFill.${field.fill}</#if><#if field.queryType?? && field.queryType?trim != ''>, condition = ${field.queryType}<#else></#if>) </#if> <#-- 乐观锁 --> <#if field.isVersionField> @Version </#if> <#-- 逻辑删除 --> <#if field.isLogicDeleteField> @TableLogic </#if> private ${field.javaType} ${field.javaField}; </#list>
注意
若你的实体类已经继承了Entity和SuperEntity,主键属性请保持默认值,否则生成的代码可能无法运行。
因为代码生成器只负责根据模板生成代码,不负责检查代码逻辑是否正确,若由于你配置错误,导致生成出来的代码无法运行,属于正常现象。
自增
若该字段配置为主键,还可以配置是否自增。
逻辑删除
标记该字段是否逻辑删除字段
注意
代码生成器只负责在该字段上生成注解,不负责代码执行时的逻辑删除功能,功能如何实现请参考mybaits-plus官方文档配置。
乐观锁
标记该字段是否乐观锁字段
注意
代码生成器只负责在该字段上生成注解,不负责实现代码的乐观锁功能,功能如何实现请参考mybaits-plus官方文档配置。
填充类型
字段的填充类型。参考mybaits-plus文档
@TableField(fill = FieldFill.${field.fill})
查询方式
可选值: like、eq 。参考mybaits-plus文档
@TableField(condition = ${field.queryType})
编辑
是否将该字段生成到前端编辑页 表单。
列表
是否将该字段生成到前端列表页 表格字段。
查询
是否将该字段生成到前端列表页 查询条件区域。
宽度
生成的字段在前端表格上显示时的宽度。
组件
生成的字段在前端表单显示什么组件样式。 参考vben官方文档
VxeTable组件
生成的字段在前端vxe-table显示什么组件样式。 参考vxe-table官方文档
Echo
生成的字段如何回显。
import getEchoType getEnumStr EchoType echoType = CommentUtils.getEchoType(column.getComment()); if (echoType != null) { // Echo tableColumn.setEchoStr(echoType.getEchoStr()); // 字典类型 tableColumn.setDictType(echoType.getDictType()); } // 解析注释中的枚举类型 EnumType enumType = CommentUtils.getEnumStr(genTable.getEntityName(), tableColumn.getJavaField(), entityConfig.getFormatEnumFileName(), tableColumn.getSwaggerComment(), column.getComment()); if (enumType != null) { tableColumn.setEnumStr(enumType.getEnumStr()); tableColumn.setJavaType(enumType.getEnumName()); // 枚举类型的回显注解固定值 tableColumn.setEchoStr("@Echo(api = Echo.ENUM_API)"); tableColumn.setTsType("string"); tableColumn.setComponent(ComponentEnum.PLUS_API_RADIO_GROUP.getValue()); tableColumn.setVxeComponent(VxeComponentEnum.$RADIO.getValue()); tableColumn.setQueryType(SqlConditionEnum.EQUAL); }
public static EchoType getEchoType(String comment) { if (StrUtil.isEmpty(comment)) { return null; } Matcher matcher = ECHO_FIELD_PATTERN.matcher(comment); if (matcher.find()) { String echoStr = trim(matcher.group(1)); String apiValue = trim(matcher.group(3)); String refValue = trim(matcher.group(5)); String beanClassValue = trim(matcher.group(7)); String dictType = trim(matcher.group(9)); EchoType et = new EchoType(); et.setEchoStr(echoStr); et.setApi(apiValue); et.setRef(refValue); et.setDictType(dictType); et.setBeanClass(beanClassValue); et.valid(); return et; } return null; }
public static EnumType getEnumStr(String entityName, String javaField, String formatEnumFileName, String swaggerComment, String comment) { if (StrUtil.isEmpty(comment)) { return null; } EnumType et = new EnumType(); et.setSwaggerComment(swaggerComment); Matcher matcher = ENUM_FIELD_PATTERN.matcher(comment); if (matcher.find()) { // 枚举字符串 String enumStr = trim(matcher.group(1)); // 枚举名称 String enumName = trim(matcher.group(2)); // kv String keyValue = trim(matcher.group(3)); et.setEnumStr(enumStr); enumName = StrUtil.isEmpty(enumName) ? getName(entityName + StrUtil.upperFirst(javaField), formatEnumFileName, GenCodeConstant.ENUM) : enumName; et.setEnumName(enumName); et.setKeyValue(keyValue); List<EnumTypeKeyValue> kvList = new ArrayList<>(); if (StrUtil.isNotEmpty(keyValue)) { keyValue = keyValue.endsWith(StrPool.SEMICOLON) ? keyValue : keyValue + StrPool.SEMICOLON; Matcher kvMatcher = ENUM_KEY_VALUE_PATTERN.matcher(keyValue); while (kvMatcher.find()) { String key = trim(kvMatcher.group(1)); String valueStr = trim(kvMatcher.group(2)); List<String> valueList = StrUtil.split(valueStr, StrPool.COMMA); List<String> values = valueList.stream().filter(StrUtil::isNotEmpty).collect(Collectors.toList()); EnumTypeKeyValue etKv = new EnumTypeKeyValue(); etKv.setKey(key); etKv.setValues(values); kvList.add(etKv); } } et.setKvList(kvList); return et; } return null; }
字典类型
生成的字段需要回显,且为字典类型时,配置该字段的枚举类型。
枚举
生成的字段为枚举类型时,字段注释中的值。
默认值
显示在前端表单中的默认值。
提示信息
前端表单中的感叹号提示信息。
主页提示信息
前端表格的表头上的感叹号提示信息。
预览
根据前面步骤总配置的信息,实时预览生成的前端、后端、SQL语句等代码。
本地生成或远程下载
可以分别生成或下载前端或后端的代码。
生成策略
覆盖
无论是否有同名文件,都覆盖原文件覆盖生成。
新增
若检测到有同名文件,就在同一个文件夹下新增一个文件,文件名后缀为 _new
忽略
无论是否有同名文件,都忽略生成此文件
存在时忽略
检测到同名文件就忽略生成,没有同名文件就立即生成。
❗️❗️❗️若评论区无法显示,请使用"手机热点"或"科学上网"。