代码演示MybatisGenerator扩展自定义生成

database

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

实际上,mybatis-generator提供了PluginAdapter供我们来继承,进行个性化的一些扩展(Plugin的相关内容是阅读本文的前置条件)如果不熟悉的同学,请自行补充,本文不对其进行相关介绍)。同时,本文不可能涵盖所有业务所需的扩展点,但是基本样板已有,可参考本文代码继续进行扩展。

一、注释的自定义生成

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

package run.override;

import java.util.Date;

import java.util.Properties;

import org.mybatis.generator.api.IntrospectedColumn;

import org.mybatis.generator.api.IntrospectedTable;

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

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

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

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

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

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

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

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

import org.mybatis.generator.internal.DefaultCommentGenerator;

import org.mybatis.generator.internal.util.StringUtility;

/**

* Comment Generator

* @ClassName CommentGenerator

* @Description

* @author Marvis

*/

public class CommentGenerator extends DefaultCommentGenerator {

private Properties properties;

private boolean suppressDate;

private boolean suppressAllComments;

public CommentGenerator() {

this.properties = new Properties();

this.suppressDate = false;

this.suppressAllComments = false;

}

public void addJavaFileComment(CompilationUnit compilationUnit) {

compilationUnit.addFileCommentLine("/*** copyright (c) 2019 Marvis ***/");

}

/**

* XML file Comment

*/

public void addComment(XmlElement xmlElement) {

if (this.suppressAllComments) {

return;

}

}

public void addRootComment(XmlElement rootElement) {

}

public void addConfigurationProperties(Properties properties) {

this.properties.putAll(properties);

this.suppressDate = StringUtility.isTrue(properties.getProperty("suppressDate"));

this.suppressAllComments = StringUtility.isTrue(properties.getProperty("suppressAllComments"));

}

protected void addJavadocTag(JavaElement javaElement, boolean markAsDoNotDelete) {

StringBuilder sb = new StringBuilder();

sb.append(" * ");

sb.append("@date");

String s = getDateString();

if (s != null) {

sb.append(" ");

sb.append(s);

}

javaElement.addJavaDocLine(sb.toString());

}

protected String getDateString() {

if (this.suppressDate) {

return null;

}

return new Date().toString();

}

/**

* Comment of Example inner class(GeneratedCriteria ,Criterion)

*/

public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable) {

if (this.suppressAllComments) {

return;

}

innerClass.addJavaDocLine("/**");

innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getDomainObjectName()+ "<p/>");

innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().toString());

addJavadocTag(innerClass, false);

innerClass.addJavaDocLine(" */");

}

public void addEnumComment(InnerEnum innerEnum, IntrospectedTable introspectedTable) {

if (this.suppressAllComments) {

return;

}

StringBuilder sb = new StringBuilder();

innerEnum.addJavaDocLine("/**");

innerEnum.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getAlias()+ "<p/>");

innerEnum.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable());

innerEnum.addJavaDocLine(sb.toString());

addJavadocTag(innerEnum, false);

innerEnum.addJavaDocLine(" */");

}

/**

* entity filed Comment

*/

public void addFieldComment(Field field, IntrospectedTable introspectedTable,

IntrospectedColumn introspectedColumn) {

if (this.suppressAllComments) {

return;

}

// if(introspectedColumn.getRemarks() != null && !introspectedColumn.getRemarks().trim().equals(""))

field.addJavaDocLine("/**");

field.addJavaDocLine(" * " + introspectedColumn.getRemarks());

field.addJavaDocLine(" * @author " );

field.addJavaDocLine(" * @date " + getDateString() );

field.addJavaDocLine(" * @return");

field.addJavaDocLine(" */");

}

/**

* Comment of EXample filed

*/

public void addFieldComment(Field field, IntrospectedTable introspectedTable) {

if (this.suppressAllComments) {

return;

}

field.addJavaDocLine("/**");

addJavadocTag(field, false);

field.addJavaDocLine(" */");

}

/**

* Comment of Example method

*/

public void addGeneralMethodComment(Method method, IntrospectedTable introspectedTable) {

if (this.suppressAllComments) {

return;

}

}

/**

*

* entity Getter Comment

*/

public void addGetterComment(Method method, IntrospectedTable introspectedTable,

IntrospectedColumn introspectedColumn) {

if (this.suppressAllComments) {

return;

}

method.addJavaDocLine("/**");

method.addJavaDocLine(" * @return " + introspectedTable.getFullyQualifiedTable().getAlias() + " : " + introspectedColumn.getRemarks());

method.addJavaDocLine(" */");

}

public void addSetterComment(Method method, IntrospectedTable introspectedTable,

IntrospectedColumn introspectedColumn) {

if (this.suppressAllComments) {

return;

}

StringBuilder sb = new StringBuilder();

method.addJavaDocLine("/**");

Parameter parm = (Parameter) method.getParameters().get(0);

sb.append(" * @param ");

sb.append(parm.getName());

sb.append(" : ");

sb.append(introspectedColumn.getRemarks());

method.addJavaDocLine(sb.toString());

method.addJavaDocLine(" */");

}

/**

* Comment of Example inner class(Criteria)

*/

public void addClassComment(InnerClass innerClass, IntrospectedTable introspectedTable, boolean markAsDoNotDelete) {

if (this.suppressAllComments) {

return;

}

innerClass.addJavaDocLine("/**");

innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().getAlias()+ "<p/>");

innerClass.addJavaDocLine(" * " + introspectedTable.getFullyQualifiedTable().toString());

addJavadocTag(innerClass, markAsDoNotDelete);

innerClass.addJavaDocLine(" */");

}

Model 类注释(表的描述): MySQL。

1)EntityCommentPlugin

package run.override.model;

import java.sql.Connection;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.sql.Statement;

import java.util.Date;

import java.util.List;

import org.mybatis.generator.api.FullyQualifiedTable;

import org.mybatis.generator.api.IntrospectedTable;

import org.mybatis.generator.api.PluginAdapter;

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

import org.mybatis.generator.internal.JDBCConnectionFactory;

import org.mybatis.generator.internal.util.StringUtility;

/**

* Comment of Entity,only support MySQL

* @ClassName CommentPlugin

* @Description

* @author Marvis

*/

public class EntityCommentPlugin extends PluginAdapter {

@Override

public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

addModelClassComment(topLevelClass, introspectedTable);

return super.modelBaseRecordClassGenerated(topLevelClass, introspectedTable);

}

