Mybatis-Generator 可自动生成Model、Dao、Mapper代码,但其自带生成的代码存在以下问题:

  • 生成的注释不是我们想要的,我们期望的是根据数据库表、字段生成不同的注释;
  • 分页代码生成缺失,每个公司的分页方式不同,尤其是老久项目或已发布API,不能随意变动,那么如何自适应分页代码生成;
  • Mapper.xml没有group by相关代码生成;
  • 重复生成代码时,Mapper.xml并不是覆盖原代码;而是对内容进行了追加;
  • 序列化,mybatis-generator内置了SerializablePlugin,但仅对Model,并没有对 Example序列化,在一些开发中是不够的;
  • 对Service Layer代码没有生成。

实际上,mybatis-generator提供了PluginAdapter供我们来继承,进行个性化的一些扩展(Plugin的相关内容是阅读本文的前置条件)如果不熟悉的同学请自行补充,本文不对其进行相关介绍。同时,本文不可能涵盖所有业务所需的扩展点,基本样板已有,可参考本文代码继续进行扩展。

1、注释的自定义生成

根据数据库表或字段的COMMENT生成注释。@Date 生成的时间可根据需要自己定义格式。

package run.override;
import java.util.Date;
import java.util.Properties;import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.InnerClass;
import org.mybatis.generator.api.dom.java.InnerEnum;
import org.mybatis.generator.api.dom.java.JavaElement;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.DefaultCommentGenerator;
import org.mybatis.generator.internal.util.StringUtility;
/*** Comment Generator* @ClassName CommentGenerator * @Description * @author Marvis*/
public class CommentGenerator extends DefaultCommentGenerator {private Properties properties;private boolean suppressDate;private boolean suppressAllComments;public CommentGenerator() {this.properties = new Properties();this.suppressDate = false;this.suppressAllComments = false;}public void addJavaFileComment(CompilationUnit compilationUnit) {compilationUnit.addFileCommentLine("/*** copyright (c) 2019 Marvis  ***/");}/*** XML file Comment*/public void addComment(XmlElement xmlElement) {if (this.suppressAllComments) {return;}}public void addRootComment(XmlElement rootElement) {}public void addConfigurationProperties(Properties properties) {this.properties.putAll(properties);this.suppressDate = StringUtility.isTrue(properties.getProperty("suppressDate"));this.suppressAllComments = StringUtility.isTrue(properties.getProperty("suppressAllComments"));}protected void addJavadocTag(JavaElement javaElement, boolean markAsDoNotDelete) {StringBuilder sb = new StringBuilder();sb.append(" * ");sb.append("@date");String s = getDateString();if (s != null) {sb.append(' ');sb.append(s);}javaElement.addJavaDocLine(sb.toString());}protected String getDateString() {if (this.suppressDate) {return null;}return new Date().toString();}/** *  Comment of Example inner class(GeneratedCriteria ,Criterion)*/public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {if (this.suppressAllComments) {return;}innerClass.addJavaDocLine("/**");innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getDomainObjectName()+ "<p/>");innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().toString());addJavadocTag(innerClass, false);innerClass.addJavaDocLine(" */");}public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {if (this.suppressAllComments) {return;}StringBuilder sb = new StringBuilder();innerEnum.addJavaDocLine("/**");innerEnum.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getAlias()+ "<p/>");innerEnum.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable());innerEnum.addJavaDocLine(sb.toString());addJavadocTag(innerEnum, false);innerEnum.addJavaDocLine(" */");}/*** entity filed Comment*/public void addFieldComment(Field field, IntrospectedTable introspectedTable,IntrospectedColumn introspectedColumn) {if (this.suppressAllComments) {return;}//       if(introspectedColumn.getRemarks() != null && !introspectedColumn.getRemarks().trim().equals(""))field.addJavaDocLine("/**");field.addJavaDocLine(" * " + introspectedColumn.getRemarks());field.addJavaDocLine(" * @author " );field.addJavaDocLine(" * @date " + getDateString() );field.addJavaDocLine(" * @return");field.addJavaDocLine(" */");}/***  Comment of EXample filed */public void addFieldComment(Field field, IntrospectedTable introspectedTable) {if (this.suppressAllComments) {return;}field.addJavaDocLine("/**");addJavadocTag(field, false);field.addJavaDocLine(" */");}/*** Comment of Example method*/public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {if (this.suppressAllComments) {return;}}/*** * entity Getter Comment*/public void addGetterComment(Method method, IntrospectedTable introspectedTable,IntrospectedColumn introspectedColumn) {if (this.suppressAllComments) {return;}method.addJavaDocLine("/**");method.addJavaDocLine(" * @return " + introspectedTable.getFullyQualifiedTable().getAlias() + " : " + introspectedColumn.getRemarks());method.addJavaDocLine(" */");}public void addSetterComment(Method method, IntrospectedTable introspectedTable,IntrospectedColumn introspectedColumn) {if (this.suppressAllComments) {return;}StringBuilder sb = new StringBuilder();method.addJavaDocLine("/**");Parameter parm = (Parameter) method.getParameters().get(0);sb.append(" * @param ");sb.append(parm.getName());sb.append(" : ");sb.append(introspectedColumn.getRemarks());method.addJavaDocLine(sb.toString());method.addJavaDocLine(" */");}/*** Comment of Example inner class(Criteria)*/public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {if (this.suppressAllComments) {return;}innerClass.addJavaDocLine("/**");innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getAlias()+ "<p/>");innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().toString());addJavadocTag(innerClass, markAsDoNotDelete);innerClass.addJavaDocLine(" */");}

Model 类注释(表的描述): MySQL。

1)EntityCommentPlugin

package run.override.model;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Date;
import java.util.List;import org.mybatis.generator.api.FullyQualifiedTable;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.internal.JDBCConnectionFactory;
import org.mybatis.generator.internal.util.StringUtility;/*** Comment of Entity,only support MySQL* @ClassName CommentPlugin * @Description * @author Marvis*/
public class EntityCommentPlugin extends PluginAdapter {@Overridepublic boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {addModelClassComment(topLevelClass, introspectedTable);return super.modelBaseRecordClassGenerated(topLevelClass, introspectedTable);}@Overridepublic boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,IntrospectedTable introspectedTable) {addModelClassComment(topLevelClass, introspectedTable);return super.modelRecordWithBLOBsClassGenerated(topLevelClass, introspectedTable);}protected void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable();String tableComment = getTableComment(table);topLevelClass.addJavaDocLine("/**");if(StringUtility.stringHasValue(tableComment))topLevelClass.addJavaDocLine(" * " + tableComment + "<p/>");topLevelClass.addJavaDocLine(" * " + table.toString() + "<p/>");topLevelClass.addJavaDocLine(" * @date " + new Date().toString());topLevelClass.addJavaDocLine(" *");topLevelClass.addJavaDocLine(" */");}/*** @author Marvis* @date Jul 13, 2017 4:39:52 PM* @param table*/private String getTableComment(FullyQualifiedTable table) {String tableComment = "";Connection connection = null;Statement statement = null;ResultSet rs = null;try {JDBCConnectionFactory jdbc = new JDBCConnectionFactory(context.getJdbcConnectionConfiguration());connection = jdbc.getConnection();statement = connection.createStatement();rs = statement.executeQuery("SHOW CREATE TABLE " + table.getIntrospectedTableName());if (rs != null && rs.next()) {String createDDL = rs.getString(2);int index = createDDL.indexOf("COMMENT='");if (index < 0) {tableComment = "";} else {tableComment = createDDL.substring(index + 9);tableComment = tableComment.substring(0, tableComment.length() - 1);}}} catch (SQLException e) {} finally {closeConnection(connection, statement, rs);}return tableComment;}/*** * @author Marvis* @date Jul 13, 2017 4:45:26 PM* @param connection* @param statement* @param rs*/private void closeConnection(Connection connection, Statement statement, ResultSet rs) {try {if (null != rs)rs.close();} catch (SQLException e) {e.printStackTrace();} finally {try {if (statement != null)statement.close();} catch (Exception e) {e.printStackTrace();} finally {try {if (connection != null)connection.close();} catch (SQLException e) {e.printStackTrace();}}}}/*** This plugin is always valid - no properties are required*/@Overridepublic boolean validate(List<String> warnings) {return true;}
}

