概述

根据数据库结构生成MyBatis可以使用的ORM映射文件的工具有很多,当然最著名的是MyBatis官方的项目MyBatis Generator,该工具提供了一个可定制的ORM生成器,可以自定义生成ORM类型(XML还是基于注解)的方式,可以对表/列进行特殊定制,还可以定义数据库支持,基本主流的数据库都进行支持,项目文档也详细说明了各项配置,下面简单说几个比较常用的配置,其余细节可以参阅文档。

generatedKey

<generatedKey column="id" sqlStatement="MySql" identity="true" />

该节点是<table>节点的子节点。

通过该项配置在生成的select语句会生成keyProperty="id"属性,即在调用insert(T t)或者insertSelective(T t)方法后T会在插入成功后同时被设置主键,方便后续进行updateByPrimeryKey(T t)的操作。

suppressDate

<commentGenerator>
<property name="suppressDate" value="false"/>
</commentGenerator>

该节点是<context>的子节点,通过该项设置可以避免生成很多无用的generate by MyBatis generator xxx之类的注解,当然如果使用maven deploy的话有没有注释影响也不是很大。

plugin

<plugin type="gov.sequarius.mybatis.MySQLPaginationPlugin"/>

该节点是<context> 的子节点,为生成器提供的插件支持,也是本文所介绍的重点内容,所谓插件为MyBatis Generator提供的自定义最灵活的地方,通过插件接口可以对生成的类文件、XML文件提供强大的自定义功能。

开发

Plugin与PluginAdapter

关系

插件接口为org.mybatis.generator.api.Plugin当然这是一个最上层的接口,在同层包下提供了org.mybatis.generator.api.PluginAdapter一个适配器,可以看到官方的一些插件(位于org.mybatis。 .generator.plugins包下)基本都继承自这个抽象类,我们这里主要研究的对象也是PluginAdapter

基础方法

首先看下基本方法,对于Plugin的各类方法,PluginAdapter都进行了基础实现,抽象的方法仅仅只有boolean validate(List<String> warnings)一个,看名字可以猜出这是一个校验方法,用于传入warnnings来检查是否插件可用。

普通方法

由于方法众多,故只寻找有代表的两个讲下,更多细节可以参考官方文档。

sqlMap???ElementGenerated(XmlElement element, IntrospectedTable introspectedTable) 该方法在基础XML生成后调用,可以看到入参有XmlElement,拿到XmlElement后就可以操作生成的XML了。

modelExampleClassGenerated(TopLevelClass, IntrospectedTable)该方法在生成modelExample时调用,如果要修改生成的modelExample内容,可以使用TopLevelClass进行反射操作。

剩下的方法基本根据命名规则都可以猜到是干什么,对于类和XML的函数参数都是一样的,只要有参数,就可以进行定制。

实战

使生成的查询列表方法支持分页

public class PagePlug extends PluginAdapter {
@Override
public boolean modelExampleClassGenerated(TopLevelClass topLevelClass, IntrospectedTable introspectedTable)
{
String pageEntityName="page";
topLevelClass.addImportedType(new FullyQualifiedJavaType("cn.bekky.microstore.repository.mapper.page.Page"));
CommentGenerator commentGenerator = context.getCommentGenerator();
Field field = new Field();
field.setVisibility(JavaVisibility.PROTECTED);
field.setType(new FullyQualifiedJavaType("cn.bekky.microstore.repository.mapper.page.Page"));
field.setName(pageEntityName);
commentGenerator.addFieldComment(field, introspectedTable);
topLevelClass.addField(field);
char c = pageEntityName.charAt(0);
String camel = Character.toUpperCase(c) + pageEntityName.substring(1);
Method method = new Method();
method.setVisibility(JavaVisibility.PUBLIC);
method.setName("set" + camel);
method.addParameter(new Parameter(new FullyQualifiedJavaType("cn.bekky.microstore.repository.mapper.page.Page"), pageEntityName));
method.addBodyLine("this." + pageEntityName + "=" + pageEntityName + ";");
commentGenerator.addGeneralMethodComment(method, introspectedTable);
topLevelClass.addMethod(method);
method = new Method();
method.setVisibility(JavaVisibility.PUBLIC);
method.setReturnType(new FullyQualifiedJavaType("cn.bekky.microstore.repository.mapper.page.Page"));
method.setName("get" + camel);
method.addBodyLine("return " + pageEntityName + ";");
commentGenerator.addGeneralMethodComment(method, introspectedTable);
topLevelClass.addMethod(method);
return super.modelExampleClassGenerated(topLevelClass, introspectedTable);
}
@Override
public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable)
{
XmlElement page = new XmlElement("if");
page.addAttribute(new Attribute("test", "page != null"));
page.addElement(new TextElement("limit #{page.begin} , #{page.length}"));
element.addElement(page);
return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);
}
public boolean validate(List<String> warnings)
{
return true;
}
}