@Override

public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,

IntrospectedTable introspectedTable) {

addModelClassComment(topLevelClass, introspectedTable);

return super.modelRecordWithBLOBsClassGenerated(topLevelClass, introspectedTable);

}

protected void addModelClassComment(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

FullyQualifiedTable table = introspectedTable.getFullyQualifiedTable();

String tableComment = getTableComment(table);

topLevelClass.addJavaDocLine("/**");

if(StringUtility.stringHasValue(tableComment))

topLevelClass.addJavaDocLine(" * " + tableComment + "<p/>");

topLevelClass.addJavaDocLine(" * " + table.toString() + "<p/>");

topLevelClass.addJavaDocLine(" * @date " + new Date().toString());

topLevelClass.addJavaDocLine(" *");

topLevelClass.addJavaDocLine(" */");

}

/**

* @author Marvis

* @date Jul 13, 2017 4:39:52 PM

* @param table

*/

private String getTableComment(FullyQualifiedTable table) {

String tableComment = "";

Connection connection = null;

Statement statement = null;

ResultSet rs = null;

try {

JDBCConnectionFactory jdbc = new JDBCConnectionFactory(context.getJdbcConnectionConfiguration());

connection = jdbc.getConnection();

statement = connection.createStatement();

rs = statement.executeQuery("SHOW CREATE TABLE " + table.getIntrospectedTableName());

if (rs != null && rs.next()) {

String createDDL = rs.getString(2);

int index = createDDL.indexOf("COMMENT="");

if (index < 0) {

tableComment = "";

} else {

tableComment = createDDL.substring(index + 9);

tableComment = tableComment.substring(0, tableComment.length() - 1);

}

}

} catch (SQLException e) {

} finally {

closeConnection(connection, statement, rs);

}

return tableComment;

}

/**

*

* @author Marvis

* @date Jul 13, 2017 4:45:26 PM

* @param connection

* @param statement

* @param rs

*/

private void closeConnection(Connection connection, Statement statement, ResultSet rs) {

try {

if (null != rs)

rs.close();

} catch (SQLException e) {

e.printStackTrace();

} finally {

try {

if (statement != null)

statement.close();

} catch (Exception e) {

e.printStackTrace();

} finally {

try {

if (connection != null)

connection.close();

} catch (SQLException e) {

e.printStackTrace();

}

}

}

}

/**

* This plugin is always valid - no properties are required

*/

@Override

public boolean validate(List<String> warnings) {

return true;

}

}

二、分页和分组代码生成

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

先对基类进行介绍。

1)BaseMapper

package cn.xxx.core.base.dao;

import java.util.List;

import org.apache.ibatis.annotations.Param;

public interface BaseMapper<T, Example, ID> {

long countByExample(Example example);

int deleteByExample(Example example);

int deleteByPrimaryKey(ID id);

int insert(T record);

int insertSelective(T record);

List<T> selectByExample(Example example);

T selectByPrimaryKey(ID id);

int updateByExampleSelective(@Param("record") T record, @Param("example") Example example);

int updateByExample(@Param("record") T record, @Param("example") Example example);

int updateByPrimaryKeySelective(T record);

int updateByPrimaryKey(T record);

}

2)BaseExample

package cn.xxx.core.base.model;

/**

* BaseExample 基类

* @ClassName BaseExample

* @Description 增加分页参数

* @author Marvis

* @date Jul 31, 2017 11:26:53 AM

*/

public abstract class BaseExample {

protected PageInfo pageInfo;

protected String groupByClause;

public PageInfo getPageInfo() {

return pageInfo;

}

public void setPageInfo(PageInfo pageInfo) {

this.pageInfo = pageInfo;

}

public String getGroupByClause() {

return groupByClause;

}

public void setGroupByClause(String groupByClause) {

this.groupByClause = groupByClause;

}

}

3)PageInfo

package cn.xxx.core.base.model;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**

* 分页查询参数类

*

* @author

*

*/

public class PageInfo {

public static final int Default_PageSize = 20;

// 当前页码

protected int currentPage = 1;

// 总页数

protected int totalPage;

// 总记录数

protected int totalCount;

// 每页条数

protected int pageSize = Default_PageSize;

// 开始

protected int pageBegin = 0;

// 结束

protected int pageEnd = 20;

/**

* bean起始坐标(不包含)

*/

private Integer pageBeginId = null;

public static final String PageQuery_classname = "pageInfo";

/**

* 将分布参数传入处理,最终计算出当前页码PageQuery_currPage,开始坐标PageQuery_star,

* 结束坐标PageQuery_end,总页数PageQuery_Psize

* <p/>

* 页数从1开始计数

*

* @param totalCount

* 记录总数

* @param pageSize

* 每页显示个数

* @param currentPage

* 当前页码

*/

public void setPageParams(int totalCount, int pageSize, int currentPage) {

this.totalPage = pageSize == 0 ? 1 : (int) Math.ceil((double) totalCount / (double) pageSize);

this.totalCount = totalCount;

this.pageSize = pageSize;

this.currentPage = currentPage;

float Psize_l = totalCount / (float) (this.pageSize);

if (currentPage < 2) {

currentPage = 1;

pageBegin = 0;

} else if (currentPage > Psize_l) {

if (Psize_l == 0) {

currentPage = 1;

} else {

currentPage = (int) Math.ceil(Psize_l);

}

pageBegin = (currentPage - 1) * this.pageSize;

} else {

pageBegin = (currentPage - 1) * this.pageSize;

}

pageSize = (int) Math.ceil(Psize_l);

this.pageEnd = currentPage * this.pageSize;

if (this.currentPage <= 0 || this.currentPage > this.totalPage)

this.pageSize = 0;

}

/**

* 将分布参数传入处理,最终计算出当前页码PageQuery_currPage,开始坐标PageQuery_star,

* 结束坐标PageQuery_end,总页数PageQuery_Psize

*

* @param infoCount

* 记录总数

*/

public void setPageParams(int totalCount) {

this.setPageParams(totalCount, this.pageSize, this.currentPage);

}

@Override

public String toString() {

return "PageInfo [currentPage=" + currentPage + ", totalPage=" + totalPage + ", totalCount=" + totalCount

+ ", pageSize=" + pageSize + ", pageBegin=" + pageBegin + ", pageEnd=" + pageEnd + ", pageBeginId="

+ pageBeginId + "]";

}

public int getCurrentPage() {

return currentPage;

}

public int getTotalPage() {

return totalPage;

}

public int getTotalCount() {

return totalCount;

}

/**

* 每页显示个数

*/

public int getPageSize() {

return pageSize;

}

@JsonIgnore

public int getPageBegin() {

return pageBegin;

}

@JsonIgnore

public int getPageEnd() {

return pageEnd;

}

/**

* bean起始id(不包含)

*/

@JsonIgnore

public Integer getPageBeginId() {

return pageBeginId;

}

/**

* 请求页

*/

public void setCurrentPage(int currentPage) {

this.currentPage = currentPage;

}

/**

* 每页显示个数

*/

public void setPageSize(int pageSize) {

this.pageSize = pageSize;

}

}