2、分页和分组代码生成

这里,我对Dao Model进行了通用方法的抽取,建立通用基类。同时,对其进行了一些扩展,增加分页和分组。

先对基类进行介绍。

1)BaseMapper

package cn.xxx.core.base.dao;import java.util.List;import org.apache.ibatis.annotations.Param;public interface BaseMapper<T, Example, ID> {long countByExample(Example example);int deleteByExample(Example example);int deleteByPrimaryKey(ID id);int insert(T record);int insertSelective(T record);List<T> selectByExample(Example example);T selectByPrimaryKey(ID id);int updateByExampleSelective(@Param("record") T record, @Param("example") Example example);int updateByExample(@Param("record") T record, @Param("example") Example example);int updateByPrimaryKeySelective(T record);int updateByPrimaryKey(T record);}

2)BaseExample

package cn.xxx.core.base.model;
/*** BaseExample 基类* @ClassName BaseExample* @Description 增加分页参数* @author Marvis* @date Jul 31, 2017 11:26:53 AM*/
public abstract class BaseExample {protected PageInfo pageInfo;protected String groupByClause;public PageInfo getPageInfo() {return pageInfo;}public void setPageInfo(PageInfo pageInfo) {this.pageInfo = pageInfo;}public String getGroupByClause() {return groupByClause;}public void setGroupByClause(String groupByClause) {this.groupByClause = groupByClause;}}

3)PageInfo

package cn.xxx.core.base.model;import com.fasterxml.jackson.annotation.JsonIgnore;/*** 分页查询参数类* * @author**/
public class PageInfo {public static final int Default_PageSize = 20;// 当前页码protected int currentPage = 1;// 总页数protected int totalPage;// 总记录数protected int totalCount;// 每页条数protected int pageSize = Default_PageSize;// 开始protected int pageBegin = 0;// 结束protected int pageEnd = 20;/*** bean起始坐标(不包含)*/private Integer pageBeginId = null;public static final String PageQuery_classname = "pageInfo";/*** 将分布参数传入处理,最终计算出当前页码PageQuery_currPage,开始坐标PageQuery_star,* 结束坐标PageQuery_end,总页数PageQuery_Psize* <p/>* 页数从1开始计数* * @param totalCount*            记录总数* @param pageSize*            每页显示个数* @param currentPage*            当前页码*/public void setPageParams(int totalCount, int pageSize, int currentPage) {this.totalPage = pageSize == 0 ? 1 : (int) Math.ceil((double) totalCount / (double) pageSize);this.totalCount = totalCount;this.pageSize = pageSize;this.currentPage = currentPage;float Psize_l = totalCount / (float) (this.pageSize);if (currentPage < 2) {currentPage = 1;pageBegin = 0;} else if (currentPage > Psize_l) {if (Psize_l == 0) {currentPage = 1;} else {currentPage = (int) Math.ceil(Psize_l);}pageBegin = (currentPage - 1) * this.pageSize;} else {pageBegin = (currentPage - 1) * this.pageSize;}pageSize = (int) Math.ceil(Psize_l);this.pageEnd = currentPage * this.pageSize;if (this.currentPage <= 0 || this.currentPage > this.totalPage)this.pageSize = 0;}/*** 将分布参数传入处理,最终计算出当前页码PageQuery_currPage,开始坐标PageQuery_star,* 结束坐标PageQuery_end,总页数PageQuery_Psize* * @param infoCount*            记录总数*/public void setPageParams(int totalCount) {this.setPageParams(totalCount, this.pageSize, this.currentPage);}@Overridepublic String toString() {return "PageInfo [currentPage=" + currentPage + ", totalPage=" + totalPage + ", totalCount=" + totalCount+ ", pageSize=" + pageSize + ", pageBegin=" + pageBegin + ", pageEnd=" + pageEnd + ", pageBeginId="+ pageBeginId + "]";}public int getCurrentPage() {return currentPage;}public int getTotalPage() {return totalPage;}public int getTotalCount() {return totalCount;}/*** 每页显示个数*/public int getPageSize() {return pageSize;}@JsonIgnorepublic int getPageBegin() {return pageBegin;}@JsonIgnorepublic int getPageEnd() {return pageEnd;}/*** bean起始id(不包含)*/@JsonIgnorepublic Integer getPageBeginId() {return pageBeginId;}/*** 请求页*/public void setCurrentPage(int currentPage) {this.currentPage = currentPage;}/*** 每页显示个数*/public void setPageSize(int pageSize) {this.pageSize = pageSize;}
}

4)PaginationPlugin

分页扩展。并且Example继承BaseExample

package run.override.pagination;import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.TopLevelClass;
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 run.override.mapper.SqlMapIsMergeablePlugin;
import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;public class PaginationPlugin extends SqlMapIsMergeablePlugin {@Overridepublic boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {FullyQualifiedJavaType baseExampleType = FullyQualifiedJavaTypeProxyFactory.getBaseExampleInstance();topLevelClass.setSuperClass(baseExampleType);topLevelClass.addImportedType(baseExampleType);return super.modelExampleClassGenerated(topLevelClass, introspectedTable);}@Overridepublic boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {XmlElement isNotNullElement1 = new XmlElement("if"); isNotNullElement1.addAttribute(new Attribute("test", "groupByClause != null")); isNotNullElement1.addElement(new TextElement("group by ${groupByClause}"));element.addElement(5, isNotNullElement1);XmlElement isNotNullElement = new XmlElement("if");isNotNullElement.addAttribute(new Attribute("test", "pageInfo != null")); isNotNullElement.addElement(new TextElement("limit #{pageInfo.pageBegin} , #{pageInfo.pageSize}"));element.addElement(isNotNullElement);return super.sqlMapUpdateByExampleWithBLOBsElementGenerated(element, introspectedTable);}@Overridepublic boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,IntrospectedTable introspectedTable) {XmlElement isNotNullElement1 = new XmlElement("if");isNotNullElement1.addAttribute(new Attribute("test", "groupByClause != null"));isNotNullElement1.addElement(new TextElement("group by ${groupByClause}"));element.addElement(5, isNotNullElement1);XmlElement isNotNullElement = new XmlElement("if"); isNotNullElement.addAttribute(new Attribute("test", "pageInfo != null"));isNotNullElement.addElement(new TextElement("limit #{pageInfo.pageBegin} , #{pageInfo.pageSize}"));element.addElement(isNotNullElement);return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);}@Overridepublic boolean sqlMapCountByExampleElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {XmlElement answer = new XmlElement("select");String fqjt = introspectedTable.getExampleType();answer.addAttribute(new Attribute("id", introspectedTable.getCountByExampleStatementId()));answer.addAttribute(new Attribute("parameterType", fqjt));answer.addAttribute(new Attribute("resultType", "java.lang.Integer"));this.context.getCommentGenerator().addComment(answer);StringBuilder sb = new StringBuilder();sb.append("select count(1) from ");sb.append(introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime());XmlElement ifElement = new XmlElement("if");ifElement.addAttribute(new Attribute("test", "_parameter != null"));XmlElement includeElement = new XmlElement("include");includeElement.addAttribute(new Attribute("refid", introspectedTable.getExampleWhereClauseId()));ifElement.addElement(includeElement);element.getElements().clear();element.getElements().add(new TextElement(sb.toString()));element.getElements().add(ifElement);return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);}
}

