本文提供一種方法,讓MyBatis Generator產生的代碼支持分頁, 適用於MySQL。html
若是要獲取分頁信息,使用MySQL語句,咱們須要怎麼作呢?java
select * from t_user limit 0 , 2
在MySQL系統中,若是要完成一個分頁,咱們須要指定limit的值,也就是須要指定兩個數,第一個指定從什麼地方開始(示例中爲0);另外一個指定須要獲取多少條數據(示例中爲2)。sql
若是要使得產生的自動產生的代碼具有分頁功能的話,那麼,Mapper對應的XML中,select語句須要多增長兩個屬性值,好比:apache
- limitStart (指定從什麼位置開始查找)
- limitSize (指定找到多少條數據)
上述已經提到須要兩個值limitStart和limitSize,那麼,咱們須要添加在哪裏纔能有效果呢?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>
從上述簡單分析能夠看出,limitStart和limitSize添加的地方有兩個:
如
<if test="limitStart != null and limitSize>=0"> limit #{limitStart} , #{limitSize} </if>
有了上述的分析以後,咱們須要寫什麼就很清楚了 。
Example中包含兩個字段limitStart和limitSize,並具備Getter和Setter方法,如:
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的selectByExample和selectByExampleWithBLOBs方法添加limitStart和limitSize屬性。
爲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 >= 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 >= 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:
本篇文章的編寫與以前的幾篇文章有部分聯繫,若是有類內容不知道,請參考以前的兩篇博文;
也能夠直接問我便可。