4)PaginationPlugin

分页扩展。并且Example继承BaseExample

package run.override.pagination;

import org.mybatis.generator.api.IntrospectedTable;

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

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

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

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

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

import run.override.mapper.SqlMapIsMergeablePlugin;

import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;

public class PaginationPlugin extends SqlMapIsMergeablePlugin {

@Override

public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

FullyQualifiedJavaType baseExampleType = FullyQualifiedJavaTypeProxyFactory.getBaseExampleInstance();

topLevelClass.setSuperClass(baseExampleType);

topLevelClass.addImportedType(baseExampleType);

return super.modelExampleClassGenerated(topLevelClass, introspectedTable);

}

@Override

public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(XmlElement element,

IntrospectedTable introspectedTable) {

XmlElement isNotNullElement1 = new XmlElement("if");

isNotNullElement1.addAttribute(new Attribute("test", "groupByClause != null"));

isNotNullElement1.addElement(new TextElement("group by ${groupByClause}"));

element.addElement(5, isNotNullElement1);

XmlElement isNotNullElement = new XmlElement("if");

isNotNullElement.addAttribute(new Attribute("test", "pageInfo != null"));

isNotNullElement.addElement(new TextElement("limit #{pageInfo.pageBegin} , #{pageInfo.pageSize}"));

element.addElement(isNotNullElement);

return super.sqlMapUpdateByExampleWithBLOBsElementGenerated(element, introspectedTable);

}

@Override

public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element,

IntrospectedTable introspectedTable) {

XmlElement isNotNullElement1 = new XmlElement("if");

isNotNullElement1.addAttribute(new Attribute("test", "groupByClause != null"));

isNotNullElement1.addElement(new TextElement("group by ${groupByClause}"));

element.addElement(5, isNotNullElement1);

XmlElement isNotNullElement = new XmlElement("if");

isNotNullElement.addAttribute(new Attribute("test", "pageInfo != null"));

isNotNullElement.addElement(new TextElement("limit #{pageInfo.pageBegin} , #{pageInfo.pageSize}"));

element.addElement(isNotNullElement);

return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);

}

@Override

public boolean sqlMapCountByExampleElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {

XmlElement answer = new XmlElement("select");

String fqjt = introspectedTable.getExampleType();

answer.addAttribute(new Attribute("id", introspectedTable.getCountByExampleStatementId()));

answer.addAttribute(new Attribute("parameterType", fqjt));

answer.addAttribute(new Attribute("resultType", "java.lang.Integer"));

this.context.getCommentGenerator().addComment(answer);

StringBuilder sb = new StringBuilder();

sb.append("select count(1) from ");

sb.append(introspectedTable.getAliasedFullyQualifiedTableNameAtRuntime());

XmlElement ifElement = new XmlElement("if");

ifElement.addAttribute(new Attribute("test", "_parameter != null"));

XmlElement includeElement = new XmlElement("include");

includeElement.addAttribute(new Attribute("refid", introspectedTable.getExampleWhereClauseId()));

ifElement.addElement(includeElement);

element.getElements().clear();

element.getElements().add(new TextElement(sb.toString()));

element.getElements().add(ifElement);

return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);

}

}

5)FullyQualifiedJavaTypeProxyFactory

package run.override.proxyFactory;

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

public class FullyQualifiedJavaTypeProxyFactory extends FullyQualifiedJavaType{

private static FullyQualifiedJavaType pageInfoInstance = new FullyQualifiedJavaType("cn.xxx.core.base.model.PageInfo");

private static FullyQualifiedJavaType baseExampleInstance = new FullyQualifiedJavaType("cn.xxx.core.base.model.BaseExample");

private static FullyQualifiedJavaType baseMapperInstance = new FullyQualifiedJavaType("cn.xxx.core.base.dao.BaseMapper");

private static FullyQualifiedJavaType baseServiceInstance = new FullyQualifiedJavaType("cn.xxx.core.base.service.BaseService");

private static FullyQualifiedJavaType baseServiceImplInstance = new FullyQualifiedJavaType("cn.xxx.core.base.service.impl.BaseServiceImpl");

public FullyQualifiedJavaTypeProxyFactory(String fullTypeSpecification) {

super(fullTypeSpecification);

}

public static final FullyQualifiedJavaType getPageInfoInstanceInstance() {

return pageInfoInstance;

}

public static final FullyQualifiedJavaType getBaseExampleInstance() {

return baseExampleInstance;

}

public static final FullyQualifiedJavaType getBaseMapperInstance() {

return baseMapperInstance;

}

public static final FullyQualifiedJavaType getBaseServiceInstance() {

return baseServiceInstance;

}

public static final FullyQualifiedJavaType getBaseServiceImplInstance() {

return baseServiceImplInstance;

}

}

三、Dao 生成代码简化

1)ClientDaoPlugin

package run.override.dao;

import java.util.Arrays;

import java.util.List;

import java.util.stream.Collectors;

import org.mybatis.generator.api.IntrospectedTable;

import org.mybatis.generator.api.JavaTypeResolver;

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

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

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

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

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

import run.override.model.EntityCommentPlugin;

import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;

/**

* javaClient("XMLMAPPER") extended

*

* @ClassName ClientDaoPlugin

* @Description Mapper.java

* @author Marvis

*/

public class ClientDaoPlugin extends EntityCommentPlugin {

@Override

public boolean clientGenerated(Interface interfaze, TopLevelClass topLevelClass,

IntrospectedTable introspectedTable) {

JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();

FullyQualifiedJavaType calculateJavaType = javaTypeResolver

.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));

