背景

今天在用mybatis写一些单表查询操作业务逻辑时,发现一个简单的查询至少要写三行,如下所示:

DemoCriteria criteria = new DemoCriteria();
criteria.createCriteria().andFiled1EqualTo(filed1Value);
List<Demo> demos = demoMapper.selectByCriteria(criteria);

这样写很累啊,于是想了下能否在一行里搞定呢?

分析

打开DemoCriteria.java,这样找到createCriteriaInternal这个方法:

protected Criteria createCriteriaInternal() {
    Criteria criteria = new Criteria();
    return criteria;
}

这里我应该可以将DemoCriteria对象的引用转入Criteria对象,而Criteria对象的大部分方法已经支持链式操作,这样就可以在一行完成查询操作,如下面代码示例:

protected Criteria createCriteriaInternal() {
    Criteria criteria = new Criteria();
    return criteria;
}

public static class Criteria extends GeneratedCriteria {
    private DemoCriteria topCriteria;

    protected Criteria() {
        super();
    }

    protected Criteria(DemoCriteria topCriteria) {
        super();
        this.topCriteria = topCriteria;
    }

    public DemoCriteria getTopCriteria() {
        return this.topCriteria;
    }
}

// 使用代码示例方法
List<Demo> demos = demoMapper.selectByCriteria(new DemoCriteria().createCriteria().andFiled1EqualTo(filed1Value)getTopCriteria());

编写mybatis-generator插件

因为工程中的Example类都是用mybatis-generator生成出来的,而mybatis-generator并没有自带插件完成这件事,因此自己动手写了个插件,如下代码:

package personal.jeremyxu2010.mybatis.plugins;

import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.PluginAdapter;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.InnerClass;
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 java.util.List;

/**
 * @Description:
 * @Author: jeremyxu
 * @Created Date: 2017/3/20
 * @Created Time: 9:31
 * @Version:1.0
 */
public class ModelExampleBuilderPlugin extends PluginAdapter {
    public boolean validate(List<String> warnings) {
        return true;
    }

    public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
                                              IntrospectedTable introspectedTable) {
        for (Method method : topLevelClass.getMethods()) {
            if("createCriteriaInternal".equals(method.getName())){
                method.getBodyLines().clear();
                method.addBodyLine("Criteria criteria = new Criteria(this);"); //$NON-NLS-1$
                method.addBodyLine("return criteria;"); //$NON-NLS-1$
            }
        }
        for (InnerClass innerClass : topLevelClass.getInnerClasses()) {
            if(new FullyQualifiedJavaType("Criteria").equals(innerClass.getType())){
                Field filed = new Field("topCriteria", topLevelClass.getType());
                filed.setVisibility(JavaVisibility.PRIVATE);
                innerClass.addField(filed);

                Method constructMethod = new Method();
                constructMethod.setVisibility(JavaVisibility.PROTECTED);
                constructMethod.setName("Criteria"); //$NON-NLS-1$
                constructMethod.addParameter(new Parameter(topLevelClass.getType(), "topCriteria"));
                constructMethod.setConstructor(true);
                constructMethod.addBodyLine("super();"); //$NON-NLS-1$
                constructMethod.addBodyLine("this.topCriteria = topCriteria;"); //$NON-NLS-1$
                innerClass.addMethod(constructMethod);

                Method getMethod = new Method();
                getMethod.setVisibility(JavaVisibility.PUBLIC);
                getMethod.setName("getTopCriteria"); //$NON-NLS-1$
                getMethod.setReturnType(topLevelClass.getType());
                getMethod.setConstructor(false);
                getMethod.addBodyLine("return this.topCriteria;"); //$NON-NLS-1$
                innerClass.addMethod(getMethod);
            }
        }
        return true;
    }
}

代码很简单,就不另外说明了。

然后在mybatis-generator的配置文件里加入<plugin type="personal.jeremyxu2010.mybatis.plugins.ModelExampleBuilderPlugin"></plugin>就可以了。

这里值得注意的是PluginAdapter里提供了很多方法供插件来覆盖,开发者可根据自己的需要修改生成的domain objectdomain example objectmapper classmapper xml file,编写插件可参考这里

最后安利一下自己常用的一些mybatis-generator插件,见这里