代码演示Mybatis-Generator 扩展自定义生成

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 {                @Override      public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {          addModelClassComment(topLevelClass, introspectedTable);          return super.modelBaseRecordClassGenerated(topLevelClass, introspectedTable);      }        @Override      public 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       */      @Override      public 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);      }        @Override      public 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;      }        @JsonIgnore      public int getPageBegin() {          return pageBegin;      }        @JsonIgnore      public int getPageEnd() {          return pageEnd;      }        /**       * bean起始id(不包含)       */      @JsonIgnore      public 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 {      @Override      public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {            FullyQualifiedJavaType baseExampleType = FullyQualifiedJavaTypeProxyFactory.getBaseExampleInstance();          topLevelClass.setSuperClass(baseExampleType);                    topLevelClass.addImportedType(baseExampleType);          return super.modelExampleClassGenerated(topLevelClass, introspectedTable);      }            @Override      public 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);      }        @Override      public 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);      }        @Override      public 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 {        @Override      public 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 {        @Override      public 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");      }        @Override      public void setProperties(Properties properties) {          super.setProperties(properties);          this.addGWTInterface = Boolean.valueOf(properties.getProperty("addGWTInterface")).booleanValue();          this.suppressJavaInterface = Boolean.valueOf(properties.getProperty("suppressJavaInterface")).booleanValue();      }      @Override      public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {          makeSerializable(topLevelClass, introspectedTable);          return true;      }      @Override      public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {          makeSerializable(topLevelClass, introspectedTable);          return true;      }      @Override      public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,              IntrospectedTable introspectedTable) {          makeSerializable(topLevelClass, introspectedTable);          return true;      }            @Override      public 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       */      @Override      public 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);      }        @Override      public int deleteByExample(Example example) {          return mapper.deleteByExample(example);      }        @Override      public int deleteByPrimaryKey(ID id) {          return mapper.deleteByPrimaryKey(id);      }        @Override      public int insert(T record) {          return mapper.insert(record);      }        @Override      public int insertSelective(T record) {          return mapper.insertSelective(record);      }        @Override      public List<T> selectByExample(Example example) {          return mapper.selectByExample(example);      }      @Override      public T selectByCondition(Example example) {                    List<T> datas = selectByExample(example);          return datas != null && datas.size() == 0 ? null : datas.get(0);      }        @Override      public 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);      }        @Override      public T selectByPrimaryKey(ID id) {          return mapper.selectByPrimaryKey(id);      }        @Override      public int updateByExampleSelective(T record, Example example) {          return mapper.updateByExampleSelective(record, example);      }        @Override      public int updateByExample(T record, Example example) {          return mapper.updateByExample(record, example);      }        @Override      public int updateByPrimaryKeySelective(T record) {          return mapper.updateByPrimaryKeySelective(record);      }        @Override      public 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文件       */      @Override      public 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.java          mapperField.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;              else                  sbf.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{      //添加ServiceGeneratorConfiguration      private ServiceGeneratorConfiguration serviceGeneratorConfiguration;        public ContextOverride(ModelType defaultModelType) {          super(defaultModelType);      }        public ServiceGeneratorConfiguration getServiceGeneratorConfiguration() {          return serviceGeneratorConfiguration;      }        public void setServiceGeneratorConfiguration(ServiceGeneratorConfiguration serviceGeneratorConfiguration) {          this.serviceGeneratorConfiguration = serviceGeneratorConfiguration;      }        @Override      public 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); ////替换Context            ServiceGeneratorConfiguration 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);          }        }        @Override      public 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<>();      }        @Override      public Configuration parseConfiguration(File inputFile) throws IOException, XMLParserException {          FileReader fr = new FileReader(inputFile);            return parseConfiguration(fr);      }            @Override      public Configuration parseConfiguration(InputStream inputStream) throws IOException, XMLParserException {          InputSource is = new InputSource(inputStream);            return parseConfiguration(is);      }        @Override      public 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 {                    //替换MyBatisGeneratorConfigurationParser          MyBatisGeneratorConfigurationParser 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 properties    resource CDATA #IMPLIED    url CDATA #IMPLIED>  <!--      括号里是声明出现的次序:      *: 出现任意次,包括0次      ?: 出现最多一次      |:选择之一      +: 出现最少1次      如果没有上述符号:必须且只能出现一次   -->  <!ELEMENT context (property*, plugin*, commentGenerator?, (connectionFactory | jdbcConnection), javaTypeResolver?,                           javaModelGenerator, sqlMapGenerator, javaClientGenerator, javaServiceGenerator,table+)>  <!ATTLIST context id ID #REQUIRED    defaultModelType CDATA #IMPLIED    targetRuntime CDATA #IMPLIED    introspectedColumnImpl CDATA #IMPLIED>    <!ELEMENT connectionFactory (property*)>  <!ATTLIST connectionFactory    type CDATA #IMPLIED>    <!ELEMENT jdbcConnection (property*)>  <!ATTLIST jdbcConnection     driverClass CDATA #REQUIRED    connectionURL CDATA #REQUIRED    userId CDATA #IMPLIED    password CDATA #IMPLIED>    <!ELEMENT classPathEntry EMPTY>  <!ATTLIST classPathEntry    location CDATA #REQUIRED>    <!ELEMENT property EMPTY>  <!ATTLIST property    name CDATA #REQUIRED    value CDATA #REQUIRED>    <!ELEMENT plugin (property*)>  <!ATTLIST plugin    type CDATA #REQUIRED>    <!ELEMENT javaModelGenerator (property*)>  <!ATTLIST javaModelGenerator    targetPackage CDATA #REQUIRED    targetProject CDATA #REQUIRED>    <!ELEMENT javaTypeResolver (property*)>  <!ATTLIST javaTypeResolver    type CDATA #IMPLIED>    <!ELEMENT sqlMapGenerator (property*)>  <!ATTLIST sqlMapGenerator    targetPackage CDATA #REQUIRED    targetProject CDATA #REQUIRED>    <!ELEMENT javaClientGenerator (property*)>  <!ATTLIST javaClientGenerator    type CDATA #REQUIRED    targetPackage CDATA #REQUIRED    targetProject CDATA #REQUIRED    implementationPackage CDATA #IMPLIED>      <!ELEMENT javaServiceGenerator (property*)>  <!ATTLIST javaServiceGenerator          targetPackage CDATA #REQUIRED          implementationPackage CDATA #REQUIRED          targetProject CDATA #REQUIRED>            <!ELEMENT table (property*, generatedKey?, domainObjectRenamingRule?, columnRenamingRule?, (columnOverride | ignoreColumn | ignoreColumnsByRegex)*) >  <!ATTLIST table    catalog CDATA #IMPLIED    schema CDATA #IMPLIED    tableName CDATA #REQUIRED    alias CDATA #IMPLIED    domainObjectName CDATA #IMPLIED    mapperName CDATA #IMPLIED    sqlProviderName CDATA #IMPLIED    enableInsert CDATA #IMPLIED    enableSelectByPrimaryKey CDATA #IMPLIED    enableSelectByExample CDATA #IMPLIED    enableUpdateByPrimaryKey CDATA #IMPLIED    enableDeleteByPrimaryKey CDATA #IMPLIED    enableDeleteByExample CDATA #IMPLIED    enableCountByExample CDATA #IMPLIED    enableUpdateByExample CDATA #IMPLIED    selectByPrimaryKeyQueryId CDATA #IMPLIED    selectByExampleQueryId CDATA #IMPLIED    modelType CDATA #IMPLIED    escapeWildcards CDATA #IMPLIED    delimitIdentifiers CDATA #IMPLIED    delimitAllColumns CDATA #IMPLIED>    <!ELEMENT columnOverride (property*)>  <!ATTLIST columnOverride    column CDATA #REQUIRED    property CDATA #IMPLIED    javaType CDATA #IMPLIED    jdbcType CDATA #IMPLIED    typeHandler CDATA #IMPLIED    isGeneratedAlways CDATA #IMPLIED    delimitedColumnName CDATA #IMPLIED>    <!ELEMENT ignoreColumn EMPTY>  <!ATTLIST ignoreColumn    column CDATA #REQUIRED    delimitedColumnName CDATA #IMPLIED>      <!ELEMENT ignoreColumnsByRegex (except*)>  <!ATTLIST ignoreColumnsByRegex    pattern CDATA #REQUIRED>    <!ELEMENT except EMPTY>  <!ATTLIST except    column CDATA #REQUIRED    delimitedColumnName CDATA #IMPLIED>    <!ELEMENT generatedKey EMPTY>  <!ATTLIST generatedKey    column CDATA #REQUIRED    sqlStatement CDATA #REQUIRED    identity CDATA #IMPLIED    type CDATA #IMPLIED>    <!ELEMENT domainObjectRenamingRule EMPTY>  <!ATTLIST domainObjectRenamingRule    searchString CDATA #REQUIRED    replaceString CDATA #IMPLIED>    <!ELEMENT columnRenamingRule EMPTY>  <!ATTLIST columnRenamingRule    searchString CDATA #REQUIRED    replaceString CDATA #IMPLIED>    <!ELEMENT commentGenerator (property*)>  <!ATTLIST commentGenerator    type 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");          //替换ConfigurationParser          ConfigurationParserOverride 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的扩展生成代码完成。