FullyQualifiedJavaType superInterfaceType = new FullyQualifiedJavaType(

new StringBuilder("BaseMapper<")

.append(introspectedTable.getBaseRecordType())

.append(",")

.append(introspectedTable.getExampleType())

.append(",")

.append(calculateJavaType.getShortName())

.append(">")

.toString()

);

FullyQualifiedJavaType baseMapperInstance = FullyQualifiedJavaTypeProxyFactory.getBaseMapperInstance();

interfaze.addSuperInterface(superInterfaceType);

interfaze.addImportedType(baseMapperInstance);

List<Method> changeMethods = interfaze.getMethods().stream()

.filter(method -> method.getName().endsWith("WithBLOBs")

|| method.getReturnType().toString().endsWith("WithBLOBs")

|| Arrays.toString(method.getParameters().toArray()).contains("WithBLOBs"))

.collect(Collectors.toList());

interfaze.getMethods().retainAll(changeMethods);

if (changeMethods.isEmpty())

interfaze.getImportedTypes().removeIf(javaType -> javaType.getFullyQualifiedName().equals("java.util.List")

|| javaType.getFullyQualifiedName().equals("org.apache.ibatis.annotations.Param"));

return super.clientGenerated(interfaze, topLevelClass, introspectedTable);

}

}

四、修正

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

1)SqlMapIsMergeablePlugin

package run.override.mapper;

import org.mybatis.generator.api.GeneratedXmlFile;

import org.mybatis.generator.api.IntrospectedTable;

import run.override.dao.ClientDaoPlugin;

public class SqlMapIsMergeablePlugin extends ClientDaoPlugin {

@Override

public boolean sqlMapGenerated(GeneratedXmlFile sqlMap, IntrospectedTable introspectedTable) {

//重新生成代码,xml内容覆盖

sqlMap.setMergeable(false);

return super.sqlMapGenerated(sqlMap, introspectedTable);

}

}

五、序列化自定义扩展

增加Example的序列化,并增加@SuppressWarnings("serial")注解。

1)SerializablePlugin

package run.override;

import java.util.List;

import java.util.Properties;

import org.mybatis.generator.api.IntrospectedTable;

import org.mybatis.generator.api.PluginAdapter;

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

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

public class SerializablePlugin extends PluginAdapter {

private FullyQualifiedJavaType serializable;

private FullyQualifiedJavaType gwtSerializable;

private boolean addGWTInterface;

private boolean suppressJavaInterface;

public SerializablePlugin() {

this.serializable = new FullyQualifiedJavaType("java.io.Serializable");

this.gwtSerializable = new FullyQualifiedJavaType("com.google.gwt.user.client.rpc.IsSerializable");

}

@Override

public void setProperties(Properties properties) {

super.setProperties(properties);

this.addGWTInterface = Boolean.valueOf(properties.getProperty("addGWTInterface")).booleanValue();

this.suppressJavaInterface = Boolean.valueOf(properties.getProperty("suppressJavaInterface")).booleanValue();

}

@Override

public boolean modelBaseRecordClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

makeSerializable(topLevelClass, introspectedTable);

return true;

}

@Override

public boolean modelPrimaryKeyClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

makeSerializable(topLevelClass, introspectedTable);

return true;

}

@Override

public boolean modelRecordWithBLOBsClassGenerated(TopLevelClass topLevelClass,

IntrospectedTable introspectedTable) {

makeSerializable(topLevelClass, introspectedTable);

return true;

}

@Override

public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,IntrospectedTable introspectedTable){

makeSerializable(topLevelClass, introspectedTable);

return true;

}

protected void makeSerializable(TopLevelClass topLevelClass, IntrospectedTable introspectedTable) {

if (this.addGWTInterface) {

topLevelClass.addImportedType(this.gwtSerializable);

topLevelClass.addSuperInterface(this.gwtSerializable);

}

if (!(this.suppressJavaInterface)) {

topLevelClass.addImportedType(this.serializable);

topLevelClass.addSuperInterface(this.serializable);

topLevelClass.addAnnotation("@SuppressWarnings("serial")");

}

}

/**

* This plugin is always valid - no properties are required

*/

@Override

public boolean validate(List<String> warnings) {

return true;

}

}

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

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

先对Service基类进行介绍。

1)BaseService

package cn.xxx.core.base.service;

import java.util.List;

import org.apache.ibatis.annotations.Param;

import cn.xxx.core.base.model.BaseExample;

import cn.xxx.core.base.model.PageInfo;

public interface BaseService<T, Example extends BaseExample, ID> {

long countByExample(Example example);

int deleteByExample(Example example);

int deleteByPrimaryKey(ID id);

int insert(T record);

int insertSelective(T record);

List<T> selectByExample(Example example);

/**

* return T object

* @author Marvis

* @date May 23, 2018 11:37:11 AM

* @param example

* @return

*/

T selectByCondition(Example example);

/**

* if pageInfo == null<p/>

* then return result of selectByExample(example)

* @author Marvis

* @date Jul 13, 2017 5:24:35 PM

* @param example

* @param pageInfo

* @return

*/

List<T> selectByPageExmple(Example example, PageInfo pageInfo);

T selectByPrimaryKey(ID id);

int updateByExampleSelective(@Param("record") T record, @Param("example") Example example);

int updateByExample(@Param("record") T record, @Param("example") Example example);

int updateByPrimaryKeySelective(T record);

int updateByPrimaryKey(T record);

}

2)BaseServiceImpl

package cn.xxx.core.base.service.impl;

import java.util.List;

import cn.xxx.core.base.dao.BaseMapper;

import cn.xxx.core.base.model.BaseExample;

import cn.xxx.core.base.model.PageInfo;

import cn.xxx.core.base.service.BaseService;