create_time和update_time不在update时候更新

public class IgnoreFieldPlug extends PluginAdapter {
@Override
public boolean sqlMapUpdateByExampleSelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
removeTimeAttribute(element);
return super.sqlMapUpdateByExampleSelectiveElementGenerated(element, introspectedTable);
}
@Override
public boolean sqlMapUpdateByPrimaryKeySelectiveElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
removeTimeAttribute(element);
return super.sqlMapUpdateByPrimaryKeySelectiveElementGenerated(element, introspectedTable);
}
@Override
public boolean sqlMapUpdateByExampleWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
// removeTimeTextAttribute(element);
removeTimeTextAttribute(element);
return super.sqlMapUpdateByExampleWithoutBLOBsElementGenerated(element, introspectedTable);
}
@Override
public boolean sqlMapUpdateByPrimaryKeyWithoutBLOBsElementGenerated(XmlElement element, IntrospectedTable introspectedTable) {
removeTimeTextAttribute(element);
return super.sqlMapUpdateByPrimaryKeyWithoutBLOBsElementGenerated(element, introspectedTable);
}
private void removeTimeTextAttribute(XmlElement element) {
List<Element> elements = element.getElements();
int removeCommaIndex=0;
TextElement replaceElement=null;
Iterator<Element> iterator = elements.iterator();
while (iterator.hasNext()){
Element baseElements=elements.get(i);
if (baseElements instanceof TextElement){
TextElement targetElment=(TextElement)baseElements;
if(targetElment.getContent().contains("update_time")||targetElment.getContent().contains("create_time")){
iterator.remove();
}
}
if (baseElements instanceof TextElement){
TextElement targetElment=(TextElement)baseElements;
if(targetElment.getContent().contains("where")){
removeCommaIndex=i-1;
replaceElement=(TextElement)(elements.get(removeCommaIndex));
String content = replaceElement.getContent().trim();
replaceElement=new TextElement(content.substring(0,content.length()-1));
}
}
iterator.next();
}
}
public boolean validate(List<String> warnings)
{
return true;
}
private void removeTimeAttribute(XmlElement element) {
List<Element> elements = element.getElements();
Iterator<Element> iterator = elements.iterator();
while (iterator.hasNext()){
Element baseElements=elements.get(i);
if (!(baseElements instanceof XmlElement)){
continue;
}
XmlElement targetElment=(XmlElement)baseElements;
if(targetElment.getName().contains("set")){
List<Element> innerElements = targetElment.getElements();
for (int i1 = 0; i1 < innerElements.size(); i1++) {
Element baseInnerElements=elements.get(i);
if (!(baseInnerElements instanceof XmlElement)){
continue;
}
targetElment=(XmlElement)innerElements.get(i1);
Iterator<Attribute> attributeIterator = targetElment.getAttributes().iterator();
while (attributeIterator.hasNext()){
attributeIterator.remove();
}
}
}
}
}
}