5)FullyQualifiedJavaTypeProxyFactory

package run.override.proxyFactory;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;public class FullyQualifiedJavaTypeProxyFactory  extends FullyQualifiedJavaType{private static FullyQualifiedJavaType pageInfoInstance = new FullyQualifiedJavaType("cn.xxx.core.base.model.PageInfo");private static FullyQualifiedJavaType baseExampleInstance = new FullyQualifiedJavaType("cn.xxx.core.base.model.BaseExample");private static FullyQualifiedJavaType baseMapperInstance = new FullyQualifiedJavaType("cn.xxx.core.base.dao.BaseMapper");private static FullyQualifiedJavaType baseServiceInstance = new FullyQualifiedJavaType("cn.xxx.core.base.service.BaseService");private static FullyQualifiedJavaType baseServiceImplInstance = new FullyQualifiedJavaType("cn.xxx.core.base.service.impl.BaseServiceImpl");public FullyQualifiedJavaTypeProxyFactory(String fullTypeSpecification) {super(fullTypeSpecification);}public static final FullyQualifiedJavaType getPageInfoInstanceInstance() {return pageInfoInstance;}public static final FullyQualifiedJavaType getBaseExampleInstance() {return baseExampleInstance;}public static final FullyQualifiedJavaType getBaseMapperInstance() {return baseMapperInstance;}public static final FullyQualifiedJavaType getBaseServiceInstance() {return baseServiceInstance;}public static final FullyQualifiedJavaType getBaseServiceImplInstance() {return baseServiceImplInstance;}
}

3、Dao 生成代码简化

1)ClientDaoPlugin

package run.override.dao;import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.JavaTypeResolver;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;import run.override.model.EntityCommentPlugin;
import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;/*** javaClient("XMLMAPPER") extended* * @ClassName ClientDaoPlugin* @Description Mapper.java* @author Marvis*/
public class ClientDaoPlugin extends EntityCommentPlugin {@Overridepublic boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass,IntrospectedTable introspectedTable) {JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();FullyQualifiedJavaType calculateJavaType = javaTypeResolver.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));FullyQualifiedJavaType superInterfaceType = new FullyQualifiedJavaType(new StringBuilder("BaseMapper<").append(introspectedTable.getBaseRecordType()).append(",").append(introspectedTable.getExampleType()).append(",").append(calculateJavaType.getShortName()).append(">").toString());FullyQualifiedJavaType baseMapperInstance = FullyQualifiedJavaTypeProxyFactory.getBaseMapperInstance();interfaze.addSuperInterface(superInterfaceType);interfaze.addImportedType(baseMapperInstance);List<Method> changeMethods = interfaze.getMethods().stream().filter(method -> method.getName().endsWith("WithBLOBs")|| method.getReturnType().toString().endsWith("WithBLOBs")|| Arrays.toString(method.getParameters().toArray()).contains("WithBLOBs")).collect(Collectors.toList());interfaze.getMethods().retainAll(changeMethods);if (changeMethods.isEmpty())interfaze.getImportedTypes().removeIf(javaType -> javaType.getFullyQualifiedName().equals("java.util.List")|| javaType.getFullyQualifiedName().equals("org.apache.ibatis.annotations.Param"));return super.clientGenerated(interfaze, topLevelClass, introspectedTable);}}

4、修正

重复生成时Mapper.xml不是覆盖原代码,而是对内容进行了追加。

1)SqlMapIsMergeablePlugin

package run.override.mapper;import org.mybatis.generator.api.GeneratedXmlFile;
import org.mybatis.generator.api.IntrospectedTable;
import run.override.dao.ClientDaoPlugin;public class SqlMapIsMergeablePlugin extends ClientDaoPlugin {@Overridepublic boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {//重新生成代码,xml内容覆盖sqlMap.setMergeable(false);return super.sqlMapGenerated(sqlMap, introspectedTable);}
}

5、序列化自定义扩展

增加Example的序列化,并增加@SuppressWarnings("serial")注解。

1)SerializablePlugin

package run.override;import java.util.List;
import java.util.Properties;import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.TopLevelClass;public class SerializablePlugin extends PluginAdapter {private FullyQualifiedJavaType serializable;private FullyQualifiedJavaType gwtSerializable;private boolean addGWTInterface;private boolean suppressJavaInterface;public SerializablePlugin() {this.serializable = new FullyQualifiedJavaType("java.io.Serializable");this.gwtSerializable = new FullyQualifiedJavaType("com.google.gwt.user.client.rpc.IsSerializable");}@Overridepublic void setProperties(Properties properties) {super.setProperties(properties);this.addGWTInterface = Boolean.valueOf(properties.getProperty("addGWTInterface")).booleanValue();this.suppressJavaInterface = Boolean.valueOf(properties.getProperty("suppressJavaInterface")).booleanValue();}@Overridepublic boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {makeSerializable(topLevelClass, introspectedTable);return true;}@Overridepublic boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {makeSerializable(topLevelClass, introspectedTable);return true;}@Overridepublic boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,IntrospectedTable introspectedTable) {makeSerializable(topLevelClass, introspectedTable);return true;}@Overridepublic boolean modelExampleClassGenerated(TopLevelClass topLevelClass,IntrospectedTable introspectedTable){makeSerializable(topLevelClass, introspectedTable);return true;}protected void makeSerializable(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {if (this.addGWTInterface) {topLevelClass.addImportedType(this.gwtSerializable);topLevelClass.addSuperInterface(this.gwtSerializable);}if (!(this.suppressJavaInterface)) {topLevelClass.addImportedType(this.serializable);topLevelClass.addSuperInterface(this.serializable);topLevelClass.addAnnotation("@SuppressWarnings(\"serial\")");}}/*** This plugin is always valid - no properties are required*/@Overridepublic boolean validate(List<String> warnings) {return true;}
}

6、服务层代码自定义生成

重写Context,ConfigurationParser,MyBatisGeneratorConfigurationParser, 增加服务层生成逻辑。

先对Service基类进行介绍。

1)BaseService

