mybatis-generator扩展
在新公司的新项目想用mybatis-generator来生成DAO层,有同事提出一些改进意见,遂获得源码后进行小幅改造。
目标:
- 中文注释,精简注释
- Model类使用lombok简化
- 增加selectOneByExample方法(较多的使用唯一索引查询场景)
首先获得源码
在任一项目中引入jar包,使用maven download sources获取源码,最新版本1.3.7
<dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.7</version> </dependency>
构建项目
新建一个maven项目,设置groupId和artifactId
<groupId>com.mine.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.0-SNAPSHOT</version>
把解压后的源码复制到目录
在pom.xml中添加项目依赖
<dependencies> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <scope>provided</scope> <version>1.2.17</version> <optional>true</optional> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <scope>provided</scope> <version>1.7.25</version> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <scope>provided</scope> <version>2.11.0</version> <optional>true</optional> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <scope>provided</scope> <version>1.2</version> <optional>true</optional> </dependency> <dependency> <groupId>org.apache.ant</groupId> <artifactId>ant</artifactId> <scope>provided</scope> <version>1.10.4</version> <optional>true</optional> </dependency> <dependency> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> <version>5.2.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>2.4.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.github.javaparser</groupId> <version>3.6.12</version> <artifactId>javaparser-core</artifactId> </dependency> </dependencies>
功能拓展
model中文注释、精简其他注释
修改生成注释默认用的DefaultCommentGenerator
package org.mybatis.generator.internal; import org.mybatis.generator.api.CommentGenerator; import org.mybatis.generator.api.IntrospectedColumn; import org.mybatis.generator.api.IntrospectedTable; import org.mybatis.generator.api.MyBatisGenerator; import org.mybatis.generator.api.dom.java.*; import org.mybatis.generator.api.dom.xml.XmlElement; import org.mybatis.generator.internal.util.StringUtility; import java.text.SimpleDateFormat; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.Properties; import java.util.Set; /** * @author Jeff Butler */ public class DefaultCommentGenerator implements CommentGenerator { private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public DefaultCommentGenerator() { super(); } @Override public void addJavaFileComment(CompilationUnit compilationUnit) { } @Override public void addComment(XmlElement xmlElement) { } @Override public void addRootComment(XmlElement rootElement) { } @Override public void addConfigurationProperties(Properties properties) { } protected String getDateString() { return dateFormat.format(new Date()); } @Override public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) { } @Override public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) { } @Override public void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) { topLevelClass.addJavaDocLine("/**"); topLevelClass.addJavaDocLine(" * 生成日期:" + getDateString()); topLevelClass.addJavaDocLine(" * 表名: " + introspectedTable.getFullyQualifiedTable().toString()); topLevelClass.addJavaDocLine(" */"); } @Override public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) { } @Override public void addFieldComment(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) { field.addJavaDocLine("/**"); field.addJavaDocLine(" * " + introspectedColumn.getRemarks()); field.addJavaDocLine(" */"); } @Override public void addFieldComment(Field field, IntrospectedTable introspectedTable) { } @Override public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) { } @Override public void addGetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) { } @Override public void addSetterComment(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn) { } @Override public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) { imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); String comment = "Source Table: " + introspectedTable.getFullyQualifiedTable().toString(); method.addAnnotation(getGeneratedAnnotation(comment)); } @Override public void addGeneralMethodAnnotation(Method method, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) { imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); String comment = "Source field: " + introspectedTable.getFullyQualifiedTable().toString() + "." + introspectedColumn.getActualColumnName(); method.addAnnotation(getGeneratedAnnotation(comment)); } @Override public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) { imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); String comment = "Source Table: " + introspectedTable.getFullyQualifiedTable().toString(); field.addAnnotation(getGeneratedAnnotation(comment)); } @Override public void addFieldAnnotation(Field field, IntrospectedTable introspectedTable, IntrospectedColumn introspectedColumn, Set<FullyQualifiedJavaType> imports) { imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); String comment = "Source field: " + introspectedTable.getFullyQualifiedTable().toString() + "." + introspectedColumn.getActualColumnName(); field.addAnnotation(getGeneratedAnnotation(comment)); String remarks = introspectedColumn.getRemarks(); if (StringUtility.stringHasValue(remarks)) { field.addJavaDocLine("/**"); field.addJavaDocLine(" * Database Column Remarks:"); String[] remarkLines = remarks.split(System.getProperty("line.separator")); for (String remarkLine : remarkLines) { field.addJavaDocLine(" * " + remarkLine); } field.addJavaDocLine(" */"); } } @Override public void addClassAnnotation(InnerClass innerClass, IntrospectedTable introspectedTable, Set<FullyQualifiedJavaType> imports) { imports.add(new FullyQualifiedJavaType("javax.annotation.Generated")); String comment = "Source Table: " + introspectedTable.getFullyQualifiedTable().toString(); innerClass.addAnnotation(getGeneratedAnnotation(comment)); } private String getGeneratedAnnotation(String comment) { StringBuilder buffer = new StringBuilder(); buffer.append("@Generated("); buffer.append("value=\""); buffer.append(MyBatisGenerator.class.getName()); buffer.append('\"'); buffer.append(", date=\""); buffer.append(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(ZonedDateTime.now())); buffer.append('\"'); buffer.append(", comments=\""); buffer.append(comment); buffer.append('\"'); buffer.append(')'); return buffer.toString(); } }
Model类使用lombok简化
修改BaseRecordGenerator的getCompilationUnits的方法即可
public List<CompilationUnit> getCompilationUnits() { FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable(); progressCallback.startTask(getString( "Progress.8", table.toString())); //$NON-NLS-1$ Plugin plugins = context.getPlugins(); CommentGenerator commentGenerator = context.getCommentGenerator(); FullyQualifiedJavaType type = new FullyQualifiedJavaType( introspectedTable.getBaseRecordType()); TopLevelClass topLevelClass = new TopLevelClass(type); topLevelClass.addImportedType("lombok.Getter");// 导入lombok类 topLevelClass.addImportedType("lombok.Setter");
topLevelClass.addImportedType("lombok.ToString"); topLevelClass.setVisibility(JavaVisibility.PUBLIC); commentGenerator.addJavaFileComment(topLevelClass); FullyQualifiedJavaType superClass = getSuperClass(); if (superClass != null) { topLevelClass.setSuperClass(superClass); topLevelClass.addImportedType(superClass); } commentGenerator.addModelClassComment(topLevelClass, introspectedTable); topLevelClass.addAnnotation("@Getter");// 增加lombok注解 topLevelClass.addAnnotation("@Setter");
topLevelClass.addAnnotation("@ToString"); List<IntrospectedColumn> introspectedColumns = getColumnsInThisClass(); if (introspectedTable.isConstructorBased()) { addParameterizedConstructor(topLevelClass, introspectedTable.getNonBLOBColumns()); if (includeBLOBColumns()) { addParameterizedConstructor(topLevelClass, introspectedTable.getAllColumns()); } if (!introspectedTable.isImmutable()) { addDefaultConstructor(topLevelClass); } } String rootClass = getRootClass(); for (IntrospectedColumn introspectedColumn : introspectedColumns) { if (RootClassInfo.getInstance(rootClass, warnings) .containsProperty(introspectedColumn)) { continue; } Field field = getJavaBeansField(introspectedColumn, context, introspectedTable); if (plugins.modelFieldGenerated(field, topLevelClass, introspectedColumn, introspectedTable, Plugin.ModelClassType.BASE_RECORD)) { topLevelClass.addField(field); topLevelClass.addImportedType(field.getType()); } } List<CompilationUnit> answer = new ArrayList<>(); if (context.getPlugins().modelBaseRecordClassGenerated( topLevelClass, introspectedTable)) { answer.add(topLevelClass); } return answer;
}
增加selectOneByExample
首先查看类似的方法selectByExample是怎么生成的,然后参考增加这个方法。
在IntrospectedTable中增加方法
public String getSelectOneByExampleStatementId() {
return "selectOneByExample";//可以跟其他源码一样设置成常量,这里简单处理
}
增加一个SelectOneByExampleMethodGenerator
/** * Copyright 2006-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mybatis.generator.codegen.mybatis3.javamapper.elements; import org.mybatis.generator.api.dom.java.*; import java.util.Set; import java.util.TreeSet; /** * * @author Jeff Butler * */ public class SelectOneByExampleMethodGenerator extends AbstractJavaMapperMethodGenerator { public SelectOneByExampleMethodGenerator() { super(); } @Override public void addInterfaceElements(Interface interfaze) { Set<FullyQualifiedJavaType> importedTypes = new TreeSet<>(); FullyQualifiedJavaType type = new FullyQualifiedJavaType( introspectedTable.getExampleType()); importedTypes.add(type); importedTypes.add(FullyQualifiedJavaType.getNewListInstance()); Method method = new Method(); method.setVisibility(JavaVisibility.PUBLIC); FullyQualifiedJavaType returnType = introspectedTable.getRules() .calculateAllFieldsClass(); method.setReturnType(returnType); method.setName(introspectedTable.getSelectOneByExampleStatementId()); method.addParameter(new Parameter(type, "example")); //$NON-NLS-1$ context.getCommentGenerator().addGeneralMethodComment(method, introspectedTable); addMapperAnnotations(interfaze, method); if (context.getPlugins() .clientSelectByExampleWithBLOBsMethodGenerated(method, interfaze, introspectedTable)) { addExtraImports(interfaze); interfaze.addImportedTypes(importedTypes); interfaze.addMethod(method); } } public void addMapperAnnotations(Interface interfaze, Method method) { } public void addExtraImports(Interface interfaze) { } }
增加一个SelectOneByExampleElementGenerator
/** * Copyright 2006-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.mybatis.generator.codegen.mybatis3.xmlmapper.elements; import org.mybatis.generator.api.dom.xml.Attribute; import org.mybatis.generator.api.dom.xml.TextElement; import org.mybatis.generator.api.dom.xml.XmlElement; import static org.mybatis.generator.internal.util.StringUtility.stringHasValue; /** * * @author Jeff Butler * */ public class SelectOneByExampleElementGenerator extends AbstractXmlElementGenerator { public SelectOneByExampleElementGenerator() { super(); } @Override public void addElements(XmlElement parentElement) { String fqjt = introspectedTable.getExampleType(); XmlElement answer = new XmlElement("select"); //$NON-NLS-1$ answer.addAttribute(new Attribute("id", //$NON-NLS-1$ introspectedTable.getSelectOneByExampleStatementId())); answer.addAttribute(new Attribute( "resultMap", introspectedTable.getBaseResultMapId())); //$NON-NLS-1$ answer.addAttribute(new Attribute("parameterType", fqjt)); //$NON-NLS-1$ context.getCommentGenerator().addComment(answer); answer.addElement(new TextElement("select")); //$NON-NLS-1$ XmlElement ifElement = new XmlElement("if"); //$NON-NLS-1$ ifElement.addAttribute(new Attribute("test", "distinct")); //$NON-NLS-1$ //$NON-NLS-2$ ifElement.addElement(new TextElement("distinct")); //$NON-NLS-1$ answer.addElement(ifElement); StringBuilder sb = new StringBuilder(); if (stringHasValue(introspectedTable .getSelectByExampleQueryId())) { sb.append('\''); sb.append(introspectedTable.getSelectByExampleQueryId()); sb.append("' as QUERYID,"); //$NON-NLS-1$ answer.addElement(new TextElement(sb.toString())); } answer.addElement(getBaseColumnListElement()); sb.setLength(0); sb.append("from "); //$NON-NLS-1$ sb.append(introspectedTable .getAliasedFullyQualifiedTableNameAtRuntime()); answer.addElement(new TextElement(sb.toString())); answer.addElement(getExampleIncludeElement()); ifElement = new XmlElement("if"); //$NON-NLS-1$ ifElement.addAttribute(new Attribute("test", "orderByClause != null")); //$NON-NLS-1$ //$NON-NLS-2$ ifElement.addElement(new TextElement("order by ${orderByClause}")); //$NON-NLS-1$ answer.addElement(ifElement); if (context.getPlugins() .sqlMapSelectByExampleWithoutBLOBsElementGenerated(answer, introspectedTable)) { parentElement.addElement(answer); } answer.addElement(new TextElement("limit 1")); } }
修改JavaMapperGenerator,在getCompilationUnits方法中增加addSelectOneByExampleMethod(interfaze),这里顺带把生成的代码排了个序,并且把不常用的几个方法给注释掉了。
@Override
public List<CompilationUnit> getCompilationUnits() {
progressCallback.startTask(getString("Progress.17", //$NON-NLS-1$
introspectedTable.getFullyQualifiedTable().toString()));
CommentGenerator commentGenerator = context.getCommentGenerator();
FullyQualifiedJavaType type = new FullyQualifiedJavaType(
introspectedTable.getMyBatis3JavaMapperType());
Interface interfaze = new Interface(type);
interfaze.setVisibility(JavaVisibility.PUBLIC);
commentGenerator.addJavaFileComment(interfaze);
String rootInterface = introspectedTable
.getTableConfigurationProperty(PropertyRegistry.ANY_ROOT_INTERFACE);
if (!stringHasValue(rootInterface)) {
rootInterface = context.getJavaClientGeneratorConfiguration()
.getProperty(PropertyRegistry.ANY_ROOT_INTERFACE);
}
if (stringHasValue(rootInterface)) {
FullyQualifiedJavaType fqjt = new FullyQualifiedJavaType(
rootInterface);
interfaze.addSuperInterface(fqjt);
interfaze.addImportedType(fqjt);
}
addInsertSelectiveMethod(interfaze);
addDeleteByPrimaryKeyMethod(interfaze);
addDeleteByExampleMethod(interfaze);
addUpdateByPrimaryKeySelectiveMethod(interfaze);
addUpdateByExampleSelectiveMethod(interfaze);
addSelectByPrimaryKeyMethod(interfaze);
addSelectOneByExampleMethod(interfaze); //由addSelectByExampleWithoutBLOBsMethod改造而来
addSelectByExampleWithoutBLOBsMethod(interfaze);
addSelectByExampleWithBLOBsMethod(interfaze);
addCountByExampleMethod(interfaze);
//addInsertMethod(interfaze);
//addUpdateByExampleWithBLOBsMethod(interfaze);
//addUpdateByExampleWithoutBLOBsMethod(interfaze);
//addUpdateByPrimaryKeyWithBLOBsMethod(interfaze);
//addUpdateByPrimaryKeyWithoutBLOBsMethod(interfaze);
List<CompilationUnit> answer = new ArrayList<>();
if (context.getPlugins().clientGenerated(interfaze, null,
introspectedTable)) {
answer.add(interfaze);
}
List<CompilationUnit> extraCompilationUnits = getExtraCompilationUnits();
if (extraCompilationUnits != null) {
answer.addAll(extraCompilationUnits);
}
return answer;
}
//增加方法
protected void addSelectOneByExampleMethod(Interface interfaze) { AbstractJavaMapperMethodGenerator methodGenerator = new SelectOneByExampleMethodGenerator(); initializeAndExecuteGenerator(methodGenerator, interfaze); }
同样地,修改XMLMapperGenerator
protected XmlElement getSqlMapElement() { FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable(); progressCallback.startTask(getString( "Progress.12", table.toString())); //$NON-NLS-1$ XmlElement answer = new XmlElement("mapper"); //$NON-NLS-1$ String namespace = introspectedTable.getMyBatis3SqlMapNamespace(); answer.addAttribute(new Attribute("namespace", //$NON-NLS-1$ namespace)); context.getCommentGenerator().addRootComment(answer); addResultMapWithoutBLOBsElement(answer); addResultMapWithBLOBsElement(answer); addExampleWhereClauseElement(answer); addMyBatis3UpdateByExampleWhereClauseElement(answer); addBaseColumnListElement(answer); addBlobColumnListElement(answer); addInsertSelectiveElement(answer); addDeleteByPrimaryKeyElement(answer); addDeleteByExampleElement(answer); addUpdateByPrimaryKeySelectiveElement(answer); addUpdateByExampleSelectiveElement(answer); addSelectByPrimaryKeyElement(answer); addSelectOneByExampleElement(answer); addSelectByExampleWithoutBLOBsElement(answer); addSelectByExampleWithBLOBsElement(answer); addCountByExampleElement(answer); //addSelectByExampleWithBLOBsElement(answer); //addInsertElement(answer); //addUpdateByExampleWithBLOBsElement(answer); //addUpdateByExampleWithoutBLOBsElement(answer); //addUpdateByPrimaryKeyWithBLOBsElement(answer); //addUpdateByPrimaryKeyWithoutBLOBsElement(answer); return answer; }
//增加方法 protected void addSelectOneByExampleElement(XmlElement parentElement) { if (introspectedTable.getRules().generateSelectByExampleWithoutBLOBs()) { AbstractXmlElementGenerator elementGenerator = new SelectOneByExampleElementGenerator(); initializeAndExecuteGenerator(elementGenerator, parentElement); } }
投入使用
deploy项目打包,然后在需要使用的项目中,修改pom.xml引入,再使用generator的generate命令即可
<plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.7</version> <dependencies> <dependency> <groupId>com.mine.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </plugin>