项目地址:https://github.com/xuanshuangchen/canna-cloud.git
1、通过简化配置文件,方便开发
datasource.type=com.alibaba.druid.pool.DruidDataSource
datasource.driverJarPath=org/postgresql/postgresql/42.2.5/postgresql-42.2.5.jar
datasource.driverClassName=org.postgresql.Driver
datasource.url=jdbc:postgresql://127.0.0.1:5432/db_canna
datasource.username=postgres
datasource.password=postgres
TEMP_PROJECT_PATH=/temp/
GENERATOR_TABLE_CONF_NAME=generator/app.ini
driverJarPath直接读取maven的工程目录,减少了驱动可能不存在的问题。
2、表配置
[module_app]
modulePackage=com.flower.canna.cloud.service.app
contextName=canna-cloud-service-app
projectPath=/canna-cloud/canna-cloud-service/canna-cloud-service-app/
schema=public
moduleSchema=module_app
[table_common]
t_app_info=AppInfo
[column_t_app_info]
columnName=type
javaType=com.flower.canna.service.common.mybatis.EnumType
typeHandler=com.flower.canna.cloud.base.biz.mybatis.CommonEnumTypeHandler
suffix=::jsonb
operation=<=
同一个模块,只需指定工程的路径,便可直接生成全部相应的定制化程序。
对应自定义处理字段,可通过配置相应的处理方法,实现字段的映射。
3、生成后的配置文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<classPathEntry location="/maven/repo/org/postgresql/postgresql/42.2.5/postgresql-42.2.5.jar"/>
<context id="canna-cloud-service-app" targetRuntime="com.flower.canna.cloud.generator.mybatis.runtime.CannaTableMyBatis3">
<plugin type="com.flower.canna.cloud.generator.mybatis.plugins.ModelMapperPlugin"/>
<plugin type="com.flower.canna.cloud.generator.mybatis.plugins.MapperXmlMapperPlugin"/>
<plugin type="com.flower.canna.cloud.generator.mybatis.plugins.ExpandMapperXmlMapperPlugin"/>
<plugin type="com.flower.canna.cloud.generator.mybatis.plugins.biz.JavaServicePlugin"/>
<plugin type="com.flower.canna.cloud.generator.mybatis.plugins.biz.JavaEnumPlugin"/>
<plugin type="com.flower.canna.cloud.generator.mybatis.plugins.CommonMapperPlugin"/>
<commentGenerator type="com.flower.canna.cloud.generator.mybatis.rewrite.RemarkDefaultCommentGenerator">
<property name="suppressAllComments" value="true"/>
</commentGenerator>
<jdbcConnection driverClass="org.postgresql.Driver" connectionURL="jdbc:postgresql://120.78.61.232:35432/db_wallet" userId="postgres" password="postgres">
<property name="remarksReporting" value="true"/>
<property name="useInformationSchema" value="true"/>
</jdbcConnection>
<javaModelGenerator targetPackage="com.flower.canna.cloud.service.app.api.model" targetProject="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-api/src/main/java">
<property name="enableSubPackages" value="false"/>
<property name="rootClass" value="com.flower.canna.cloud.base.biz.model.Identifiable"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<sqlMapGenerator targetPackage="mybatis.postgresql.com.flower.canna.cloud.service.app" targetProject="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-producer/src/main/resources">
<property name="enableSubPackages" value="false"/>
</sqlMapGenerator>
<javaClientGenerator targetPackage="com.flower.canna.cloud.service.app.producer.mapper" targetProject="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-producer/src/main/java" type="CANNA_MAPPER">
<property name="enableSubPackages" value="false"/>
<property name="rootInterface" value="com.flower.canna.cloud.base.biz.mapper.BaseMapper"/>
</javaClientGenerator>
<table tableName="t_app_info" domainObjectName="AppInfo" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" catalog="catalog" alias="t">
<property name="runtimeSchema" value="${module_app}"/>
<property name="enableSubPackages" value="false"/>
<property name="serviceGenerator-targetPackage" value="com.flower.canna.cloud.service.app.api.service"/>
<property name="serviceGenerator-targetProject" value="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-api/src/main/java"/>
<property name="serviceGenerator-template" value="common/service.vm"/>
<property name="serviceGenerator-serviceName" value="AppInfoService"/>
<property name="serviceGenerator-serviceFullName" value="com.flower.canna.cloud.service.app.api.service.AppInfoService"/>
<property name="serviceGenerator-firstLowServiceName" value="appInfoService"/>
<property name="serviceGenerator-firstLowConsumerServiceName" value="appInfoConsumerService"/>
<property name="serviceGenerator-restPath" value="/app/info"/>
<property name="serviceGenerator-feignClientName" value="T-APP-INFO"/>
<property name="serviceImplGenerator-targetPackage" value="com.flower.canna.cloud.service.app.producer.service"/>
<property name="serviceImplGenerator-targetProject" value="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-producer/src/main/java"/>
<property name="serviceImplGenerator-template" value="common/service-impl.vm"/>
<property name="serviceImplGenerator-serviceName" value="AppInfoService"/>
<property name="serviceImplGenerator-serviceFullName" value="com.flower.canna.cloud.service.app.api.service.AppInfoService"/>
<property name="serviceImplGenerator-firstLowServiceName" value="appInfoService"/>
<property name="serviceImplGenerator-firstLowConsumerServiceName" value="appInfoConsumerService"/>
<property name="serviceImplGenerator-restPath" value="/app/info"/>
<property name="serviceImplGenerator-feignClientName" value="T-APP-INFO"/>
<property name="producerControllerGenerator-targetPackage" value="com.flower.canna.cloud.service.app.producer.controller"/>
<property name="producerControllerGenerator-targetProject" value="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-producer/src/main/java"/>
<property name="producerControllerGenerator-template" value="eurake-base/producer-controller.vm"/>
<property name="producerControllerGenerator-serviceName" value="AppInfoService"/>
<property name="producerControllerGenerator-serviceFullName" value="com.flower.canna.cloud.service.app.api.service.AppInfoService"/>
<property name="producerControllerGenerator-firstLowServiceName" value="appInfoService"/>
<property name="producerControllerGenerator-firstLowConsumerServiceName" value="appInfoConsumerService"/>
<property name="producerControllerGenerator-restPath" value="/app/info"/>
<property name="producerControllerGenerator-feignClientName" value="T-APP-INFO"/>
<property name="consumerControllerGenerator-targetPackage" value="com.flower.canna.cloud.service.app.consumer.controller"/>
<property name="consumerControllerGenerator-targetProject" value="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-consumer/src/main/java"/>
<property name="consumerControllerGenerator-template" value="eurake-base/consumer-controller.vm"/>
<property name="consumerControllerGenerator-serviceName" value="AppInfoService"/>
<property name="consumerControllerGenerator-serviceFullName" value="com.flower.canna.cloud.service.app.api.service.AppInfoService"/>
<property name="consumerControllerGenerator-firstLowServiceName" value="appInfoService"/>
<property name="consumerControllerGenerator-firstLowConsumerServiceName" value="appInfoConsumerService"/>
<property name="consumerControllerGenerator-restPath" value="/app/info"/>
<property name="consumerControllerGenerator-feignClientName" value="T-APP-INFO"/>
<property name="consumerRemoteGenerator-targetPackage" value="com.flower.canna.cloud.service.app.consumer.remote"/>
<property name="consumerRemoteGenerator-targetProject" value="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-consumer/src/main/java"/>
<property name="consumerRemoteGenerator-template" value="eurake-base/consumer-remote.vm"/>
<property name="consumerRemoteGenerator-serviceName" value="AppInfoService"/>
<property name="consumerRemoteGenerator-serviceFullName" value="com.flower.canna.cloud.service.app.api.service.AppInfoService"/>
<property name="consumerRemoteGenerator-firstLowServiceName" value="appInfoService"/>
<property name="consumerRemoteGenerator-firstLowConsumerServiceName" value="appInfoConsumerService"/>
<property name="consumerRemoteGenerator-restPath" value="/app/info"/>
<property name="consumerRemoteGenerator-feignClientName" value="T-APP-INFO"/>
<property name="consumerServiceGenerator-targetPackage" value="com.flower.canna.cloud.service.app.consumer.service"/>
<property name="consumerServiceGenerator-targetProject" value="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-consumer/src/main/java"/>
<property name="consumerServiceGenerator-template" value="eurake-base/consumer-service.vm"/>
<property name="consumerServiceGenerator-serviceName" value="AppInfoService"/>
<property name="consumerServiceGenerator-serviceFullName" value="com.flower.canna.cloud.service.app.api.service.AppInfoService"/>
<property name="consumerServiceGenerator-firstLowServiceName" value="appInfoService"/>
<property name="consumerServiceGenerator-firstLowConsumerServiceName" value="appInfoConsumerService"/>
<property name="consumerServiceGenerator-restPath" value="/app/info"/>
<property name="consumerServiceGenerator-feignClientName" value="T-APP-INFO"/>
<property name="enumsGenerator-targetPackage" value="com.flower.canna.cloud.service.app.api.enums"/>
<property name="enumsGenerator-targetProject" value="/canna-cloud/canna-cloud-service/canna-cloud-service-app/canna-cloud-service-app-api/src/main/java"/>
<property name="enumsGenerator-template" value="not-exist-enum.vm"/>
<property name="enumsGenerator-serviceName" value="AppInfoService"/>
<property name="enumsGenerator-serviceFullName" value="com.flower.canna.cloud.service.app.api.service.AppInfoService"/>
<property name="enumsGenerator-firstLowServiceName" value="appInfoService"/>
<property name="enumsGenerator-firstLowConsumerServiceName" value="appInfoConsumerService"/>
<property name="enumsGenerator-restPath" value="/app/info"/>
<property name="enumsGenerator-feignClientName" value="T-APP-INFO"/>
<generatedKey column="id" sqlStatement="JDBC"/>
<columnOverride column="type" javaType="com.flower.canna.service.common.mybatis.EnumType" typeHandler="com.flower.canna.cloud.base.biz.mybatis.CommonEnumTypeHandler" delimitedColumnName="false">
<property name="operation" value="&lt;="/>
</columnOverride>
</table>
</context>
</generatorConfiguration>
4、通过一系列的自定义插件,完成相对应的代码生成
使用lombok,简化getter/setter,同时引入builder
public class ModelMapperPlugin extends PluginAdapter {
public ModelMapperPlugin() {
super();
}
@Override
public boolean validate(List<String> warnings) {
return true;
}
@Override
public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass,
IntrospectedTable introspectedTable) {
topLevelClass.addImportedType("lombok.AllArgsConstructor");
topLevelClass.addImportedType("lombok.Builder");
topLevelClass.addImportedType("lombok.Getter");
topLevelClass.addImportedType("lombok.NoArgsConstructor");
topLevelClass.addImportedType("lombok.Setter");
topLevelClass.addAnnotation("@AllArgsConstructor");
topLevelClass.addAnnotation("@Builder");
topLevelClass.addAnnotation("@NoArgsConstructor");
topLevelClass.addAnnotation("@Setter");
topLevelClass.addAnnotation("@Getter");
return true;
}
@Override
public boolean modelFieldGenerated(Field field,
TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
IntrospectedTable introspectedTable,
ModelClassType modelClassType) {
// 添加日期操作
if ("Date".equals(introspectedColumn.getFullyQualifiedJavaType().getShortName())) {
Field fieldPrefix = new Field(field.getName() + CommonConstants.DATE_PREFIX, FullyQualifiedJavaType.getStringInstance()); //$NON-NLS-1$
fieldPrefix.setVisibility(JavaVisibility.PRIVATE);
Field fieldSuffix = new Field(field.getName() + CommonConstants.DATE_SUFFIX, FullyQualifiedJavaType.getStringInstance()); //$NON-NLS-1$
fieldSuffix.setVisibility(JavaVisibility.PRIVATE);
topLevelClass.addField(fieldPrefix);
topLevelClass.addField(fieldSuffix);
try {
IntrospectedColumn columnPrefix = BeanTransferUtils.transferColumn(introspectedColumn, IntrospectedColumn.class, IntrospectedColumn.class);
columnPrefix.setActualColumnName(columnPrefix.getActualColumnName() + CommonConstants.DATE_PREFIX);
columnPrefix.setRemarks( columnPrefix.getRemarks() + "-起始" );
IntrospectedColumn columnSuffix = BeanTransferUtils.transferColumn(introspectedColumn, IntrospectedColumn.class, IntrospectedColumn.class);
columnSuffix.setActualColumnName(columnPrefix.getActualColumnName() + CommonConstants.DATE_SUFFIX);
columnSuffix.setRemarks( columnSuffix.getRemarks() + "-截止" );
context.getCommentGenerator().addFieldComment(fieldPrefix, introspectedTable, columnPrefix);
context.getCommentGenerator().addFieldComment(fieldSuffix, introspectedTable, columnSuffix);
}catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
@Override
public boolean modelSetterMethodGenerated(Method method,
TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
IntrospectedTable introspectedTable,
ModelClassType modelClassType) {
// 取消get/set
return false;
}
@Override
public boolean modelGetterMethodGenerated(Method method,
TopLevelClass topLevelClass, IntrospectedColumn introspectedColumn,
IntrospectedTable introspectedTable,
ModelClassType modelClassType) {
// 取消get/set
return false;
}
}
字段枚举的生成,避免在需要使用字段时,引入字符串,增加代码可读性
public class JavaEnumPlugin extends PluginAdapter {
public JavaEnumPlugin() {
super();
}
@Override
public boolean validate(List<String> warnings) {
return true;
}
@Override
public boolean clientGenerated(Interface interfaze, IntrospectedTable introspectedTable) {
this.generatorEnum(introspectedTable);
return true;
}
private void generatorEnum(IntrospectedTable introspectedTable) {
String tagName = TagConstants.ENUMS_GENERATOR;
Properties properties = introspectedTable.getTableConfiguration().getProperties();
String targetPackage = properties.getProperty(tagName + "-" + AttrConstants.TARGET_PACKAGE);
String targetProject = properties.getProperty(tagName + "-" + AttrConstants.TARGET_PROJECT);
String domainObjectName = introspectedTable.getTableConfiguration().getDomainObjectName();
String enumColumnJava = CannaUtils.getFullName(targetProject, targetPackage, domainObjectName,"Enum.java");
String packageLine = "package " + targetPackage + ";";
String enumName = "public enum " + domainObjectName + "Enum {";
List<String> resultList = new ArrayList<>();
resultList.add(packageLine);
resultList.add(enumName);
for ( IntrospectedColumn introspectedColumn: introspectedTable.getAllColumns() ) {
resultList.add(" " + introspectedColumn.getActualColumnName().toUpperCase() + ",");
}
resultList.add("}");
try {
FileUtils.writeLines(new File(enumColumnJava), CommonConstants.DEFAULT_CHARSET, resultList);
} catch (IOException e) {
System.err.println(e);
}
}
}
5、继承代码生成逻辑,添加自定义Mapper生成器
public class CannaTableMyBatis3 extends IntrospectedTableMyBatis3Impl {
@Override
public List<GeneratedXmlFile> getGeneratedXmlFiles() {
List<GeneratedXmlFile> answer = new ArrayList<>();
if (xmlMapperGenerator != null) {
Document document = xmlMapperGenerator.getDocument();
GeneratedXmlFile gxf = new GeneratedXmlFile(document,
getMyBatis3XmlMapperFileName(), getMyBatis3XmlMapperPackage(),
context.getSqlMapGeneratorConfiguration().getTargetProject(),
false, context.getXmlFormatter());
if (context.getPlugins().sqlMapGenerated(gxf, this)) {
answer.add(gxf);
}
}
return answer;
}
protected AbstractJavaClientGenerator createJavaClientGenerator() {
if (context.getJavaClientGeneratorConfiguration() == null) {
return null;
}
String type = context.getJavaClientGeneratorConfiguration()
.getConfigurationType();
AbstractJavaClientGenerator javaGenerator;
if ("XMLMAPPER".equalsIgnoreCase(type)) { //$NON-NLS-1$
javaGenerator = new JavaMapperGenerator(getClientProject());
} else if ("MIXEDMAPPER".equalsIgnoreCase(type)) { //$NON-NLS-1$
javaGenerator = new MixedClientGenerator(getClientProject());
} else if ("ANNOTATEDMAPPER".equalsIgnoreCase(type)) { //$NON-NLS-1$
javaGenerator = new AnnotatedClientGenerator(getClientProject());
} else if ("MAPPER".equalsIgnoreCase(type)) { //$NON-NLS-1$
javaGenerator = new JavaMapperGenerator(getClientProject());
} else if ("CANNA_MAPPER".equalsIgnoreCase(type)) { //$NON-NLS-1$
javaGenerator = new CannaJavaMapperGenerator(getClientProject());
} else {
javaGenerator = (AbstractJavaClientGenerator) ObjectFactory
.createInternalObject(type);
}
return javaGenerator;
}
}
6、自动生成apidoc,方便前后端对接
public class RemarkDefaultCommentGenerator extends DefaultCommentGenerator {
@Override
public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {
innerClass.addJavaDocLine("/**");
innerClass.addJavaDocLine(" * @apiDefine SUCCESS_" + introspectedTable.getFullyQualifiedTable().getDomainObjectName());
List<IntrospectedColumn> introspectedColumnList = introspectedTable.getAllColumns();
for (IntrospectedColumn introspectedColumn: introspectedColumnList){
innerClass.addJavaDocLine(" * @apiSuccess {" + introspectedColumn.getFullyQualifiedJavaType().getShortName() + "} " + introspectedColumn.getJavaProperty() + " " + introspectedColumn.getRemarks());
}
innerClass.addJavaDocLine(" */");
innerClass.addJavaDocLine("/**");
innerClass.addJavaDocLine(" * @apiDefine PARAM_" + introspectedTable.getFullyQualifiedTable().getDomainObjectName());
for (IntrospectedColumn introspectedColumn: introspectedColumnList){
innerClass.addJavaDocLine(" * @apiParam {" + introspectedColumn.getFullyQualifiedJavaType().getShortName() + "} " + introspectedColumn.getJavaProperty() + " " + introspectedColumn.getRemarks());
}
innerClass.addJavaDocLine(" */");
}
@Override
public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {
this.addClassComment(topLevelClass, introspectedTable);
}
@Override
public void addFieldComment(Field field, IntrospectedTable introspectedTable,
IntrospectedColumn introspectedColumn) {
field.addJavaDocLine("/**"); //$NON-NLS-1$
if (introspectedColumn.getRemarks() != null) {
field.addJavaDocLine(" * " + introspectedColumn.getRemarks()); //$NON-NLS-1$
}
field.addJavaDocLine(" */"); //$NON-NLS-1$
}
}