package cn.xxx.core.base.service;import java.util.List;import org.apache.ibatis.annotations.Param;import cn.xxx.core.base.model.BaseExample;
import cn.xxx.core.base.model.PageInfo;public interface BaseService<T, Example extends BaseExample, ID> {long countByExample(Example example);int deleteByExample(Example example);int deleteByPrimaryKey(ID id);int insert(T record);int insertSelective(T record);List<T> selectByExample(Example example);/*** return T object* @author Marvis* @date May 23, 2018 11:37:11 AM* @param example* @return*/T selectByCondition(Example example);/*** if pageInfo == null<p/>* then return result of selectByExample(example)* @author Marvis* @date Jul 13, 2017 5:24:35 PM* @param example* @param pageInfo* @return*/List<T> selectByPageExmple(Example example, PageInfo pageInfo);T selectByPrimaryKey(ID id);int updateByExampleSelective(@Param("record") T record, @Param("example") Example example);int updateByExample(@Param("record") T record, @Param("example") Example example);int updateByPrimaryKeySelective(T record);int updateByPrimaryKey(T record);
}

2)BaseServiceImpl

package cn.xxx.core.base.service.impl;import java.util.List;import cn.xxx.core.base.dao.BaseMapper;
import cn.xxx.core.base.model.BaseExample;
import cn.xxx.core.base.model.PageInfo;
import cn.xxx.core.base.service.BaseService;public abstract class BaseServiceImpl<T, Example extends BaseExample, ID> implements BaseService<T, Example, ID> {private BaseMapper<T, Example, ID> mapper;public void setMapper(BaseMapper<T, Example, ID> mapper) {this.mapper = mapper;}public long countByExample(Example example) {return mapper.countByExample(example);}@Overridepublic int deleteByExample(Example example) {return mapper.deleteByExample(example);}@Overridepublic int deleteByPrimaryKey(ID id) {return mapper.deleteByPrimaryKey(id);}@Overridepublic int insert(T record) {return mapper.insert(record);}@Overridepublic int insertSelective(T record) {return mapper.insertSelective(record);}@Overridepublic List<T> selectByExample(Example example) {return mapper.selectByExample(example);}@Overridepublic T selectByCondition(Example example) {List<T> datas = selectByExample(example);return datas != null && datas.size() == 0 ? null : datas.get(0);}@Overridepublic List<T> selectByPageExmple(Example example, PageInfo pageInfo) {if(pageInfo != null){example.setPageInfo(pageInfo);pageInfo.setPageParams(Long.valueOf(this.countByExample(example)).intValue());}return this.selectByExample(example);}@Overridepublic T selectByPrimaryKey(ID id) {return mapper.selectByPrimaryKey(id);}@Overridepublic int updateByExampleSelective(T record, Example example) {return mapper.updateByExampleSelective(record, example);}@Overridepublic int updateByExample(T record, Example example) {return mapper.updateByExample(record, example);}@Overridepublic int updateByPrimaryKeySelective(T record) {return mapper.updateByPrimaryKeySelective(record);}@Overridepublic int updateByPrimaryKey(T record) {return mapper.updateByPrimaryKey(record);}
}

3)ServiceLayerPlugin