public abstract class BaseServiceImpl<T, Example extends BaseExample, ID> implements BaseService<T, Example, ID> {

private BaseMapper<T, Example, ID> mapper;

public void setMapper(BaseMapper<T, Example, ID> mapper) {

this.mapper = mapper;

}

public long countByExample(Example example) {

return mapper.countByExample(example);

}

@Override

public int deleteByExample(Example example) {

return mapper.deleteByExample(example);

}

@Override

public int deleteByPrimaryKey(ID id) {

return mapper.deleteByPrimaryKey(id);

}

@Override

public int insert(T record) {

return mapper.insert(record);

}

@Override

public int insertSelective(T record) {

return mapper.insertSelective(record);

}

@Override

public List<T> selectByExample(Example example) {

return mapper.selectByExample(example);

}

@Override

public T selectByCondition(Example example) {

List<T> datas = selectByExample(example);

return datas != null && datas.size() == 0 ? null : datas.get(0);

}

@Override

public List<T> selectByPageExmple(Example example, PageInfo pageInfo) {

if(pageInfo != null){

example.setPageInfo(pageInfo);

pageInfo.setPageParams(Long.valueOf(this.countByExample(example)).intValue());

}

return this.selectByExample(example);

}

@Override

public T selectByPrimaryKey(ID id) {

return mapper.selectByPrimaryKey(id);

}

@Override

public int updateByExampleSelective(T record, Example example) {

return mapper.updateByExampleSelective(record, example);

}

@Override

public int updateByExample(T record, Example example) {

return mapper.updateByExample(record, example);

}

@Override

public int updateByPrimaryKeySelective(T record) {

return mapper.updateByPrimaryKeySelective(record);

}

@Override

public int updateByPrimaryKey(T record) {

return mapper.updateByPrimaryKey(record);

}

}

3)ServiceLayerPlugin

package run.override.service;

import org.mybatis.generator.api.GeneratedJavaFile;

import org.mybatis.generator.api.IntrospectedTable;

import org.mybatis.generator.api.JavaTypeResolver;

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

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

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

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

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

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

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

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

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

import run.override.pagination.PaginationPlugin;

import run.override.proxyFactory.FullyQualifiedJavaTypeProxyFactory;

import java.util.ArrayList;

import java.util.List;

import java.util.stream.Collectors;

public class ServiceLayerPlugin extends PaginationPlugin {

/**

* 生成额外java文件

*/

@Override

public List<GeneratedJavaFile> contextGenerateAdditionalJavaFiles(IntrospectedTable introspectedTable) {

ContextOverride context = (ContextOverride) introspectedTable.getContext();

ServiceGeneratorConfiguration serviceGeneratorConfiguration;

if ((serviceGeneratorConfiguration = context.getServiceGeneratorConfiguration()) == null)

return null;

String targetPackage = serviceGeneratorConfiguration.getTargetPackage();

String targetProject = serviceGeneratorConfiguration.getTargetProject();

String implementationPackage = serviceGeneratorConfiguration.getImplementationPackage();

CompilationUnit addServiceInterface = addServiceInterface(introspectedTable, targetPackage);

CompilationUnit addServiceImplClazz = addServiceImplClazz(introspectedTable, targetPackage,

implementationPackage);

GeneratedJavaFile gjfServiceInterface = new GeneratedJavaFile(addServiceInterface, targetProject,

this.context.getProperty("javaFileEncoding"), this.context.getJavaFormatter());

GeneratedJavaFile gjfServiceImplClazz = new GeneratedJavaFile(addServiceImplClazz, targetProject,

this.context.getProperty("javaFileEncoding"), this.context.getJavaFormatter());

List<GeneratedJavaFile> list = new ArrayList<>();

list.add(gjfServiceInterface);

list.add(gjfServiceImplClazz);

return list;

}

protected CompilationUnit addServiceInterface(IntrospectedTable introspectedTable, String targetPackage) {

String entityClazzType = introspectedTable.getBaseRecordType();

String serviceSuperPackage = targetPackage;

String entityExampleClazzType = introspectedTable.getExampleType();

String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();

JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();

FullyQualifiedJavaType calculateJavaType = javaTypeResolver

.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));

StringBuilder builder = new StringBuilder();

FullyQualifiedJavaType superInterfaceType = new FullyQualifiedJavaType(

builder.append("BaseService<")

.append(entityClazzType)

.append(",")

.append(entityExampleClazzType)

.append(",")

.append(calculateJavaType.getShortName()).append(">").toString());

Interface serviceInterface = new Interface(

builder.delete(0, builder.length())

.append(serviceSuperPackage)

.append(".")

.append(domainObjectName)

.append("Service")

.toString()

);

serviceInterface.addSuperInterface(superInterfaceType);

serviceInterface.setVisibility(JavaVisibility.PUBLIC);

FullyQualifiedJavaType baseServiceInstance = FullyQualifiedJavaTypeProxyFactory.getBaseServiceInstance();

FullyQualifiedJavaType modelJavaType = new FullyQualifiedJavaType(entityClazzType);

FullyQualifiedJavaType exampleJavaType = new FullyQualifiedJavaType(entityExampleClazzType);

serviceInterface.addImportedType(baseServiceInstance);

serviceInterface.addImportedType(modelJavaType);

serviceInterface.addImportedType(exampleJavaType);

serviceInterface.addFileCommentLine("/*** copyright (c) 2019 Marvis ***/");

this.additionalServiceMethods(introspectedTable, serviceInterface);

return serviceInterface;

}

protected CompilationUnit addServiceImplClazz(IntrospectedTable introspectedTable, String targetPackage,

String implementationPackage) {

String entityClazzType = introspectedTable.getBaseRecordType();

String serviceSuperPackage = targetPackage;

String serviceImplSuperPackage = implementationPackage;

String entityExampleClazzType = introspectedTable.getExampleType();

String javaMapperType = introspectedTable.getMyBatis3JavaMapperType();

String domainObjectName = introspectedTable.getFullyQualifiedTable().getDomainObjectName();

JavaTypeResolver javaTypeResolver = new JavaTypeResolverDefaultImpl();

FullyQualifiedJavaType calculateJavaType = javaTypeResolver

.calculateJavaType(introspectedTable.getPrimaryKeyColumns().get(0));

StringBuilder builder = new StringBuilder();

FullyQualifiedJavaType superClazzType = new FullyQualifiedJavaType(

builder.append("BaseServiceImpl<")

.append(entityClazzType)

.append(",")

.append(entityExampleClazzType)

.append(",")

.append(calculateJavaType.getShortName()).append(">")

.toString()

);

FullyQualifiedJavaType implInterfaceType = new FullyQualifiedJavaType(

builder.delete(0, builder.length())

.append(serviceSuperPackage)

.append(".")

.append(domainObjectName)

.append("Service")

.toString()

);

TopLevelClass serviceImplClazz = new TopLevelClass(

builder.delete(0, builder.length())

.append(serviceImplSuperPackage)

.append(".")

.append(domainObjectName)

.append("ServiceImpl")

.toString()

);

serviceImplClazz.addSuperInterface(implInterfaceType);

serviceImplClazz.setSuperClass(superClazzType);

serviceImplClazz.setVisibility(JavaVisibility.PUBLIC);

serviceImplClazz.addAnnotation("@Service");

FullyQualifiedJavaType baseServiceInstance = FullyQualifiedJavaTypeProxyFactory.getBaseServiceImplInstance();

FullyQualifiedJavaType modelJavaType = new FullyQualifiedJavaType(entityClazzType);

FullyQualifiedJavaType exampleJavaType = new FullyQualifiedJavaType(entityExampleClazzType);

serviceImplClazz

.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));

