天天看點

代碼示範Mybatis-Generator擴充自定義生成

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.List;

import org.mybatis.generator.api.FullyQualifiedTable;

import org.mybatis.generator.api.PluginAdapter;

import org.mybatis.generator.api.dom.java.TopLevelClass;

import org.mybatis.generator.internal.JDBCConnectionFactory;

  • Comment of Entity,only support MySQL
  • @ClassName CommentPlugin

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 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 增加分頁參數
  • @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

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.dom.java.FullyQualifiedJavaType;

import org.mybatis.generator.api.dom.xml.Attribute;

import org.mybatis.generator.api.dom.xml.TextElement;

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;

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.stream.Collectors;

import org.mybatis.generator.api.JavaTypeResolver;

import org.mybatis.generator.api.dom.java.Interface;

import org.mybatis.generator.internal.types.JavaTypeResolverDefaultImpl;

import run.override.model.EntityCommentPlugin;

  • javaClient("XMLMAPPER") extended
  • @ClassName ClientDaoPlugin
  • @Description Mapper.java

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 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)可序列化插件

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 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 cn.xxx.core.base.dao.BaseMapper;

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.dom.java.JavaVisibility;

import run.override.pagination.PaginationPlugin;

import java.util.ArrayList;

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

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

import org.mybatis.generator.config.Configuration;

import org.mybatis.generator.config.JavaClientGeneratorConfiguration;

import org.mybatis.generator.config.PluginConfiguration;

import org.mybatis.generator.config.xml.MyBatisGeneratorConfigurationParser;

import org.mybatis.generator.exception.XMLParserException;

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

import org.mybatis.generator.config.PropertyHolder;

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

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.Reader;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

import org.mybatis.generator.config.xml.ConfigurationParser;

import org.mybatis.generator.config.xml.ParserEntityResolver;

import org.mybatis.generator.config.xml.ParserErrorHandler;

import org.w3c.dom.Document;

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進行更改)。

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

<!ELEMENT sqlMapGenerator (property*)>

<!ATTLIST sqlMapGenerator

<!ELEMENT javaClientGenerator (property*)>

<!ATTLIST javaClientGenerator

type 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

<!ELEMENT ignoreColumnsByRegex (except*)>

<!ATTLIST ignoreColumnsByRegex

pattern CDATA #REQUIRED>

<!ELEMENT except EMPTY>

<!ATTLIST except

<!ELEMENT generatedKey EMPTY>

<!ATTLIST generatedKey

sqlStatement CDATA #REQUIRED

identity CDATA #IMPLIED

<!ELEMENT domainObjectRenamingRule EMPTY>

<!ATTLIST domainObjectRenamingRule

searchString CDATA #REQUIRED

replaceString CDATA #IMPLIED>

<!ELEMENT columnRenamingRule EMPTY>

<!ATTLIST columnRenamingRule

<!ELEMENT commentGenerator (property*)>

<!ATTLIST commentGenerator

]

<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 org.mybatis.generator.api.MyBatisGenerator;

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的擴充生成代碼完成。