package run.override.service;import org.mybatis.generator.api.GeneratedJavaFile;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.JavaTypeResolver;
import org.mybatis.generator.api.dom.java.CompilationUnit;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;
import run.override.pagination.PaginationPlugin;
import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;public class ServiceLayerPlugin extends PaginationPlugin {/*** 生成额外java文件*/@Overridepublic List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {ContextOverride context = (ContextOverride) introspectedTable.getContext();ServiceGeneratorConfiguration serviceGeneratorConfiguration;if ((serviceGeneratorConfiguration = context.getServiceGeneratorConfiguration()) == null)return null;String targetPackage = serviceGeneratorConfiguration.getTargetPackage();String targetProject = serviceGeneratorConfiguration.getTargetProject();String implementationPackage = serviceGeneratorConfiguration.getImplementationPackage();CompilationUnit addServiceInterface = addServiceInterface(introspectedTable, targetPackage);CompilationUnit addServiceImplClazz = addServiceImplClazz(introspectedTable, targetPackage,implementationPackage);GeneratedJavaFile gjfServiceInterface = new GeneratedJavaFile(addServiceInterface, targetProject,this.context.getProperty("javaFileEncoding"), this.context.getJavaFormatter());GeneratedJavaFile gjfServiceImplClazz = new GeneratedJavaFile(addServiceImplClazz, targetProject,this.context.getProperty("javaFileEncoding"), this.context.getJavaFormatter());List<GeneratedJavaFile> list = new ArrayList<>();list.add(gjfServiceInterface);list.add(gjfServiceImplClazz);return list;}protected CompilationUnit addServiceInterface(IntrospectedTable introspectedTable, String targetPackage) {String entityClazzType = introspectedTable.getBaseRecordType();String serviceSuperPackage = targetPackage;String entityExampleClazzType = introspectedTable.getExampleType();String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();FullyQualifiedJavaType calculateJavaType = javaTypeResolver.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));StringBuilder builder = new StringBuilder();FullyQualifiedJavaType superInterfaceType = new FullyQualifiedJavaType(builder.append("BaseService<").append(entityClazzType).append(",").append(entityExampleClazzType).append(",").append(calculateJavaType.getShortName()).append(">").toString());Interface serviceInterface = new Interface(builder.delete(0, builder.length()).append(serviceSuperPackage).append(".").append(domainObjectName).append("Service").toString());serviceInterface.addSuperInterface(superInterfaceType);serviceInterface.setVisibility(JavaVisibility.PUBLIC);FullyQualifiedJavaType baseServiceInstance = FullyQualifiedJavaTypeProxyFactory.getBaseServiceInstance();FullyQualifiedJavaType modelJavaType = new FullyQualifiedJavaType(entityClazzType);FullyQualifiedJavaType exampleJavaType = new FullyQualifiedJavaType(entityExampleClazzType);serviceInterface.addImportedType(baseServiceInstance);serviceInterface.addImportedType(modelJavaType);serviceInterface.addImportedType(exampleJavaType);serviceInterface.addFileCommentLine("/*** copyright (c) 2019 Marvis  ***/");this.additionalServiceMethods(introspectedTable, serviceInterface);return serviceInterface;}protected CompilationUnit addServiceImplClazz(IntrospectedTable introspectedTable, String targetPackage,String implementationPackage) {String entityClazzType = introspectedTable.getBaseRecordType();String serviceSuperPackage = targetPackage;String serviceImplSuperPackage = implementationPackage;String entityExampleClazzType = introspectedTable.getExampleType();String javaMapperType = introspectedTable.getMyBatis3JavaMapperType();String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();FullyQualifiedJavaType calculateJavaType = javaTypeResolver.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));StringBuilder builder = new StringBuilder();FullyQualifiedJavaType superClazzType = new FullyQualifiedJavaType(builder.append("BaseServiceImpl<").append(entityClazzType).append(",").append(entityExampleClazzType).append(",").append(calculateJavaType.getShortName()).append(">").toString());FullyQualifiedJavaType implInterfaceType = new FullyQualifiedJavaType(builder.delete(0, builder.length()).append(serviceSuperPackage).append(".").append(domainObjectName).append("Service").toString());TopLevelClass serviceImplClazz = new TopLevelClass(builder.delete(0, builder.length()).append(serviceImplSuperPackage).append(".").append(domainObjectName).append("ServiceImpl").toString());serviceImplClazz.addSuperInterface(implInterfaceType);serviceImplClazz.setSuperClass(superClazzType);serviceImplClazz.setVisibility(JavaVisibility.PUBLIC);serviceImplClazz.addAnnotation("@Service");FullyQualifiedJavaType baseServiceInstance = FullyQualifiedJavaTypeProxyFactory.getBaseServiceImplInstance();FullyQualifiedJavaType modelJavaType = new FullyQualifiedJavaType(entityClazzType);FullyQualifiedJavaType exampleJavaType = new FullyQualifiedJavaType(entityExampleClazzType);serviceImplClazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));serviceImplClazz.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));serviceImplClazz.addImportedType(baseServiceInstance);serviceImplClazz.addImportedType(modelJavaType);serviceImplClazz.addImportedType(exampleJavaType);serviceImplClazz.addImportedType(implInterfaceType);FullyQualifiedJavaType logType = new FullyQualifiedJavaType("org.slf4j.Logger");FullyQualifiedJavaType logFactoryType = new FullyQualifiedJavaType("org.slf4j.LoggerFactory");Field logField = new Field();logField.setVisibility(JavaVisibility.PRIVATE);logField.setStatic(true);logField.setFinal(true);logField.setType(logType);logField.setName("logger");logField.setInitializationString(builder.delete(0, builder.length()).append("LoggerFactory.getLogger(").append(domainObjectName).append("ServiceImpl.class)").toString());logField.addAnnotation("");logField.addAnnotation("@SuppressWarnings(\"unused\")");serviceImplClazz.addField(logField);serviceImplClazz.addImportedType(logType);serviceImplClazz.addImportedType(logFactoryType);String mapperName = builder.delete(0, builder.length()).append(Character.toLowerCase(domainObjectName.charAt(0))).append(domainObjectName.substring(1)).append("Mapper").toString();FullyQualifiedJavaType JavaMapperType = new FullyQualifiedJavaType(javaMapperType);Field mapperField = new Field();mapperField.setVisibility(JavaVisibility.PUBLIC);mapperField.setType(JavaMapperType);// Mapper.javamapperField.setName(mapperName);mapperField.addAnnotation("@Autowired");serviceImplClazz.addField(mapperField);serviceImplClazz.addImportedType(JavaMapperType);Method mapperMethod = new Method();mapperMethod.setVisibility(JavaVisibility.PUBLIC);mapperMethod.setName("setMapper");mapperMethod.addBodyLine("super.setMapper(" + mapperName + ");");mapperMethod.addAnnotation("@Autowired");serviceImplClazz.addMethod(mapperMethod);serviceImplClazz.addFileCommentLine("/*** copyright (c) 2019 Marvis  ***/");serviceImplClazz.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));this.additionalServiceImplMethods(introspectedTable, serviceImplClazz, mapperName);return serviceImplClazz;}protected void additionalServiceMethods(IntrospectedTable introspectedTable, Interface serviceInterface) {if (this.notHasBLOBColumns(introspectedTable))return;introspectedTable.getGeneratedJavaFiles().stream().filter(file -> file.getCompilationUnit().isJavaInterface()&& file.getCompilationUnit().getType().getShortName().endsWith("Mapper")).map(GeneratedJavaFile::getCompilationUnit).forEach(compilationUnit -> ((Interface) compilationUnit).getMethods().forEach(m -> serviceInterface.addMethod(this.additionalServiceLayerMethod(serviceInterface, m))));}protected void additionalServiceImplMethods(IntrospectedTable introspectedTable, TopLevelClass clazz,String mapperName) {if (this.notHasBLOBColumns(introspectedTable))return;introspectedTable.getGeneratedJavaFiles().stream().filter(file -> file.getCompilationUnit().isJavaInterface()&& file.getCompilationUnit().getType().getShortName().endsWith("Mapper")).map(GeneratedJavaFile::getCompilationUnit).forEach(compilationUnit -> ((Interface) compilationUnit).getMethods().forEach(m -> {Method serviceImplMethod = this.additionalServiceLayerMethod(clazz, m);serviceImplMethod.addAnnotation("@Override");serviceImplMethod.addBodyLine(this.generateBodyForServiceImplMethod(mapperName, m));clazz.addMethod(serviceImplMethod);}));}private boolean notHasBLOBColumns(IntrospectedTable introspectedTable) {return !introspectedTable.hasBLOBColumns();}private Method additionalServiceLayerMethod(CompilationUnit compilation, Method m) {Method method = new Method();method.setVisibility(JavaVisibility.PUBLIC);method.setName(m.getName());List<Parameter> parameters = m.getParameters();method.getParameters().addAll(parameters.stream().peek(param -> param.getAnnotations().clear()).collect(Collectors.toList()));method.setReturnType(m.getReturnType());compilation.addImportedType(new FullyQualifiedJavaType(m.getReturnType().getFullyQualifiedNameWithoutTypeParameters()));return method;}private String generateBodyForServiceImplMethod(String mapperName, Method m) {StringBuilder sbf = new StringBuilder("return ");sbf.append(mapperName).append(".").append(m.getName()).append("(");boolean singleParam = true;for (Parameter parameter : m.getParameters()) {if (singleParam)singleParam = !singleParam;elsesbf.append(", ");sbf.append(parameter.getName());}sbf.append(");");return sbf.toString();}}

4)ContextOverride

package run.override.service;import java.util.List;import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.ModelType;public class ContextOverride extends Context{//添加ServiceGeneratorConfigurationprivate ServiceGeneratorConfiguration serviceGeneratorConfiguration;public ContextOverride(ModelType defaultModelType) {super(defaultModelType);}public ServiceGeneratorConfiguration getServiceGeneratorConfiguration() {return serviceGeneratorConfiguration;}public void setServiceGeneratorConfiguration(ServiceGeneratorConfiguration serviceGeneratorConfiguration) {this.serviceGeneratorConfiguration = serviceGeneratorConfiguration;}@Overridepublic void validate(List<String> errors) {if(serviceGeneratorConfiguration != null)serviceGeneratorConfiguration.validate(errors, this.getId());super.validate(errors);}public XmlElement toXmlElement() {XmlElement xmlElement = super.toXmlElement();if (serviceGeneratorConfiguration != null)xmlElement.addElement(serviceGeneratorConfiguration.toXmlElement());return xmlElement;}
}

5)MyBatisGeneratorConfigurationParserOverride