serviceImplClazz.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));

serviceImplClazz.addImportedType(baseServiceInstance);

serviceImplClazz.addImportedType(modelJavaType);

serviceImplClazz.addImportedType(exampleJavaType);

serviceImplClazz.addImportedType(implInterfaceType);

FullyQualifiedJavaType logType = new FullyQualifiedJavaType("org.slf4j.Logger");

FullyQualifiedJavaType logFactoryType = new FullyQualifiedJavaType("org.slf4j.LoggerFactory");

Field logField = new Field();

logField.setVisibility(JavaVisibility.PRIVATE);

logField.setStatic(true);

logField.setFinal(true);

logField.setType(logType);

logField.setName("logger");

logField.setInitializationString(

builder.delete(0, builder.length())

.append("LoggerFactory.getLogger(")

.append(domainObjectName)

.append("ServiceImpl.class)")

.toString()

);

logField.addAnnotation("");

logField.addAnnotation("@SuppressWarnings("unused")");

serviceImplClazz.addField(logField);

serviceImplClazz.addImportedType(logType);

serviceImplClazz.addImportedType(logFactoryType);

String mapperName = builder.delete(0, builder.length())

.append(Character.toLowerCase(domainObjectName.charAt(0)))

.append(domainObjectName.substring(1))

.append("Mapper")

.toString();

FullyQualifiedJavaType JavaMapperType = new FullyQualifiedJavaType(javaMapperType);

Field mapperField = new Field();

mapperField.setVisibility(JavaVisibility.PUBLIC);

mapperField.setType(JavaMapperType);// Mapper.java

mapperField.setName(mapperName);

mapperField.addAnnotation("@Autowired");

serviceImplClazz.addField(mapperField);

serviceImplClazz.addImportedType(JavaMapperType);

Method mapperMethod = new Method();

mapperMethod.setVisibility(JavaVisibility.PUBLIC);

mapperMethod.setName("setMapper");

mapperMethod.addBodyLine("super.setMapper(" + mapperName + ");");

mapperMethod.addAnnotation("@Autowired");

serviceImplClazz.addMethod(mapperMethod);

serviceImplClazz.addFileCommentLine("/*** copyright (c) 2019 Marvis ***/");

serviceImplClazz

.addImportedType(new FullyQualifiedJavaType("org.springframework.beans.factory.annotation.Autowired"));

this.additionalServiceImplMethods(introspectedTable, serviceImplClazz, mapperName);

return serviceImplClazz;

}

protected void additionalServiceMethods(IntrospectedTable introspectedTable, Interface serviceInterface) {

if (this.notHasBLOBColumns(introspectedTable))

return;

introspectedTable.getGeneratedJavaFiles().stream().filter(file -> file.getCompilationUnit().isJavaInterface()

&& file.getCompilationUnit().getType().getShortName().endsWith("Mapper")).map(GeneratedJavaFile::getCompilationUnit).forEach(

compilationUnit -> ((Interface) compilationUnit).getMethods().forEach(

m -> serviceInterface.addMethod(this.additionalServiceLayerMethod(serviceInterface, m))));

}

protected void additionalServiceImplMethods(IntrospectedTable introspectedTable, TopLevelClass clazz,

String mapperName) {

if (this.notHasBLOBColumns(introspectedTable))

return;

introspectedTable.getGeneratedJavaFiles().stream().filter(file -> file.getCompilationUnit().isJavaInterface()

&& file.getCompilationUnit().getType().getShortName().endsWith("Mapper")).map(GeneratedJavaFile::getCompilationUnit).forEach(

compilationUnit -> ((Interface) compilationUnit).getMethods().forEach(m -> {

Method serviceImplMethod = this.additionalServiceLayerMethod(clazz, m);

serviceImplMethod.addAnnotation("@Override");

serviceImplMethod.addBodyLine(this.generateBodyForServiceImplMethod(mapperName, m));

clazz.addMethod(serviceImplMethod);

}));

}

private boolean notHasBLOBColumns(IntrospectedTable introspectedTable) {

return !introspectedTable.hasBLOBColumns();

}

private Method additionalServiceLayerMethod(CompilationUnit compilation, Method m) {

Method method = new Method();

method.setVisibility(JavaVisibility.PUBLIC);

method.setName(m.getName());

List<Parameter> parameters = m.getParameters();

method.getParameters().addAll(parameters.stream().peek(param -> param.getAnnotations().clear()).collect(Collectors.toList()));

method.setReturnType(m.getReturnType());

compilation.addImportedType(

new FullyQualifiedJavaType(m.getReturnType().getFullyQualifiedNameWithoutTypeParameters()));

return method;

}

private String generateBodyForServiceImplMethod(String mapperName, Method m) {

StringBuilder sbf = new StringBuilder("return ");

sbf.append(mapperName).append(".").append(m.getName()).append("(");

boolean singleParam = true;

for (Parameter parameter : m.getParameters()) {

if (singleParam)

singleParam = !singleParam;

else

sbf.append(", ");

sbf.append(parameter.getName());

}

sbf.append(");");

return sbf.toString();

}

}

4)ContextOverride

package run.override.service;

import java.util.List;

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

import org.mybatis.generator.config.Context;

import org.mybatis.generator.config.ModelType;

