前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >让MyBatis Generator产生的代码支持分页

让MyBatis Generator产生的代码支持分页

作者头像
孟君
发布2020-02-14 16:15:05
4K0
发布2020-02-14 16:15:05
举报
文章被收录于专栏:孟君的编程札记

本文提供一种方法,让MyBatis Generator产生的代码支持分页, 适用于MySQL。

01

分析

如果要获取分页信息,使用MySQL语句,我们需要怎么做呢?

代码语言:javascript
复制
select * from t_user limit 0 , 2

在MySQL系统中,如果要完成一个分页,我们需要指定limit的值,也就是需要指定两个数,第一个指定从什么地方开始(示例中为0);另一个指定需要获取多少条数据(示例中为2)。

  • 问题转化

如果要使得产生的自动产生的代码具备分页功能的话,那么,Mapper对应的XML中select语句需要多增加两个属性值,比如:

  • limitStart (指定从什么位置开始查找)
  • limitSize (指定找到多少条数据)

上述已经提到需要两个值limitStartlimitSize,那么,我们需要添加在哪里才能有效果呢

  • 何处添加

以t_news表为例,创建表的SQL语句如下:

代码语言:javascript
复制
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来完成的。

代码语言:javascript
复制
    List<News> selectByExampleWithBLOBs(NewsExample example);

    List<News> selectByExample(NewsExample example);

其中,selectByExampleWithBLOBs方法只有当数据表中的某一列需要存储较大内容的时候,才会产生。来看一下判断是否为BLOB列的源代码吧。摘自IntrospectedColumn类。

代码语言:javascript
复制
    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$
    }

注意: 使用selectByExample方法是不会返回BLOB类型的字段,如t_news新闻表中的content内容字段。如果想返回content的值,那么,需要使用selectByExampleWithBLOBs方法。

大家可以来看看如下内容感受一下。selectByExampleWithBLOBs中包含Blob_Column_List,而selectByExample没有。

代码语言:javascript
复制
<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属性。

代码语言:javascript
复制
    <if test="limitStart != null and limitSize&gt;=0">
      limit #{limitStart} , #{limitSize}
    </if>

有了上述的分析之后,我们需要写什么就很清楚了 。

02

编码

  • Example类具有分页属性

Example中包含两个字段limitStartlimitSize,并具有GetterSetter方法,如:

代码语言:javascript
复制
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方法:

代码语言:javascript
复制
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方法的函数,直接调用即可。

代码语言:javascript
复制
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方法,如:

代码语言:javascript
复制
  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产生的方法,如:

代码语言:javascript
复制
  @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

代码语言:javascript
复制
  /**
   * 为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

代码语言:javascript
复制
  /**
   * 为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类完整代码

代码语言:javascript
复制
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。

代码语言:javascript
复制
    <!-- 配置内置的或者自定义的Plugin -->
    <plugin type="my.mabatis.example.plugin.MysqlPaginationPlugin" />

自动产生代码,我们可以看到NewsExample.java以及NewsMapper.xml都具有limitStart和limitSize, 可以支持分页。部分相关代码如下:

代码语言:javascript
复制
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;
    }
    //省略其它
}
代码语言:javascript
复制
 <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>

至此,大功告成。

03

测试

创建一个用于获取分页列表的方法。

代码语言:javascript
复制
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条

代码语言:javascript
复制
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());
  }
}

测试数据一共有三条,所以返回结果是正确的。

代码语言:javascript
复制
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.

Note: 本篇文章的编写与之前的几篇文章有部分联系,如果有类内容不知道,请参考之前的两篇博文; <<使用MyBatis Generator自动生成代码>> <<让MyBatis Generator产生的Mapper更简洁>>

也可以直接问我即可。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 孟君的编程札记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档