代码演示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的相关内容是阅读本文的前置条件)如果不熟悉的同学,请自行补充,本文不对其进行相关介绍)。同时,本文不可能涵盖所有业务所需的扩展点,但是基本样板已有,可参考本文代码继续进行扩展。

一、注释的自定义生成

根据数据库表或字段的 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()+ "

");         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()+ "

");         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()+ "

");         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 + "

");         topLevelClass.addJavaDocLine(" * " + table.toString() + "

");         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 warnings) {         return true;     } }

二、分页和分组代码生成

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

先对基类进行介绍。

1)BaseMapper

package cn.xxx.core.base.dao;
import java.util.List;
import org.apache.ibatis.annotations.Param;
public interface BaseMapper {
    
    long countByExample(Example example);
    int deleteByExample(Example example);
    int deleteByPrimaryKey(ID id);
    int insert(T record);
    int insertSelective(T record);
    List 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
     * 

     * 页数从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;
    }
}

三、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 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);
    }
}

四、修正

重复生成时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);
    }
}

五、序列化自定义扩展

增加 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 warnings) {
        return true;
    }
}

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

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

先对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 {
    long countByExample(Example example);
    int deleteByExample(Example example);
    int deleteByPrimaryKey(ID id);
    int insert(T record);
    int insertSelective(T record);
    List 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

     * then return result of selectByExample(example)      * @author Marvis      * @date Jul 13, 2017 5:24:35 PM      * @param example      * @param pageInfo      * @return      */     List 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 implements BaseService {
    private BaseMapper mapper;
    public void setMapper(BaseMapper 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 selectByExample(Example example) {
        return mapper.selectByExample(example);
    }
    @Override
    public T selectByCondition(Example example) {
        
        List datas = selectByExample(example);
        return datas != null && datas.size() == 0 ? null : datas.get(0);
    }
    @Override
    public List 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 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 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 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 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 warnings;
    private List parseErrors;
    private Properties extraProperties;
    public ConfigurationParserOverride(List warnings) {
        this(null, warnings);
    }
    public ConfigurationParserOverride(Properties extraProperties, List 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);
    }
}

七、PluginChain

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

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

八、generatorConfig.xml

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

1)generatorConfig.xml




                        























  


        


















 ]
  >
   
 
    
                
        
        
        
        
        
        
        
            
        
        
            
            
        
        
            
        
        
            
        
              
        
            
        
        
        
            
        
    

九、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 warnings = new ArrayList();
        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的扩展生成代码完成。

来源:宜信技术学院

作者:马伟伟


请使用浏览器的分享功能分享到微信等