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

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS PostgreSQL,集群系列 2核4GB
简介: Mybatis-Generator可自动生成模型,Dao,Mapper代码,但其自带生成的代码存在以下问题:生成的注释不是我们想要的,我们期望的是根据数据库表,细分生成不同的注释;分页代码生成缺失,每个公司的分页方式不同,尤其是老久项目或已发布API,不能随意移动,那么如何自适应分页代码生成;Mapper.xml没有按相关代码生成分组;重复生成代码时,Mapper.xml并非覆盖原始代码,而是对内容进行了追加;序列化,mybatis-generator内置了SerializablePlugin,但仅对Model,并没有对Example序列化,在一些开发中是不够的;对服务层代码没有生

Mybatis-Generator可自动生成模型,Dao,Mapper代码,但其自带生成的代码存在以下问题:
生成的注释不是我们想要的,我们期望的是根据数据库表,细分生成不同的注释;
分页代码生成缺失,每个公司的分页方式不同,尤其是老久项目或已发布API,不能随意移动,那么如何自适应分页代码生成;
Mapper.xml没有按相关代码生成分组;
重复生成代码时,Mapper.xml并非覆盖原始代码,而是对内容进行了追加;
序列化,mybatis-generator内置了SerializablePlugin,但仅对Model,并没有对Example序列化,在一些开发中是不够的;
对服务层代码没有生成。
实际上,mybatis-generator提供了PluginAdapter供我们来继承,进行个性化的一些扩展(插件的相关内容是阅读本文的首要条件)如果不熟悉的同学,请自行补充,此处不进行进行相关介绍)。不可能涵盖所有业务所需的扩展点,但是基本样板已有,可参考本文继续进行扩展。

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

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)EntityComment插件
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 < ) {
                tableComment = "";
            } else {
                tableComment = createDDL.substring(index + 9);
                tableComment = tableComment.substring(, 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;
}

}
二,分页和分组代码生成
这里,我对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 = ;

// 结束
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 ==  ? 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 = ;
    } else if (currentPage > Psize_l) {
        if (Psize_l == ) {
            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 <=  || this.currentPage > this.totalPage)
        this.pageSize = ;
}

/**
 * 将分布参数传入处理,最终计算出当前页码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)分页插件
分页扩展。并且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)完全合格的JavaTypeProxyFactory
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());

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

}
四,修正
重复生成时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)可序列化插件
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;
}

}
六,服务层代码自定义生成
重写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() ==  ? null : datas.get();
}

@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());

    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(, 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());

    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(, builder.length())
                    .append(serviceSuperPackage)
                    .append(".")
                    .append(domainObjectName)
                    .append("Service")
                    .toString()
    );

    TopLevelClass serviceImplClazz = new TopLevelClass(

            builder.delete(, 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(, 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(, builder.length())
            .append(Character.toLowerCase(domainObjectName.charAt()))
            .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 = ; 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 = ; 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 = ; 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 = ; 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 = ; i < nodeList.getLength(); i++) {
        Node childNode = nodeList.item(i);
        if (childNode.getNodeType() == 1 && "property".equals(childNode.getNodeName()))
            parseProperty(javaClientGeneratorConfiguration, childNode);
    }

}

}
6)ServiceGenerator配置
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() > ) {
            throw new XMLParserException(this.parseErrors);
        }

        Element rootNode = document.getDocumentElement();
        Configuration config = parseMyBatisGeneratorConfiguration(rootNode);
        
        if (this.parseErrors.size() > ) {
            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);
}

}
七,插件链
通过继承,把以上扩展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
<?xml version="1.0" encoding="UTF-8"?>

<!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>
]

<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 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>


九,主启动
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的扩展生成代码完成。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
3月前
|
SQL XML Java
8、Mybatis-Plus 分页插件、自定义分页
这篇文章介绍了Mybatis-Plus的分页功能,包括如何配置分页插件、使用Mybatis-Plus提供的Page对象进行分页查询,以及如何在XML中自定义分页SQL。文章通过具体的代码示例和测试结果,展示了分页插件的使用和自定义分页的方法。
8、Mybatis-Plus 分页插件、自定义分页
|
3月前
|
SQL Java 测试技术
3、Mybatis-Plus 自定义sql语句
这篇文章介绍了如何在Mybatis-Plus框架中使用自定义SQL语句进行数据库操作。内容包括文档结构、编写mapper文件、mapper.xml文件的解释说明、在mapper接口中定义方法、在mapper.xml文件中实现接口方法的SQL语句,以及如何在单元测试中测试自定义的SQL语句,并展示了测试结果。
3、Mybatis-Plus 自定义sql语句
|
2月前
|
XML Java 数据库连接
mybatis plus模板快速生成代码
MybatisX 是一款提升开发效率的 IDEA 插件,尤其适用于处理多表情况。通过 MybatisX-Generator,用户能轻松生成实体类、服务类、Mapper 接口及 XML 文件,显著减少工作量。安装步骤简便:通过 File -&gt; Settings -&gt; Plugins -&gt; Browse Repositories 完成搜索与安装流程。集成数据库后,右键所需操作的数据表,选择 MyBatisX-Generator 进行自动化代码生成。更多细节可参考相关教程。
66 0
|
3月前
|
SQL Java Kotlin
MybatisPlus怎么拓展自定义BaseMapper
通过扩展Mybatis-Plus的`BaseMapper`,可以自定义SQL模板以满足特定业务需求。例如,当遇到唯一键冲突而不希望抛出异常时,可使用`INSERT IGNORE`语法。首先,创建`InsertIgnore`类继承`AbstractMethod`并定义`insertIgnore`方法及其SQL模板。接着,在自定义的`UltraBaseMapper`接口中声明`insertIgnore`方法,并让业务Mapper继承此接口。最后,通过`UltraSqlInjector`类将`InsertIgnore`方法注册到Mybatis-Plus插件中。
136 1
|
5天前
|
SQL 缓存 Java
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
本文详细介绍了MyBatis的各种常见用法MyBatis多级缓存、逆向工程、分页插件 包括获取参数值和结果的各种情况、自定义映射resultMap、动态SQL
【详细实用のMyBatis教程】获取参数值和结果的各种情况、自定义映射、动态SQL、多级缓存、逆向工程、分页插件
|
29天前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
88 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
15天前
|
搜索推荐 Java 数据库连接
Java|在 IDEA 里自动生成 MyBatis 模板代码
基于 MyBatis 开发的项目,新增数据库表以后,总是需要编写对应的 Entity、Mapper 和 Service 等等 Class 的代码,这些都是重复的工作,我们可以想一些办法来自动生成这些代码。
26 6
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
263 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
4月前
|
SQL Java 数据库连接
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
idea中配置mybatis 映射文件模版及 mybatis plus 自定义sql
87 3
|
5月前
|
SQL 前端开发 Java
我这样写代码,比直接使用 MyBatis 效率提高了 100 倍
Mybatis Hibernate 等都是我们常用的 ORM, 它们有时候很好用,但某些场景下也很繁琐,比如下文要讲的一个需求,最后本文会给出比直接用这些 ORM 开发效率至少提高 100 倍的方法...
53 1
我这样写代码,比直接使用 MyBatis 效率提高了 100 倍