写点什么

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

  • 2020-03-26
  • 本文字数:33589 字

    阅读完需:约 110 分钟

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

Mybatis-Generator 可自动生成 Model、Dao、Mapper 代码,但其自带生成的代码存在以下问题:


  • 生成的注释不是我们想要的,我们期望的是根据数据库表、字段生成不同的注释;

  • 分页代码生成缺失,每个公司的分页方式不同,尤其是老久项目或已发布 API,不能随意变动,那么如何自适应分页代码生成;

  • Mapper.xml 没有 group by 相关代码生成;

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

  • 序列化,mybatis-generator内置了SerializablePlugin,但仅对 Model,并没有对 Example 序列化,在一些开发中是不够的;

  • 对 Service Layer 代码没有生成。


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

1、注释的自定义生成

根据数据库表或字段的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; }}
复制代码

2、分页和分组代码生成

这里,我对 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; }}
复制代码

3、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); }
}
复制代码

4、修正

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

5、序列化自定义扩展

增加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; }}
复制代码

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

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


先对 Service 基类进行介绍。


1)BaseService


package cn.xxx.core.base.service;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import cn.xxx.core.base.model.BaseExample;import cn.xxx.core.base.model.PageInfo;
public interface BaseService<T, Example extends BaseExample, ID> {
long countByExample(Example example);
int deleteByExample(Example example);
int deleteByPrimaryKey(ID id);
int insert(T record);
int insertSelective(T record);
List<T> selectByExample(Example example); /** * return T object * @author Marvis * @date May 23, 2018 11:37:11 AM * @param example * @return */ T selectByCondition(Example example); /** * if pageInfo == null<p/> * then return result of selectByExample(example) * @author Marvis * @date Jul 13, 2017 5:24:35 PM * @param example * @param pageInfo * @return */ List<T> selectByPageExmple(Example example, PageInfo pageInfo);
T selectByPrimaryKey(ID id);
int updateByExampleSelective(@Param("record") T record, @Param("example") Example example);
int updateByExample(@Param("record") T record, @Param("example") Example example);
int updateByPrimaryKeySelective(T record);
int updateByPrimaryKey(T record);}
复制代码


2)BaseServiceImpl


package cn.xxx.core.base.service.impl;
import java.util.List;
import cn.xxx.core.base.dao.BaseMapper;import cn.xxx.core.base.model.BaseExample;import cn.xxx.core.base.model.PageInfo;import cn.xxx.core.base.service.BaseService;
public abstract class BaseServiceImpl<T, Example extends BaseExample, ID> implements BaseService<T, Example, ID> {
private BaseMapper<T, Example, ID> mapper;
public void setMapper(BaseMapper<T, Example, ID> mapper) { this.mapper = mapper; } public long countByExample(Example example) { return mapper.countByExample(example); }
@Override public int deleteByExample(Example example) { return mapper.deleteByExample(example); }
@Override public int deleteByPrimaryKey(ID id) { return mapper.deleteByPrimaryKey(id); }
@Override public int insert(T record) { return mapper.insert(record); }
@Override public int insertSelective(T record) { return mapper.insertSelective(record); }
@Override public List<T> selectByExample(Example example) { return mapper.selectByExample(example); } @Override public T selectByCondition(Example example) { List<T> datas = selectByExample(example); return datas != null && datas.size() == 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); }
}
复制代码

7、PluginChain

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


package run.override;
import run.override.service.ServiceLayerPlugin;public class PluginChain extends ServiceLayerPlugin {}
复制代码

8、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>
复制代码

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


2020-03-26 18:591373

评论

发布
暂无评论
发现更多内容

SpringBoot系列(1)-初识SpringBoot

引花眠

学习 springboot

架构师训练营第 1 期第一次作业

Geek_a01290

极客大学架构师训练营

Java新特性:数据类型可以扔掉了?

王磊

Java 新特性 Java新特性 var 局部类型推导

Java ConcurrentHashMap 高并发安全实现原理解析

vivo互联网技术

Java hashmap 多线程 高并发

# 架构师训练营Week1总结

lggl

极客大学架构师训练营 UML

week-1-part2 学习总结

陈龙

第1周 作业

Pyr0man1ac

架构师第一周笔记

Geek_Gu

ARTS打卡 第17周

引花眠

微服务 ARTS 打卡计划

信任环:口碑传播的关键环节

boshi

用户增长 运营创新

第一周:学习总结

王建军

架构师训练营第一周课程笔记及心得

Airs

架构师训练营第 1 期第一周总结

Geek_a01290

极客大学架构师训练营

第二周 - 框架设计

Arthur云剑

java安全编码指南之:输入校验

程序那些事

java安全编码 安全编码规范 java安全编码指南

智能商业时代的思考(三)数据驱动

刘旭东

大数据 数据驱动 智能商业

科大讯飞再握一国产核心技术,可高精细拾取30分贝超小音量

Talk A.I.

架构师训练营第一周总结

知鱼君

极客大学架构师训练营

第1周 作业

wgl

UML

oeasy 教您玩转linux 010303文件管理器 nautilus

o

早知道这 8 个锦囊,我的程序人生一定更精彩

沉默王二

程序员

腾讯PCG数据中台专场介绍&招聘报名

Geek_c46970

数据中台 腾讯 招聘

课程大作业

小胖子

【架构师训练营1期】第一周作业

诺乐

程序员为什么热衷于造轮子,升职加薪吗?

小傅哥

Java 小傅哥 代码质量 编程开发 编程经验

高效程序员的45个习惯:敏捷开发修炼之道(8)

石云升

敏捷开发 技术分享 轮换制

从linux源码看socket的阻塞和非阻塞

无毁的湖光

Linux TCP socket Linux Kenel

RDS、DDS和GaussDB理不清?看这一篇足够了!

华为云开发者联盟

数据库 华为云 RDS

git 常用操作及 git 工作流介绍

hepingfly

git git分支操作 git工作流

深入理解JVM垃圾回收算法 - 标记清理算法

SkyeDance

GC算法 标记清理 位图标记 懒惰标记

超全面分布式缓存高可用方案:哨兵机制

架构精进之路

redis哨兵模式

代码演示Mybatis-Generator 扩展自定义生成_文化 & 方法_马伟伟_InfoQ精选文章