public class ContextOverride extends Context{

//添加ServiceGeneratorConfiguration

private ServiceGeneratorConfiguration serviceGeneratorConfiguration;

public ContextOverride(ModelType defaultModelType) {

super(defaultModelType);

}

public ServiceGeneratorConfiguration getServiceGeneratorConfiguration() {

return serviceGeneratorConfiguration;

}

public void setServiceGeneratorConfiguration(ServiceGeneratorConfiguration serviceGeneratorConfiguration) {

this.serviceGeneratorConfiguration = serviceGeneratorConfiguration;

}

@Override

public void validate(List<String> errors) {

if(serviceGeneratorConfiguration != null)

serviceGeneratorConfiguration.validate(errors, this.getId());

super.validate(errors);

}

public XmlElement toXmlElement() {

XmlElement xmlElement = super.toXmlElement();

if (serviceGeneratorConfiguration != null)

xmlElement.addElement(serviceGeneratorConfiguration.toXmlElement());

return xmlElement;

}

}

5)MyBatisGeneratorConfigurationParserOverride

package run.override.service;

import java.util.Properties;

import org.mybatis.generator.config.Configuration;

import org.mybatis.generator.config.Context;

import org.mybatis.generator.config.JavaClientGeneratorConfiguration;

import org.mybatis.generator.config.ModelType;

import org.mybatis.generator.config.PluginConfiguration;

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

import org.mybatis.generator.exception.XMLParserException;

import org.mybatis.generator.internal.util.StringUtility;

import org.w3c.dom.Element;

import org.w3c.dom.Node;

import org.w3c.dom.NodeList;

public class MyBatisGeneratorConfigurationParserOverride extends MyBatisGeneratorConfigurationParser {

public MyBatisGeneratorConfigurationParserOverride(Properties extraProperties) {

super(extraProperties);

}

private void parseJavaServiceGenerator(Context context, Node node) {

ContextOverride contextOverride = ContextOverride.class.cast(context); ////替换Context

ServiceGeneratorConfiguration serviceGeneratorConfiguration = new ServiceGeneratorConfiguration();

contextOverride.setServiceGeneratorConfiguration(serviceGeneratorConfiguration);

Properties attributes = parseAttributes(node);

String targetPackage = attributes.getProperty("targetPackage");

String targetProject = attributes.getProperty("targetProject");

String implementationPackage = attributes.getProperty("implementationPackage");

serviceGeneratorConfiguration.setTargetPackage(targetPackage);

serviceGeneratorConfiguration.setTargetProject(targetProject);

serviceGeneratorConfiguration.setImplementationPackage(implementationPackage);

NodeList nodeList = node.getChildNodes();

for (int i = 0; i < nodeList.getLength(); i++) {

Node childNode = nodeList.item(i);

if (childNode.getNodeType() == Node.ELEMENT_NODE && "property".equals(childNode.getNodeName()))

parseProperty(serviceGeneratorConfiguration, childNode);

}

}

@Override

public Configuration parseConfiguration(Element rootNode) throws XMLParserException {

Configuration configuration = new Configuration();

NodeList nodeList = rootNode.getChildNodes();

for (int i = 0; i < nodeList.getLength(); ++i) {

Node childNode = nodeList.item(i);

if (childNode.getNodeType() != 1) {

continue;

}

if ("properties".equals(childNode.getNodeName()))

parseProperties(configuration, childNode);

else if ("classPathEntry".equals(childNode.getNodeName()))

parseClassPathEntry(configuration, childNode);

else if ("context".equals(childNode.getNodeName())) {

parseContext(configuration, childNode);

}

}

return configuration;

}

private void parseContext(Configuration configuration, Node node) {

Properties attributes = parseAttributes(node);

String defaultModelType = attributes.getProperty("defaultModelType");

String targetRuntime = attributes.getProperty("targetRuntime");

String introspectedColumnImpl = attributes.getProperty("introspectedColumnImpl");

String id = attributes.getProperty("id");

ModelType mt = defaultModelType != null ? ModelType.getModelType(defaultModelType) : null;

Context context = new ContextOverride(mt);

context.setId(id);

if (StringUtility.stringHasValue(introspectedColumnImpl))

context.setIntrospectedColumnImpl(introspectedColumnImpl);

if (StringUtility.stringHasValue(targetRuntime))

context.setTargetRuntime(targetRuntime);

configuration.addContext(context);

NodeList nodeList = node.getChildNodes();

for (int i = 0; i < nodeList.getLength(); i++) {

Node childNode = nodeList.item(i);

if (childNode.getNodeType() != 1)

continue;

if ("property".equals(childNode.getNodeName())) {

parseProperty(context, childNode);

continue;

}

if ("plugin".equals(childNode.getNodeName())) {

parsePlugin(context, childNode);

continue;

}

if ("commentGenerator".equals(childNode.getNodeName())) {

parseCommentGenerator(context, childNode);

continue;

}

if ("jdbcConnection".equals(childNode.getNodeName())) {

parseJdbcConnection(context, childNode);

continue;

}

if ("connectionFactory".equals(childNode.getNodeName())) {

parseConnectionFactory(context, childNode);

continue;

}

if ("javaModelGenerator".equals(childNode.getNodeName())) {

parseJavaModelGenerator(context, childNode);

continue;

}

if ("javaTypeResolver".equals(childNode.getNodeName())) {

parseJavaTypeResolver(context, childNode);

continue;

}

if ("sqlMapGenerator".equals(childNode.getNodeName())) {

parseSqlMapGenerator(context, childNode);

continue;

}

if ("javaClientGenerator".equals(childNode.getNodeName())) {

parseJavaClientGenerator(context, childNode);

continue;

}

if ("javaServiceGenerator".equals(childNode.getNodeName())) {

parseJavaServiceGenerator(context, childNode);

continue;

}

if ("table".equals(childNode.getNodeName()))

parseTable(context, childNode);

}

}

private void parsePlugin(Context context, Node node) {

PluginConfiguration pluginConfiguration = new PluginConfiguration();

context.addPluginConfiguration(pluginConfiguration);

Properties attributes = parseAttributes(node);

String type = attributes.getProperty("type");

pluginConfiguration.setConfigurationType(type);

NodeList nodeList = node.getChildNodes();

for (int i = 0; i < nodeList.getLength(); i++) {

Node childNode = nodeList.item(i);

if (childNode.getNodeType() == 1 && "property".equals(childNode.getNodeName()))

parseProperty(pluginConfiguration, childNode);

}

}

private void parseJavaClientGenerator(Context context, Node node) {

JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();

context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);

Properties attributes = parseAttributes(node);

String type = attributes.getProperty("type");

String targetPackage = attributes.getProperty("targetPackage");

String targetProject = attributes.getProperty("targetProject");

String implementationPackage = attributes.getProperty("implementationPackage");

javaClientGeneratorConfiguration.setConfigurationType(type);

javaClientGeneratorConfiguration.setTargetPackage(targetPackage);

javaClientGeneratorConfiguration.setTargetProject(targetProject);

javaClientGeneratorConfiguration.setImplementationPackage(implementationPackage);

NodeList nodeList = node.getChildNodes();

for (int i = 0; i < nodeList.getLength(); i++) {

Node childNode = nodeList.item(i);

if (childNode.getNodeType() == 1 && "property".equals(childNode.getNodeName()))

parseProperty(javaClientGeneratorConfiguration, childNode);

}

}

}

