讓MyBatis Generator產生的代碼支持分頁

本文提供一種方法,讓MyBatis Generator產生的代碼支持分頁,  適用於MySQL。html

分析

若是要獲取分頁信息,使用MySQL語句,咱們須要怎麼作呢?java

select * from t_user limit 0 , 2

在MySQL系統中,若是要完成一個分頁,咱們須要指定limit的值,也就是須要指定兩個數,第一個指定從什麼地方開始(示例中爲0);另外一個指定須要獲取多少條數據(示例中爲2)。sql

問題轉化

若是要使得產生的自動產生的代碼具有分頁功能的話,那麼,Mapper對應的XML中select語句須要多增長兩個屬性值,好比:apache

  • limitStart (指定從什麼位置開始查找
  • limitSize (指定找到多少條數據

何處添加

上述已經提到須要兩個值limitStartlimitSize,那麼,咱們須要添加在哪裏纔能有效果呢api

以t_news表爲例,建立表的SQL語句以下:session

CREATE TABLE `t_news` (
  `news_id` int(11) NOT NULL AUTO_INCREMENT,
  `title` varchar(150) NOT NULL,
  `content` text NOT NULL,
  `brief_intro` varchar(255) DEFAULT NULL,
  `pic_url` varchar(255) DEFAULT NULL,
  `news_from` varchar(100) DEFAULT NULL,
  `news_author` varchar(50) DEFAULT NULL,
  `news_url` varchar(255) DEFAULT NULL,
  `keywords` varchar(150) DEFAULT NULL,
  `meta_desc` varchar(150) DEFAULT NULL,
  `create_time` datetime DEFAULT NULL,
  PRIMARY KEY (`news_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

那麼,咱們能夠看到NewsMapper.java中查找列表數據都是經過Example來完成的。mybatis

​

    List<News> selectByExampleWithBLOBs(NewsExample example);

    List<News> selectByExample(NewsExample example);

​

其中,selectByExampleWithBLOBs方法只有當數據表中的某一列須要存儲較大內容的時候,纔會產生。來看一下判斷是否爲BLOB列的源代碼吧。摘自IntrospectedColumn類。app

public boolean isBLOBColumn() {
        String typeName = getJdbcTypeName();

        return "BINARY".equals(typeName) || "BLOB".equals(typeName) //$NON-NLS-1$ //$NON-NLS-2$
                || "CLOB".equals(typeName) || "LONGVARBINARY".equals(typeName) //$NON-NLS-1$ //$NON-NLS-2$
                || "LONGVARCHAR".equals(typeName) || "VARBINARY".equals(typeName); //$NON-NLS-1$ //$NON-NLS-2$
    }

注意:dom

使用selectByExample方法是不會返回BLOB類型的字段,如t_news新聞表中的content內容字段。若是想返回content的值,那麼,須要使用selectByExampleWithBLOBs方法。ide

你們能夠來看看以下內容感覺一下。selectByExampleWithBLOBs中包含Blob_Column_List,而selectByExample沒有。

<select id="selectByExampleWithBLOBs" parameterType="my.mybatis.generator.auto.entity.NewsExample" resultMap="ResultMapWithBLOBs">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Wed Nov 09 19:01:57 CST 2016.
    -->
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    ,
    <include refid="Blob_Column_List" />
    from m_news
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
  </select>
  <select id="selectByExample" parameterType="my.mybatis.generator.auto.entity.NewsExample" resultMap="BaseResultMap">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Wed Nov 09 19:01:57 CST 2016.
    -->
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    from m_news
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
  </select>

從上述簡單分析能夠看出,limitStartlimitSize添加的地方有兩個:

  • 實體類對應的Example中須要添加。
  • XML文件中,selectByExampleselectByExampleWithBLOBs配置須要添加limitStartlimitSize屬性。

<if test="limitStart != null and limitSize&gt;=0">
      limit #{limitStart} , #{limitSize}
    </if>

有了上述的分析以後,咱們須要寫什麼就很清楚了 。

編碼

Example類具有分頁屬性

Example中包含兩個字段limitStartlimitSize,並具備GetterSetter方法,如:

public class NewsExample {

    protected Integer limitStart;
  
    protected Integer limitSize;

    public void setLimitStart(Integer limitStart) {
        this.limitStart = limitStart;
    }

    public Integer getLimitStart() {
        return limitStart;
    }

    public void setLimitSize(Integer limitSize) {
        this.limitSize = limitSize;
    }

    public Integer getLimitSize() {
        return limitSize;
    }

    //省略其它
}

增長一個私有方法addLimit用於在Example中建立字段並生成Getter和Setter方法:

private void addLimit(TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable, String name) {
		
		CommentGenerator commentGenerator = context.getCommentGenerator();
		
		/**
		 * 建立成員變量
		 * 如protected Integer limitStart;
		 */
		Field field = new Field();
		field.setVisibility(JavaVisibility.PROTECTED);
		field.setType(PrimitiveTypeWrapper.getIntegerInstance());
		field.setName(name);
		commentGenerator.addFieldComment(field, introspectedTable);
		topLevelClass.addField(field);
		/**
		 * 首字母大寫
		 */
		char c = name.charAt(0);
		String camel = Character.toUpperCase(c) + name.substring(1);

		/**
		 * 添加Setter方法
		 */
		Method method = new Method();
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setName("set" + camel);
		method.addParameter(new Parameter(PrimitiveTypeWrapper
				.getIntegerInstance(), name));

		StringBuilder sb = new StringBuilder();
		sb.append("this.");
		sb.append(name);
		sb.append(" = ");
		sb.append(name);
		sb.append(";");
		/**
		 * 如 this.limitStart = limitStart;
		 */
		method.addBodyLine(sb.toString());

		commentGenerator.addGeneralMethodComment(method, introspectedTable);
		topLevelClass.addMethod(method);

		/**
		 * 添加Getter Method 直接調用AbstractJavaGenerator的getGetter方法
		 */
		Method getterMethod = AbstractJavaGenerator.getGetter(field);
		commentGenerator.addGeneralMethodComment(getterMethod,
				introspectedTable);
		topLevelClass.addMethod(getterMethod);
	}

 

其實,產生上述的代碼並不難,由於MyBatis Generator自己就是在爲生成的實體類添加變量和Getter Setter方法。

如:

AbstractJavaGenerator抽象類自己就有產生Getter方法的函數,直接調用便可。

public abstract class AbstractJavaGenerator extends AbstractGenerator {
    public abstract List<CompilationUnit> getCompilationUnits();

    public static Method getGetter(Field field) {
        Method method = new Method();
        method.setName(getGetterMethodName(field.getName(), field
                .getType()));
        method.setReturnType(field.getType());
        method.setVisibility(JavaVisibility.PUBLIC);
        StringBuilder sb = new StringBuilder();
        sb.append("return "); //$NON-NLS-1$
        sb.append(field.getName());
        sb.append(';');
        method.addBodyLine(sb.toString());
        return method;
    }
}

另外, Setter方法的實現,能夠參考AbstractJavaGenerator抽象類的getJavaBeansSetter方法,如:

public Method getJavaBeansSetter(IntrospectedColumn introspectedColumn) {
        FullyQualifiedJavaType fqjt = introspectedColumn
                .getFullyQualifiedJavaType();
        String property = introspectedColumn.getJavaProperty();

        Method method = new Method();
        method.setVisibility(JavaVisibility.PUBLIC);
        method.setName(getSetterMethodName(property));
        method.addParameter(new Parameter(fqjt, property));
        context.getCommentGenerator().addSetterComment(method,
                introspectedTable, introspectedColumn);

        StringBuilder sb = new StringBuilder();
        if (isTrimStringsEnabled() && introspectedColumn.isStringColumn()) {
            sb.append("this."); //$NON-NLS-1$
            sb.append(property);
            sb.append(" = "); //$NON-NLS-1$
            sb.append(property);
            sb.append(" == null ? null : "); //$NON-NLS-1$
            sb.append(property);
            sb.append(".trim();"); //$NON-NLS-1$
            method.addBodyLine(sb.toString());
        } else {
            sb.append("this."); //$NON-NLS-1$
            sb.append(property);
            sb.append(" = "); //$NON-NLS-1$
            sb.append(property);
            sb.append(';');
            method.addBodyLine(sb.toString());
        }

        return method;
    }

而後,重寫modelExampleClassGenerated產生的方法,如:

@Override
	public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable) {
		addLimit(topLevelClass, introspectedTable, "limitStart");
		addLimit(topLevelClass, introspectedTable, "limitSize");
		return super.modelExampleClassGenerated(topLevelClass,
				introspectedTable);
	}

這樣,Example改變就完成了。

XML文件支持分頁

接下來,咱們須要對產生的XML的selectByExampleselectByExampleWithBLOBs方法添加limitStartlimitSize屬性。

selectByExample添加limitStart和limitSize

/**
	 * 爲selectByExample添加limitStart和limitSize
	 */
	@Override
	public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(
			XmlElement element, IntrospectedTable introspectedTable) {
		XmlElement isNotNullElement = new XmlElement("if");
		isNotNullElement.addAttribute(new Attribute("test",
				"limitStart != null and limitSize >= 0"));
		isNotNullElement.addElement(new TextElement(
				"limit #{limitStart} , #{limitSize}"));
		element.addElement(isNotNullElement);
		return super.sqlMapSelectByExampleWithoutBLOBsElementGenerated(element,
				introspectedTable);
	}

selectByExampleWithBLOBs添加limitStart和limitSize

/**
	 * 爲selectByExampleWithBLOBs添加limitStart和limitSize
	 */
	@Override
	public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(
			XmlElement element, IntrospectedTable introspectedTable) {
		XmlElement isNotNullElement = new XmlElement("if");
		isNotNullElement.addAttribute(new Attribute("test",
				"limitStart != null and limitSize >= 0"));
		isNotNullElement.addElement(new TextElement(
				"limit #{limitStart} , #{limitSize}"));
		element.addElement(isNotNullElement);
		return super.sqlMapSelectByExampleWithBLOBsElementGenerated(element,
				introspectedTable);
	}

MysqlPaginationPlugin類完整代碼

package my.mabatis.example.plugin;

import java.util.List;

import org.mybatis.generator.api.CommentGenerator;
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.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.PrimitiveTypeWrapper;
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 org.mybatis.generator.codegen.AbstractJavaGenerator;

/**
 * MyBatis MySQL自動生成帶分頁插件
 * 
 * @author wangmengjun
 *
 */
public class MysqlPaginationPlugin extends PluginAdapter {

	@Override
	public boolean modelExampleClassGenerated(TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable) {
		addLimit(topLevelClass, introspectedTable, "limitStart");
		addLimit(topLevelClass, introspectedTable, "limitSize");
		return super.modelExampleClassGenerated(topLevelClass,
				introspectedTable);
	}

	/**
	 * 爲selectByExample添加limitStart和limitSize
	 */
	@Override
	public boolean sqlMapSelectByExampleWithoutBLOBsElementGenerated(
			XmlElement element, IntrospectedTable introspectedTable) {
		XmlElement isNotNullElement = new XmlElement("if");
		isNotNullElement.addAttribute(new Attribute("test",
				"limitStart != null and limitSize >= 0"));
		isNotNullElement.addElement(new TextElement(
				"limit #{limitStart} , #{limitSize}"));
		element.addElement(isNotNullElement);
		return super.sqlMapSelectByExampleWithoutBLOBsElementGenerated(element,
				introspectedTable);
	}

	/**
	 * 爲selectByExampleWithBLOBs添加limitStart和limitSize
	 */
	@Override
	public boolean sqlMapSelectByExampleWithBLOBsElementGenerated(
			XmlElement element, IntrospectedTable introspectedTable) {
		XmlElement isNotNullElement = new XmlElement("if");
		isNotNullElement.addAttribute(new Attribute("test",
				"limitStart != null and limitSize >= 0"));
		isNotNullElement.addElement(new TextElement(
				"limit #{limitStart} , #{limitSize}"));
		element.addElement(isNotNullElement);
		return super.sqlMapSelectByExampleWithBLOBsElementGenerated(element,
				introspectedTable);
	}

	private void addLimit(TopLevelClass topLevelClass,
			IntrospectedTable introspectedTable, String name) {

		CommentGenerator commentGenerator = context.getCommentGenerator();

		/**
		 * 建立類成員變量 如protected Integer limitStart;
		 */
		Field field = new Field();
		field.setVisibility(JavaVisibility.PROTECTED);
		field.setType(PrimitiveTypeWrapper.getIntegerInstance());
		field.setName(name);
		commentGenerator.addFieldComment(field, introspectedTable);
		topLevelClass.addField(field);
		/**
		 * 首字母大寫
		 */
		char c = name.charAt(0);
		String camel = Character.toUpperCase(c) + name.substring(1);

		/**
		 * 添加Setter方法
		 */
		Method method = new Method();
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setName("set" + camel);
		method.addParameter(new Parameter(PrimitiveTypeWrapper
				.getIntegerInstance(), name));

		StringBuilder sb = new StringBuilder();
		sb.append("this.");
		sb.append(name);
		sb.append(" = ");
		sb.append(name);
		sb.append(";");
		/**
		 * 如 this.limitStart = limitStart;
		 */
		method.addBodyLine(sb.toString());

		commentGenerator.addGeneralMethodComment(method, introspectedTable);
		topLevelClass.addMethod(method);

		/**
		 * 添加Getter Method 直接調用AbstractJavaGenerator的getGetter方法
		 */
		Method getterMethod = AbstractJavaGenerator.getGetter(field);
		commentGenerator.addGeneralMethodComment(getterMethod,
				introspectedTable);
		topLevelClass.addMethod(getterMethod);
	}

	public boolean validate(List<String> warnings) {
		return true;
	}

}

修改自動產生代碼配置文件generatorConfig.xml中的plugin。

<!-- 配置內置的或者自定義的Plugin -->
		<plugin type="my.mabatis.example.plugin.MysqlPaginationPlugin" />

自動產生代碼,咱們能夠看到NewsExample.java以及NewsMapper.xml都具備limitStart和limitSize, 能夠支持分頁。部分相關代碼以下:

package my.mybatis.generator.auto.entity;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class NewsExample {

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database table m_news
     *
     * @mbggenerated Wed Nov 09 21:39:59 CST 2016
     */
    protected Integer limitStart;

    /**
     * This field was generated by MyBatis Generator.
     * This field corresponds to the database table m_news
     *
     * @mbggenerated Wed Nov 09 21:39:59 CST 2016
     */
    protected Integer limitSize;


    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table m_news
     *
     * @mbggenerated Wed Nov 09 21:39:59 CST 2016
     */
    public void setLimitStart(Integer limitStart) {
        this.limitStart = limitStart;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table m_news
     *
     * @mbggenerated Wed Nov 09 21:39:59 CST 2016
     */
    public Integer getLimitStart() {
        return limitStart;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table m_news
     *
     * @mbggenerated Wed Nov 09 21:39:59 CST 2016
     */
    public void setLimitSize(Integer limitSize) {
        this.limitSize = limitSize;
    }

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table m_news
     *
     * @mbggenerated Wed Nov 09 21:39:59 CST 2016
     */
    public Integer getLimitSize() {
        return limitSize;
    }
    //省略其它
}
<select id="selectByExampleWithBLOBs" parameterType="my.mybatis.generator.auto.entity.NewsExample" resultMap="ResultMapWithBLOBs">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Wed Nov 09 21:39:59 CST 2016.
    -->
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    ,
    <include refid="Blob_Column_List" />
    from m_news
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
    <if test="limitStart != null and limitSize &gt;= 0">
      limit #{limitStart} , #{limitSize}
    </if>
  </select>
  <select id="selectByExample" parameterType="my.mybatis.generator.auto.entity.NewsExample" resultMap="BaseResultMap">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
      This element was generated on Wed Nov 09 21:39:59 CST 2016.
    -->
    select
    <if test="distinct">
      distinct
    </if>
    <include refid="Base_Column_List" />
    from m_news
    <if test="_parameter != null">
      <include refid="Example_Where_Clause" />
    </if>
    <if test="orderByClause != null">
      order by ${orderByClause}
    </if>
    <if test="limitStart != null and limitSize &gt;= 0">
      limit #{limitStart} , #{limitSize}
    </if>
  </select>

至此,大功告成。

測試驗證

建立一個用於獲取分頁列表的方法。

package my.mabatis.example.service;

import java.util.List;

import my.mabatis.example.util.MyBatisUtil;
import my.mybatis.generator.auto.dao.UserMapper;
import my.mybatis.generator.auto.entity.User;
import my.mybatis.generator.auto.entity.UserExample;
import my.mybatis.generator.auto.entity.UserExample.Criteria;

import org.apache.ibatis.session.SqlSession;

/**
 * 
 * @author wangmengjun
 *
 */
public class UserService {

	/**
	 * 查找分頁列表
	 */
	public List<User> selectNewsByPage(int pageNo, int pageSize) {

		SqlSession sqlSession = MyBatisUtil.getSqlSessionFactory()
				.openSession();
		try {
			UserMapper userDao = sqlSession.getMapper(UserMapper.class);
			/**
			 * 使用Example來操做
			 */
			UserExample example = new UserExample();
			/**
			 * 設置limitStart和limitSize
			 */
			example.setLimitStart((pageNo - 1) * pageSize);
			example.setLimitSize(pageSize);
			return userDao.selectByExample(example);
		} finally {
			sqlSession.close();
		}
	}

}

寫一個測試類,獲取第一頁數據,一頁5條。

package my.mabatis.example.runner;

import java.util.List;

import my.mabatis.example.service.UserService;
import my.mybatis.generator.auto.entity.User;

public class Test {

	public static void main(String[] args) {
		UserService userService = new UserService();
		/**
		 * 獲取第一頁的數據, 一頁5條數據
		 */
		List<User> users = userService.selectNewsByPage(1, 5);
		System.out.println(users.size());
	}
}

測試數據一共有三條,因此返回結果是正確的。

log4j:WARN No appenders could be found for logger (org.apache.ibatis.logging.LogFactory).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
3

若有疑問

Note:

本篇文章的編寫與以前的幾篇文章有部分聯繫,若是有類內容不知道,請參考以前的兩篇博文;

<<使用MyBatis Generator自動生成代碼>>

<<讓MyBatis Generator產生的Mapper更簡潔>>

也能夠直接問我便可。

相關文章
相關標籤/搜索