package run.override.service;import java.util.Properties;import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.Context;
import org.mybatis.generator.config.JavaClientGeneratorConfiguration;
import org.mybatis.generator.config.ModelType;
import org.mybatis.generator.config.PluginConfiguration;
import org.mybatis.generator.config.xml.MyBatisGeneratorConfigurationParser;
import org.mybatis.generator.exception.XMLParserException;
import org.mybatis.generator.internal.util.StringUtility;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;public class MyBatisGeneratorConfigurationParserOverride extends MyBatisGeneratorConfigurationParser {public MyBatisGeneratorConfigurationParserOverride(Properties extraProperties) {super(extraProperties);}private void parseJavaServiceGenerator(Context context, Node node) {ContextOverride contextOverride = ContextOverride.class.cast(context); 替换ContextServiceGeneratorConfiguration serviceGeneratorConfiguration = new ServiceGeneratorConfiguration();contextOverride.setServiceGeneratorConfiguration(serviceGeneratorConfiguration);Properties attributes = parseAttributes(node);String targetPackage = attributes.getProperty("targetPackage");String targetProject = attributes.getProperty("targetProject");String implementationPackage = attributes.getProperty("implementationPackage");serviceGeneratorConfiguration.setTargetPackage(targetPackage);serviceGeneratorConfiguration.setTargetProject(targetProject);serviceGeneratorConfiguration.setImplementationPackage(implementationPackage);NodeList nodeList = node.getChildNodes();for (int i = 0; i < nodeList.getLength(); i++) {Node childNode = nodeList.item(i);if (childNode.getNodeType() == Node.ELEMENT_NODE && "property".equals(childNode.getNodeName()))parseProperty(serviceGeneratorConfiguration, childNode);}}@Overridepublic Configuration parseConfiguration(Element rootNode) throws XMLParserException {Configuration configuration = new Configuration();NodeList nodeList = rootNode.getChildNodes();for (int i = 0; i < nodeList.getLength(); ++i) {Node childNode = nodeList.item(i);if (childNode.getNodeType() != 1) {continue;}if ("properties".equals(childNode.getNodeName()))parseProperties(configuration, childNode);else if ("classPathEntry".equals(childNode.getNodeName()))parseClassPathEntry(configuration, childNode);else if ("context".equals(childNode.getNodeName())) {parseContext(configuration, childNode);}}return configuration;}private void parseContext(Configuration configuration, Node node) {Properties attributes = parseAttributes(node);String defaultModelType = attributes.getProperty("defaultModelType");String targetRuntime = attributes.getProperty("targetRuntime");String introspectedColumnImpl = attributes.getProperty("introspectedColumnImpl");String id = attributes.getProperty("id");ModelType mt = defaultModelType != null ? ModelType.getModelType(defaultModelType) : null;Context context = new ContextOverride(mt);context.setId(id);if (StringUtility.stringHasValue(introspectedColumnImpl))context.setIntrospectedColumnImpl(introspectedColumnImpl);if (StringUtility.stringHasValue(targetRuntime))context.setTargetRuntime(targetRuntime);configuration.addContext(context);NodeList nodeList = node.getChildNodes();for (int i = 0; i < nodeList.getLength(); i++) {Node childNode = nodeList.item(i);if (childNode.getNodeType() != 1)continue;if ("property".equals(childNode.getNodeName())) {parseProperty(context, childNode);continue;}if ("plugin".equals(childNode.getNodeName())) {parsePlugin(context, childNode);continue;}if ("commentGenerator".equals(childNode.getNodeName())) {parseCommentGenerator(context, childNode);continue;}if ("jdbcConnection".equals(childNode.getNodeName())) {parseJdbcConnection(context, childNode);continue;}if ("connectionFactory".equals(childNode.getNodeName())) {parseConnectionFactory(context, childNode);continue;}if ("javaModelGenerator".equals(childNode.getNodeName())) {parseJavaModelGenerator(context, childNode);continue;}if ("javaTypeResolver".equals(childNode.getNodeName())) {parseJavaTypeResolver(context, childNode);continue;}if ("sqlMapGenerator".equals(childNode.getNodeName())) {parseSqlMapGenerator(context, childNode);continue;}if ("javaClientGenerator".equals(childNode.getNodeName())) {parseJavaClientGenerator(context, childNode);continue;}if ("javaServiceGenerator".equals(childNode.getNodeName())) {parseJavaServiceGenerator(context, childNode);continue;}if ("table".equals(childNode.getNodeName()))parseTable(context, childNode);}}private void parsePlugin(Context context, Node node) {PluginConfiguration pluginConfiguration = new PluginConfiguration();context.addPluginConfiguration(pluginConfiguration);Properties attributes = parseAttributes(node);String type = attributes.getProperty("type");pluginConfiguration.setConfigurationType(type);NodeList nodeList = node.getChildNodes();for (int i = 0; i < nodeList.getLength(); i++) {Node childNode = nodeList.item(i);if (childNode.getNodeType() == 1 && "property".equals(childNode.getNodeName()))parseProperty(pluginConfiguration, childNode);}}private void parseJavaClientGenerator(Context context, Node node) {JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);Properties attributes = parseAttributes(node);String type = attributes.getProperty("type");String targetPackage = attributes.getProperty("targetPackage");String targetProject = attributes.getProperty("targetProject");String implementationPackage = attributes.getProperty("implementationPackage");javaClientGeneratorConfiguration.setConfigurationType(type);javaClientGeneratorConfiguration.setTargetPackage(targetPackage);javaClientGeneratorConfiguration.setTargetProject(targetProject);javaClientGeneratorConfiguration.setImplementationPackage(implementationPackage);NodeList nodeList = node.getChildNodes();for (int i = 0; i < nodeList.getLength(); i++) {Node childNode = nodeList.item(i);if (childNode.getNodeType() == 1 && "property".equals(childNode.getNodeName()))parseProperty(javaClientGeneratorConfiguration, childNode);}}
}

6)ServiceGeneratorConfiguration

package run.override.service;import java.util.List;import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.config.PropertyHolder;
import org.mybatis.generator.internal.util.StringUtility;
import org.mybatis.generator.internal.util.messages.Messages;public class ServiceGeneratorConfiguration extends PropertyHolder {private String targetPackage;private String implementationPackage;private String targetProject;/****/public ServiceGeneratorConfiguration() {super();}public String getTargetPackage() {return targetPackage;}public void setTargetPackage(String targetPackage) {this.targetPackage = targetPackage;}public String getImplementationPackage() {return implementationPackage;}public void setImplementationPackage(String implementationPackage) {this.implementationPackage = implementationPackage;}public String getTargetProject() {return targetProject;}public void setTargetProject(String targetProject) {this.targetProject = targetProject;}public XmlElement toXmlElement() {XmlElement answer = new XmlElement("javaServiceGenerator"); if (targetPackage != null) {answer.addAttribute(new Attribute("targetPackage", targetPackage)); }if (implementationPackage != null) {answer.addAttribute(new Attribute("implementationPackage", targetPackage)); }if (targetProject != null) {answer.addAttribute(new Attribute("targetProject", targetProject)); }addPropertyXmlElements(answer);return answer;}@SuppressWarnings({ "rawtypes", "unchecked" })public void validate(List errors, String contextId) {if (!StringUtility.stringHasValue(getTargetProject()))errors.add(Messages.getString("ValidationError.102", contextId));if (!StringUtility.stringHasValue(getTargetPackage()))errors.add(Messages.getString("ValidationError.112", "ServiceGenerator", contextId));if (!StringUtility.stringHasValue(getImplementationPackage()))errors.add(Messages.getString("ValidationError.120", contextId));}}

7)ConfigurationParserOverride:

