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 的扩展生成代码完成。
更多内容推荐
探讨丨传统行业必须数字化转型吗?
传统行业是否一定要数字化转型才能活下去,这个问题你说了不算,我说了不算,只有时间才能给出答案。
2023-02-14
15|mBatis:如何将 SQL 语句配置化?
mBatis:如何将SQL语句配置化?
2023-04-14
把 Mybatis Generator 生成的代码加上想要的注释
在日常开发工作中,我们经常用Mybatis Generator根据表结构生成对应的实体类和Mapper文件。但是Mybatis Generator默认生成的代码中,注释并不是我们想要的,所以一般在Generator配置文件中,会设置不自动生成注释。带来的问题就是自动生成代码之后,我们还要
2022-11-22
2023 世界人工智能大会如约而至!低代码开发:点燃数智时代,让 AI 风口助您飞跃
以“智联世界·生成未来”为主题的2023世界人工智能大会将于7月6日至8日在上海举办。这是上海连续第六年举办世界人工智能大会。本次大会由上海市政府和国家发改委、工业和信息化部、科技部、国家网信办、中国科学院、中国工程院、中国科协共同主办。
2023-07-06
Fiori Elements 应用进行二次开发的一个具体案例分享
笔者之前的文章 使用 Fiori Elements 框架创建 UI5 Web 应用,介绍了如何使用 Visual Studio Code,创建 SAP Fiori Elements 应用。 本文介绍如何对该自动生成的应用进行二次开发。
2022-11-18
Altium Designer
Hello,大家好我是泽 En,一起共同学习,多多指教(●'◡'●)
2022-03-26
蚂蚁集团 Service Mesh 进展回顾与展望
继 2019 年的 《蚂蚁集团 Service Mesh 落地实践与挑战》之后,蚂蚁集团在 Service Mesh 方向已经继续探索演进近 3 年,这 3 年里有哪些新的变化,以及对未来的思考是什么,值此 SOFAStack 开源 4 周年之际,欢迎大家一起进入《蚂蚁集团 Service Mesh 进展回
2022-05-17
01|原始 IoC:如何通过 BeanFactory 实现原始版本的 IoC 容器?
用原始的IoC容器来管理一个Bean
2023-03-13
Hango Rider:网易数帆开源 Envoy 企业级自定义扩展框架
目前,Rider扩展框架已经全面开源,并且被集成于开源云原生 API 网关 Hango当中,为 Hango 网关提供了灵活、强大、易用的自定义扩展能力。
2022-02-11
兆骑科创创新创业大赛活动举办,线上直播路演,投融资对接
兆骑科创创新创业大赛活动举办,线上直播路演,投融资对接
2022-08-04
加餐|GPT 编程(上) :如何用 ChatGPT 辅助我们编程?
如何用ChatGPT辅助我们编程?
2023-05-15
33|Schema:如何设计实现 Schema 模块?
Schema是什么?它有什么用?什么时候可以用到它?这节课我们就重点解决这三个问题。
2023-09-04
介绍 16 个让你的代码变漂亮的属性
大家好,我是小鑫同学。一位从事过Android开发、混合开发,现在长期从事前端开发的编程爱好者,我觉得在编程之路上最重要的是知识的分享,所谓三人行必有我师。所以我开始在社区持续输出我所了解到、学习到、工作中遇到的各种编程知识,欢迎有想法、有同感的
2022-08-20
spring 整合 mybatis、springMVC(总结)
实体类pojo类
2022-10-22
07|原始 MVC:如何通过单一的 Servlet 拦截请求分派任务?
通过单一的Servlet拦截请求分派任务
2023-03-27
Java 近期新闻:Classfile API 草案、Spring Boot、GlassFish、Reactor 项目、Micronaut
本期Java新闻综述,内容主要涉及OpenJDK、JDK 19、JDK 20、Spring点版本、GlassFish 7.0.0-M6、GraalVM Native Build Tools 0.9.12。
Tinymce plugins [Tinymce 扩展插件集合]
因为项目需要用到富文本编辑器众多富文本编辑器中,选择了 Tinymce,根据项目需要对Tinymce 进行扩展和增强插件,记录一下,并同时分享给需要帮助的人。
2022-08-03
【Mybatis】如何继承 Mybatis 中的 Mapper.xml 文件
最近在写一个 Mybatis 代码自动生成插件,用的是Mybatis来扩展,其中有一个需求就是 生成javaMapper文件和 xmlMapper文件的时候 希望另外生成一个扩展类和扩展xml文件
2022-10-18
少儿春晚表演
春晚大家一定都看过,但是少儿春晚大家不一定都看过,如果经常看过的我敢肯定你本身有颗童真无邪的心,大多数都是结婚并且已有小孩的,我以前是从来没有关注过少儿春晚,也是自从有了孩子之后,才开始关注的,其实少儿春晚还是非常风趣幽默的,可以时不时勾起
2021-12-06
02|扩展 Bean:如何配置 constructor、property 和 init-method?
配置constructor、property和init-method
2023-03-15
推荐阅读
从典型工具看 SAST 工具的可扩展性实现
2023-08-29
11. AOP 简介与不同框架设计概览
2023-09-26
从 HumanEval 到 CoderEval: 你的代码生成模型真的 work 吗?
2023-12-04
彻底搞懂 Java 继承的五种用法
2023-07-17
6. Mybatis 和 Spring 集成原理剖析
2023-09-25
如何为 3D 模型导入材质贴图
2023-12-12
6、使用自定义 starter 完成案例
2023-09-28
电子书
大厂实战PPT下载
换一换 唐飞虎 | 月之暗面 高级研发工程师 开发者关系负责人
董天成(晟怀) | 蔚来汽车 资深研发工程师
马希民 | 蚂蚁金服 高级技术专家
评论