美文网首页
Mybatis-Generator 扩展自定义生成代码

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

作者: 灵技阁 | 来源:发表于2018-09-12 13:10 被阅读0次

    license
    Mybatis-Generator 可自动生成Model,Dao,Mapper代码,但是它自带的生成的代码:

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

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

    分页和分组代码生成:
    这里,我对Dao Model进行了通用方法的抽取,建立通用基类.同时,对其进行了一些扩展,增加分页和分组.先对基类进行介绍.

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

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

    PageInfo :

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

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

    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 生成代码简化:

    ClientDaoPlugin :

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

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

    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")注解

    SerializablePlugin:

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

    服务层代码自定义生成: 重写Context,ConfigurationParser,MyBatisGeneratorConfigurationParser, 增加服务层生成逻辑

    先对Service基类进行介绍:
    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);
    }
    
    

    BaseServiceImpl:

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

    ServiceLayerPlugin :

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

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

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

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

    ConfigurationParserOverride:

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

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

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

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

    generatorConfig.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- 内部DTD 亦可通过外部DTD来实现-->
    <!DOCTYPE generatorConfiguration
      
      [
    <!ELEMENT generatorConfiguration (properties?, classPathEntry*, context+)>
                            
    <!ELEMENT properties EMPTY>
    <!ATTLIST properties
      resource CDATA #IMPLIED
      url CDATA #IMPLIED>
    <!--
        括号里是声明出现的次序:
        *: 出现任意次,包括0次
        ?: 出现最多一次
        |:选择之一
        +: 出现最少1次
        如果没有上述符号:必须且只能出现一次
     -->
    <!ELEMENT context (property*, plugin*, commentGenerator?, (connectionFactory | jdbcConnection), javaTypeResolver?,
                             javaModelGenerator, sqlMapGenerator, javaClientGenerator, javaServiceGenerator,table+)>
    <!ATTLIST context id ID #REQUIRED
      defaultModelType CDATA #IMPLIED
      targetRuntime CDATA #IMPLIED
      introspectedColumnImpl CDATA #IMPLIED>
    
    <!ELEMENT connectionFactory (property*)>
    <!ATTLIST connectionFactory
      type CDATA #IMPLIED>
    
    <!ELEMENT jdbcConnection (property*)>
    <!ATTLIST jdbcConnection 
      driverClass CDATA #REQUIRED
      connectionURL CDATA #REQUIRED
      userId CDATA #IMPLIED
      password CDATA #IMPLIED>
    
    <!ELEMENT classPathEntry EMPTY>
    <!ATTLIST classPathEntry
      location CDATA #REQUIRED>
    
    <!ELEMENT property EMPTY>
    <!ATTLIST property
      name CDATA #REQUIRED
      value CDATA #REQUIRED>
    
    <!ELEMENT plugin (property*)>
    <!ATTLIST plugin
      type CDATA #REQUIRED>
    
    <!ELEMENT javaModelGenerator (property*)>
    <!ATTLIST javaModelGenerator
      targetPackage CDATA #REQUIRED
      targetProject CDATA #REQUIRED>
    
    <!ELEMENT javaTypeResolver (property*)>
    <!ATTLIST javaTypeResolver
      type CDATA #IMPLIED>
    
    <!ELEMENT sqlMapGenerator (property*)>
    <!ATTLIST sqlMapGenerator
      targetPackage CDATA #REQUIRED
      targetProject CDATA #REQUIRED>
    
    <!ELEMENT javaClientGenerator (property*)>
    <!ATTLIST javaClientGenerator
      type CDATA #REQUIRED
      targetPackage CDATA #REQUIRED
      targetProject CDATA #REQUIRED
      implementationPackage CDATA #IMPLIED>
      
    <!ELEMENT javaServiceGenerator (property*)>
    <!ATTLIST javaServiceGenerator
            targetPackage CDATA #REQUIRED
            implementationPackage CDATA #REQUIRED
            targetProject CDATA #REQUIRED>
            
    <!ELEMENT table (property*, generatedKey?, domainObjectRenamingRule?, columnRenamingRule?, (columnOverride | ignoreColumn | ignoreColumnsByRegex)*) >
    <!ATTLIST table
      catalog CDATA #IMPLIED
      schema CDATA #IMPLIED
      tableName CDATA #REQUIRED
      alias CDATA #IMPLIED
      domainObjectName CDATA #IMPLIED
      mapperName CDATA #IMPLIED
      sqlProviderName CDATA #IMPLIED
      enableInsert CDATA #IMPLIED
      enableSelectByPrimaryKey CDATA #IMPLIED
      enableSelectByExample CDATA #IMPLIED
      enableUpdateByPrimaryKey CDATA #IMPLIED
      enableDeleteByPrimaryKey CDATA #IMPLIED
      enableDeleteByExample CDATA #IMPLIED
      enableCountByExample CDATA #IMPLIED
      enableUpdateByExample CDATA #IMPLIED
      selectByPrimaryKeyQueryId CDATA #IMPLIED
      selectByExampleQueryId CDATA #IMPLIED
      modelType CDATA #IMPLIED
      escapeWildcards CDATA #IMPLIED
      delimitIdentifiers CDATA #IMPLIED
      delimitAllColumns CDATA #IMPLIED>
    
    <!ELEMENT columnOverride (property*)>
    <!ATTLIST columnOverride
      column CDATA #REQUIRED
      property CDATA #IMPLIED
      javaType CDATA #IMPLIED
      jdbcType CDATA #IMPLIED
      typeHandler CDATA #IMPLIED
      isGeneratedAlways CDATA #IMPLIED
      delimitedColumnName CDATA #IMPLIED>
    
    <!ELEMENT ignoreColumn EMPTY>
    <!ATTLIST ignoreColumn
      column CDATA #REQUIRED
      delimitedColumnName CDATA #IMPLIED>
    
    
    <!ELEMENT ignoreColumnsByRegex (except*)>
    <!ATTLIST ignoreColumnsByRegex
      pattern CDATA #REQUIRED>
    
    <!ELEMENT except EMPTY>
    <!ATTLIST except
      column CDATA #REQUIRED
      delimitedColumnName CDATA #IMPLIED>
    
    <!ELEMENT generatedKey EMPTY>
    <!ATTLIST generatedKey
      column CDATA #REQUIRED
      sqlStatement CDATA #REQUIRED
      identity CDATA #IMPLIED
      type CDATA #IMPLIED>
    
    <!ELEMENT domainObjectRenamingRule EMPTY>
    <!ATTLIST domainObjectRenamingRule
      searchString CDATA #REQUIRED
      replaceString CDATA #IMPLIED>
    
    <!ELEMENT columnRenamingRule EMPTY>
    <!ATTLIST columnRenamingRule
      searchString CDATA #REQUIRED
      replaceString CDATA #IMPLIED>
    
    <!ELEMENT commentGenerator (property*)>
    <!ATTLIST commentGenerator
      type CDATA #IMPLIED>
     ]
      >
       
    <generatorConfiguration> 
        <context id="ables" targetRuntime="MyBatis3">
                    <!--
                        添加Plugin
                   -->
            <plugin type="run.override.PluginChain" />
            <plugin type="run.override.SerializablePlugin" />
            <plugin type="org.mybatis.generator.plugins.ToStringPlugin" />
            <commentGenerator type="run.override.CommentGenerator"/>
    
            <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                connectionURL="jdbc:mysql://xxx.xxx.xxx.xxx:3306/xxx?characterEncoding=utf8"
                userId="xxx" password="xxx">
            </jdbcConnection>
            <javaTypeResolver>
                <property name="forceBigDecimals" value="false" />
            </javaTypeResolver>
            <javaModelGenerator targetPackage="cn.xxx.elecsign.model" targetProject=".\src">
                <property name="enableSubPackages" value="false" />
                <property name="trimStrings" value="true" />
            </javaModelGenerator>
    
            <sqlMapGenerator targetPackage="mapper.cn.xxx.elecsign.dao" targetProject=".\src">
                <property name="enableSubPackages" value="false" />
            </sqlMapGenerator>
    
            <javaClientGenerator type="XMLMAPPER" targetPackage="cn.xxx.elecsign.dao" targetProject=".\src">
                <property name="enableSubPackages" value="false" />
            </javaClientGenerator>
                  <!-- javaServiceGenerator  -->
            <javaServiceGenerator  targetPackage="cn.xxx.elecsign.dly.service" 
                    implementationPackage = "cn.xxx.elecsign.dly.service.impl" targetProject=".\src">
                <property name="enableSubPackages" value="false" />
            </javaServiceGenerator>
    
            <!-- 批次表,针对批量的异步操作 -->
            <table tableName="table" domainObjectName="Table" 
                alias="table">
                <generatedKey column="id" sqlStatement="MySql" identity="true" />
            </table>
        </context>
    </generatorConfiguration>
    
    

    main启动

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

    至此,对mybatis-generator的扩展生成代码完成.

    相关文章

      网友评论

          本文标题:Mybatis-Generator 扩展自定义生成代码

          本文链接:https://www.haomeiwen.com/subject/zihugftx.html