package run.override.service;import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.config.xml.ConfigurationParser;
import org.mybatis.generator.config.xml.MyBatisGeneratorConfigurationParser;
import org.mybatis.generator.config.xml.ParserEntityResolver;
import org.mybatis.generator.config.xml.ParserErrorHandler;
import org.mybatis.generator.exception.XMLParserException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;public class ConfigurationParserOverride extends ConfigurationParser {private List<String> warnings;private List<String> parseErrors;private Properties extraProperties;public ConfigurationParserOverride(List<String> warnings) {this(null, warnings);}public ConfigurationParserOverride(Properties extraProperties, List<String> warnings) {super(extraProperties, warnings);this.extraProperties = extraProperties;if (warnings == null)this.warnings = new ArrayList<>();else {this.warnings = warnings;}this.parseErrors = new ArrayList<>();}@Overridepublic Configuration parseConfiguration(File inputFile) throws IOException, XMLParserException {FileReader fr = new FileReader(inputFile);return parseConfiguration(fr);}@Overridepublic Configuration parseConfiguration(InputStream inputStream) throws IOException, XMLParserException {InputSource is = new InputSource(inputStream);return parseConfiguration(is);}@Overridepublic Configuration parseConfiguration(Reader reader) throws IOException, XMLParserException {InputSource is = new InputSource(reader);return parseConfiguration(is);}private Configuration parseConfiguration(InputSource inputSource) throws IOException, XMLParserException {this.parseErrors.clear();DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();factory.setValidating(true);try {DocumentBuilder builder = factory.newDocumentBuilder();builder.setEntityResolver(new ParserEntityResolver());ParserErrorHandler handler = new ParserErrorHandler(this.warnings, this.parseErrors);builder.setErrorHandler(handler);Document document = null;try {document = builder.parse(inputSource);} catch (SAXParseException e) {throw new XMLParserException(this.parseErrors);} catch (SAXException e) {if (e.getException() == null)this.parseErrors.add(e.getMessage());else {this.parseErrors.add(e.getException().getMessage());}}if (this.parseErrors.size() > 0) {throw new XMLParserException(this.parseErrors);}Element rootNode = document.getDocumentElement();Configuration config = parseMyBatisGeneratorConfiguration(rootNode);if (this.parseErrors.size() > 0) {throw new XMLParserException(this.parseErrors);}return config;} catch (ParserConfigurationException e) {this.parseErrors.add(e.getMessage());throw new XMLParserException(this.parseErrors);}}private Configuration parseMyBatisGeneratorConfiguration(Element rootNode) throws XMLParserException {//替换MyBatisGeneratorConfigurationParserMyBatisGeneratorConfigurationParser parser = new MyBatisGeneratorConfigurationParserOverride(this.extraProperties);return parser.parseConfiguration(rootNode);}}

7、PluginChain

通过继承,把以上扩展Plugin串起来(SerializablePlugin一些项目中可能不需要,故不加入Chain。同时,其他也可以根据需要对Chain进行更改)。

package run.override;import run.override.service.ServiceLayerPlugin;
public class PluginChain extends ServiceLayerPlugin {}

8、generatorConfig.xml

增加javaServiceGenerator相关配置标签。本文使用内部DTD做示例,亦可通过外部DTD或xsd来实现。

1)generatorConfig.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 内部DTD 亦可通过外部DTD来实现-->
<!DOCTYPE generatorConfiguration[
<!ELEMENT generatorConfiguration (properties?, classPathEntry*, context+)><!ELEMENT properties EMPTY>
<!ATTLIST propertiesresource CDATA #IMPLIEDurl CDATA #IMPLIED>
<!--括号里是声明出现的次序:*: 出现任意次,包括0次?: 出现最多一次|:选择之一+: 出现最少1次如果没有上述符号:必须且只能出现一次-->
<!ELEMENT context (property*, plugin*, commentGenerator?, (connectionFactory | jdbcConnection), javaTypeResolver?,javaModelGenerator, sqlMapGenerator, javaClientGenerator, javaServiceGenerator,table+)>
<!ATTLIST context id ID #REQUIREDdefaultModelType CDATA #IMPLIEDtargetRuntime CDATA #IMPLIEDintrospectedColumnImpl CDATA #IMPLIED><!ELEMENT connectionFactory (property*)>
<!ATTLIST connectionFactorytype CDATA #IMPLIED><!ELEMENT jdbcConnection (property*)>
<!ATTLIST jdbcConnection driverClass CDATA #REQUIREDconnectionURL CDATA #REQUIREDuserId CDATA #IMPLIEDpassword CDATA #IMPLIED><!ELEMENT classPathEntry EMPTY>
<!ATTLIST classPathEntrylocation CDATA #REQUIRED><!ELEMENT property EMPTY>
<!ATTLIST propertyname CDATA #REQUIREDvalue CDATA #REQUIRED><!ELEMENT plugin (property*)>
<!ATTLIST plugintype CDATA #REQUIRED><!ELEMENT javaModelGenerator (property*)>
<!ATTLIST javaModelGeneratortargetPackage CDATA #REQUIREDtargetProject CDATA #REQUIRED><!ELEMENT javaTypeResolver (property*)>
<!ATTLIST javaTypeResolvertype CDATA #IMPLIED><!ELEMENT sqlMapGenerator (property*)>
<!ATTLIST sqlMapGeneratortargetPackage CDATA #REQUIREDtargetProject CDATA #REQUIRED><!ELEMENT javaClientGenerator (property*)>
<!ATTLIST javaClientGeneratortype CDATA #REQUIREDtargetPackage CDATA #REQUIREDtargetProject CDATA #REQUIREDimplementationPackage CDATA #IMPLIED><!ELEMENT javaServiceGenerator (property*)>
<!ATTLIST javaServiceGeneratortargetPackage CDATA #REQUIREDimplementationPackage CDATA #REQUIREDtargetProject CDATA #REQUIRED><!ELEMENT table (property*, generatedKey?, domainObjectRenamingRule?, columnRenamingRule?, (columnOverride | ignoreColumn | ignoreColumnsByRegex)*) >
<!ATTLIST tablecatalog CDATA #IMPLIEDschema CDATA #IMPLIEDtableName CDATA #REQUIREDalias CDATA #IMPLIEDdomainObjectName CDATA #IMPLIEDmapperName CDATA #IMPLIEDsqlProviderName CDATA #IMPLIEDenableInsert CDATA #IMPLIEDenableSelectByPrimaryKey CDATA #IMPLIEDenableSelectByExample CDATA #IMPLIEDenableUpdateByPrimaryKey CDATA #IMPLIEDenableDeleteByPrimaryKey CDATA #IMPLIEDenableDeleteByExample CDATA #IMPLIEDenableCountByExample CDATA #IMPLIEDenableUpdateByExample CDATA #IMPLIEDselectByPrimaryKeyQueryId CDATA #IMPLIEDselectByExampleQueryId CDATA #IMPLIEDmodelType CDATA #IMPLIEDescapeWildcards CDATA #IMPLIEDdelimitIdentifiers CDATA #IMPLIEDdelimitAllColumns CDATA #IMPLIED><!ELEMENT columnOverride (property*)>
<!ATTLIST columnOverridecolumn CDATA #REQUIREDproperty CDATA #IMPLIEDjavaType CDATA #IMPLIEDjdbcType CDATA #IMPLIEDtypeHandler CDATA #IMPLIEDisGeneratedAlways CDATA #IMPLIEDdelimitedColumnName CDATA #IMPLIED><!ELEMENT ignoreColumn EMPTY>
<!ATTLIST ignoreColumncolumn CDATA #REQUIREDdelimitedColumnName CDATA #IMPLIED><!ELEMENT ignoreColumnsByRegex (except*)>
<!ATTLIST ignoreColumnsByRegexpattern CDATA #REQUIRED><!ELEMENT except EMPTY>
<!ATTLIST exceptcolumn CDATA #REQUIREDdelimitedColumnName CDATA #IMPLIED><!ELEMENT generatedKey EMPTY>
<!ATTLIST generatedKeycolumn CDATA #REQUIREDsqlStatement CDATA #REQUIREDidentity CDATA #IMPLIEDtype CDATA #IMPLIED><!ELEMENT domainObjectRenamingRule EMPTY>
<!ATTLIST domainObjectRenamingRulesearchString CDATA #REQUIREDreplaceString CDATA #IMPLIED><!ELEMENT columnRenamingRule EMPTY>
<!ATTLIST columnRenamingRulesearchString CDATA #REQUIREDreplaceString CDATA #IMPLIED><!ELEMENT commentGenerator (property*)>
<!ATTLIST commentGeneratortype CDATA #IMPLIED>]><generatorConfiguration> <context id="ables" targetRuntime="MyBatis3"><!--添加Plugin--><plugin type="run.override.PluginChain" /><plugin type="run.override.SerializablePlugin" /><plugin type="org.mybatis.generator.plugins.ToStringPlugin" /><commentGenerator type="run.override.CommentGenerator"/><jdbcConnection driverClass="com.mysql.jdbc.Driver"connectionURL="jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxx?characterEncoding=utf8"userId="xxx" password="xxx"></jdbcConnection><javaTypeResolver><property name="forceBigDecimals" value="false" /></javaTypeResolver><javaModelGenerator targetPackage="cn.xxx.elecsign.model" targetProject=".\src"><property name="enableSubPackages" value="false" /><property name="trimStrings" value="true" /></javaModelGenerator><sqlMapGenerator targetPackage="mapper.cn.xxx.elecsign.dao" targetProject=".\src"><property name="enableSubPackages" value="false" /></sqlMapGenerator><javaClientGenerator type="XMLMAPPER" targetPackage="cn.xxx.elecsign.dao" targetProject=".\src"><property name="enableSubPackages" value="false" /></javaClientGenerator><!-- javaServiceGenerator  --><javaServiceGenerator  targetPackage="cn.xxx.elecsign.dly.service" implementationPackage = "cn.xxx.elecsign.dly.service.impl" targetProject=".\src"><property name="enableSubPackages" value="false" /></javaServiceGenerator><!-- 批次表,针对批量的异步操作 --><table tableName="table" domainObjectName="Table" alias="table"><generatedKey column="id" sqlStatement="MySql" identity="true" /></table></context>
</generatorConfiguration>

9、main启动

 package run.generator;import java.io.File;
import java.util.ArrayList;
import java.util.List;import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.Configuration;
import org.mybatis.generator.internal.DefaultShellCallback;import run.override.service.ConfigurationParserOverride;public class Generator {public void generator() throws Exception{List<String> warnings = new ArrayList<String>();boolean overwrite = true;File configFile = new File("generatorConfig.xml"); //替换ConfigurationParserConfigurationParserOverride cp = new ConfigurationParserOverride(warnings);Configuration config = cp.parseConfiguration(configFile);DefaultShellCallback callback = new DefaultShellCallback(overwrite);MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);myBatisGenerator.generate(null);} public static void main(String[] args) throws Exception {try {Generator generator = new Generator();generator.generator();} catch (Exception e) {e.printStackTrace();}}}

至此,对Mybatis-generator的扩展生成代码完成。

作者:马伟伟

来源:宜信技术学院

代码演示Mybatis-Generator 扩展自定义生成相关推荐

  1. idea mybaits逆向工程_IDEA 中集成 MyBatis Generator 组件逆向生成工程

    IDEA 逆向 MyBatis 工程时,不像支持 Hibernate 那样有自带插件,需要集成第三方的 MyBatis Generator. MyBatis Generator的详细介绍 http:/ ...

  2. mybatis generator修改默认生成的sql模板

    相关连接: mybatis-generator扩展教程系列 -- 自定义sql xml文件 git项目地址 转载于:https://www.cnblogs.com/hujunzheng/p/71105 ...

  3. SpringBoot如何自动生成实体类和Dao层以及映射文件(mybatis generator 自动生成代码)

    一.首先添加自动生成代码插件 <!-- mybatis generator 自动生成代码插件 生成时解除注释 --><plugin><groupId>org.myb ...

  4. MyBatis Generator 代码自动生成器,从此解放你的双手

    前言 在日常开发工作中,我们往往需要自己去构建各种数据表所对应的持久化对象(PO).用于操作数据库的接口(DAO)以及跟 DAO 所绑定的对应 XML.这都是一些重复性的操作,不需要多大技术含量,这时 ...

  5. 使用MyBatis Generator自动生成实体、mapper和dao层

    原文链接 通过MyBatis Generator可以自动生成实体.mapper和dao层,记录一下怎么用的. 主要步骤: 关于mybatis从数据库反向生成实体.DAO.mapper: 参考文章:ht ...

  6. 图解 IDEA 中 springboot 项目 MyBatis Generator 逆向生成实体类及 mapper 配置文件

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 一.准备工作: 1. 新建一个 配置文件:generatorConfig.xml . <?xm ...

  7. Mybatis Generator生成工具使用

    一.创建数据库以及表t_user 二.引入依赖 <dependency><groupId>org.mybatis.generator</groupId><ar ...

  8. Mybatis Generator 自动生成数据库XML(Mybatis Generator 逆向工程)

    Mybatis Generator 逆向工程自动生成XML 1.MyBatis Generator简单介绍: (1)MyBatis Generator 会生成: Dao,Model,Mapping基础 ...

  9. MyBatis Generator 详解

    MyBatis Generator中文文档 MyBatis Generator中文文档地址: http://mbg.cndocs.tk/ 该中文文档由于尽可能和原文内容一致,所以有些地方如果不熟悉,看 ...

最新文章

  1. (转载)从无知到有知
  2. 单片机c语言第三版答案,单片机C语言应用程序设计马忠梅课后习题答案
  3. Android 改变AlertDialog的大小
  4. python 函数参数类型检查
  5. java 连接不上hbase_无法远程连接到Hbase
  6. Axure快速原型教程02--创建页面和设置界面
  7. 2019如何新建流程图_用Word制作流程图,居然还有这么多小技巧
  8. FPGA智能传感系统(一)Verilog基础入门
  9. Julia: 关于下载库时WinRPM的Bug
  10. python量化投资19种方法_【Python量化投资】新手资源大合集
  11. 用VMware克隆CentOS 6.4后HWaddr和UUID的设置
  12. php获取本机内网ip地址
  13. ts中类型检测的鸭子类型是什么意思
  14. 文件服务器均衡负载,文件服务器均衡负载
  15. matlab中cell元胞到底怎么理解
  16. 家庭财务管理系统(C++面向对象课程设计附课设报告)
  17. 图片去底色,图片透明化,免费简单快捷 [ 没有比这更好用的了 ]
  18. VSCode下载慢的问题解决
  19. matlab偏分赋值错误,MATLAB ode45求解高阶微分方程组,出现“无法执行赋值,因为左侧和右侧的元素数目不同”问题...
  20. 好看的渐变色网址收藏

热门文章

  1. 2021 回头看看这一年
  2. 【机器学习和数据分析与可视化课程设计】基于天气预报的数据分析与可视化课程设计(Python实现)
  3. 使用convert命令将pdf转成图片时遇到的一个问题
  4. 持久化存储-MySql拓展
  5. Windows程序设计 读书笔记(3)
  6. qt程序打包(5) linux(UOS)应用程序图标以及 文件关联应用程序
  7. 前往美孚主义2013
  8. JPA的@Query用法
  9. 详解百度指数搜索指数js逆向
  10. 数控机床联网知识普及