6)ServiceGeneratorConfiguration

package run.override.service;

import java.util.List;

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

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

import org.mybatis.generator.config.PropertyHolder;

import org.mybatis.generator.internal.util.StringUtility;

import org.mybatis.generator.internal.util.messages.Messages;

public class ServiceGeneratorConfiguration extends PropertyHolder {

private String targetPackage;

private String implementationPackage;

private String targetProject;

/**

*

*/

public ServiceGeneratorConfiguration() {

super();

}

public String getTargetPackage() {

return targetPackage;

}

public void setTargetPackage(String targetPackage) {

this.targetPackage = targetPackage;

}

public String getImplementationPackage() {

return implementationPackage;

}

public void setImplementationPackage(String implementationPackage) {

this.implementationPackage = implementationPackage;

}

public String getTargetProject() {

return targetProject;

}

public void setTargetProject(String targetProject) {

this.targetProject = targetProject;

}

public XmlElement toXmlElement() {

XmlElement answer = new XmlElement("javaServiceGenerator");

if (targetPackage != null) {

answer.addAttribute(new Attribute("targetPackage", targetPackage));

}

if (implementationPackage != null) {

answer.addAttribute(new Attribute("implementationPackage", targetPackage));

}

if (targetProject != null) {

answer.addAttribute(new Attribute("targetProject", targetProject));

}

addPropertyXmlElements(answer);

return answer;

}

@SuppressWarnings({ "rawtypes", "unchecked" })

public void validate(List errors, String contextId) {

if (!StringUtility.stringHasValue(getTargetProject()))

errors.add(Messages.getString("ValidationError.102", contextId));

if (!StringUtility.stringHasValue(getTargetPackage()))

errors.add(Messages.getString("ValidationError.112", "ServiceGenerator", contextId));

if (!StringUtility.stringHasValue(getImplementationPackage()))

errors.add(Messages.getString("ValidationError.120", contextId));

}

}

7)ConfigurationParserOverride

package run.override.service;

import java.io.File;

import java.io.FileReader;

import java.io.IOException;

import java.io.InputStream;

import java.io.Reader;

import java.util.ArrayList;

import java.util.List;

import java.util.Properties;

import javax.xml.parsers.DocumentBuilder;

import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.parsers.ParserConfigurationException;

import org.mybatis.generator.config.Configuration;

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

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

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

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

import org.mybatis.generator.exception.XMLParserException;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import org.xml.sax.InputSource;

import org.xml.sax.SAXException;

import org.xml.sax.SAXParseException;

public class ConfigurationParserOverride extends ConfigurationParser {

private List<String> warnings;

private List<String> parseErrors;

private Properties extraProperties;

public ConfigurationParserOverride(List<String> warnings) {

this(null, warnings);

}

public ConfigurationParserOverride(Properties extraProperties, List<String> warnings) {

super(extraProperties, warnings);

this.extraProperties = extraProperties;

if (warnings == null)

this.warnings = new ArrayList<>();

else {

this.warnings = warnings;

}

this.parseErrors = new ArrayList<>();

}

@Override

public Configuration parseConfiguration(File inputFile) throws IOException, XMLParserException {

FileReader fr = new FileReader(inputFile);

return parseConfiguration(fr);

}

@Override

public Configuration parseConfiguration(InputStream inputStream) throws IOException, XMLParserException {

InputSource is = new InputSource(inputStream);

return parseConfiguration(is);

}

@Override

public Configuration parseConfiguration(Reader reader) throws IOException, XMLParserException {

InputSource is = new InputSource(reader);

return parseConfiguration(is);

}

private Configuration parseConfiguration(InputSource inputSource) throws IOException, XMLParserException {

this.parseErrors.clear();

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

factory.setValidating(true);

try {

DocumentBuilder builder = factory.newDocumentBuilder();

builder.setEntityResolver(new ParserEntityResolver());

ParserErrorHandler handler = new ParserErrorHandler(this.warnings, this.parseErrors);

builder.setErrorHandler(handler);

Document document = null;

try {

document = builder.parse(inputSource);

} catch (SAXParseException e) {

throw new XMLParserException(this.parseErrors);

} catch (SAXException e) {

if (e.getException() == null)

this.parseErrors.add(e.getMessage());

else {

this.parseErrors.add(e.getException().getMessage());

}

}

if (this.parseErrors.size() > 0) {

throw new XMLParserException(this.parseErrors);

}

Element rootNode = document.getDocumentElement();

Configuration config = parseMyBatisGeneratorConfiguration(rootNode);

if (this.parseErrors.size() > 0) {

throw new XMLParserException(this.parseErrors);

}

return config;

} catch (ParserConfigurationException e) {

this.parseErrors.add(e.getMessage());

throw new XMLParserException(this.parseErrors);

}

}

private Configuration parseMyBatisGeneratorConfiguration(Element rootNode) throws XMLParserException {

//替换MyBatisGeneratorConfigurationParser

MyBatisGeneratorConfigurationParser parser = new MyBatisGeneratorConfigurationParserOverride(

this.extraProperties);

return parser.parseConfiguration(rootNode);

}

}

七、PluginChain

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

package run.override;

import run.override.service.ServiceLayerPlugin;

public class PluginChain extends ServiceLayerPlugin {

}

八、generatorConfig.xml

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

1)generatorConfig.xml

<?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的扩展生成代码完成。

来源:宜信技术学院

作者:马伟伟

以上是 代码演示MybatisGenerator扩展自定义生成 的全部内容, 来源链接: utcz.com/z/532382.html

回到顶部