zoukankan      html  css  js  c++  java
  • 一步步学Mybatis-实现简单的分页效果逻辑 (5)

      在前四章中我们已经基本完成了对单表的CRUD与多表联合查询方式的Mybatis操作与配置方式,今天这里要讲的是关于一个业务问题中我们常碰到的分页问题。在开发web项目的时候我们经常会使用到列表显示,一般我们都会用一些常用的列表控件例如,datatables(个人感觉十分不错),easy ui下面的那些封装好的表格控件。

      思路:在这些控件里要达到分页的效果,一般都会传2个参数,第一个是表示当前页的索引(一般从0开始),第二个表示当前页展示多少条业务记录,然后将相应的参数传递给List<T> getList(PagenateArgs args)方法,最终实现数据库中的分页时候我们可以使用limit关键词(针对mysql)进行分页,如果是oracle或者sql server他们都有自带的rownum函数可以使用。

      针对上述思路,首先我们需要还是一如既往的在demo.mybatis.model下面新建一个名为PagenateArgs的分页参数实体类与一个名为SortDirectionEnum的枚举类,里面包含当前页面索引pageIndex, 当前页展示业务记录数pageSize, pageStart属性表示从第几条开始,(pageStart=pageIndex*pageSize)因为limit关键词用法是表示【limit 起始条数(不包含),取几条】,orderFieldStr排序字段,orderDirectionStr 排序方向,所以具体创建如下:

    package david.mybatis.model;
    
    /*
     * 分页参数实体类
     */
    public class PagenateArgs {
        private int pageIndex;
        private int pageSize;
        private int pageStart;
        private String orderFieldStr;
        private String orderDirectionStr;
    
        public PagenateArgs() {
            // TODO Auto-generated constructor stub
        }
    
        public PagenateArgs(int pageIndex, int pageSize, String orderFieldStr, String orderDirectionStr) {
            this.pageIndex = pageIndex;
            this.pageSize = pageSize;
            this.orderFieldStr = orderFieldStr;
            this.orderDirectionStr = orderDirectionStr;
            pageStart = pageIndex * pageSize;
        }
    
        public int getPageIndex() {
            return pageIndex;
        }
    
        public int getPageStart() {
            return pageStart;
        }
    
        public int getPageSize() {
            return pageSize;
        }
    
        public String orderFieldStr() {
            return orderFieldStr;
        }
    
        public String getOrderDirectionStr() {
            return orderDirectionStr;
        }
    }
    PagenateArgs分页参数类
    package david.mybatis.model;
    
    /*
     * 排序枚举
     */
    public enum SortDirectionEnum {
        /*
         * 升序
         */
        ASC,
        
        /*
         * 降序
         */
        DESC
    }
    SQL排序枚举

      完成上面的步骤以后我们在IVisitorOperation接口类中继续添加一个方法public List<Visitor> getListByPagenate(PagenateArgs args),前几章中我们其实已经有getList方法了,这次的分页其实也就是在这个的基础上稍加改动即可,IVisitorOperation接口类改动后如下所示:

    package david.mybatis.demo;
    
    import java.util.List;
    import david.mybatis.model.PagenateArgs;
    import david.mybatis.model.Visitor;
    import david.mybatis.model.VisitorWithRn;
    
    public interface IVisitorOperation {
        /*
         * 基础查询
         */
        public Visitor basicQuery(int id);
    
        /*
         * 添加访问者
         */
        public int add(Visitor visitor);
        
        /*
         * 删除访问者
         */
        public int delete(int id);
        
        /*
         * 更新访问者
         */
        public int update(Visitor visitor);
        
        /*
         * 查询访问者
         */
        public Visitor query(int id);
        
        /*
         * 查询List
         */
        public List<Visitor> getList();
        
        /*
         * 分页查询List
         */
        public List<Visitor> getListByPagenate(PagenateArgs args);    
    }
    修改后的IVisitorOperation

      接下来我们就要开始动手改动我们的VisitorMapper.xml配置文件了,新增一个<select>节点id与参数类型参照前几章的方式配置好,如下此处新增的id就为getListByPagenate,配置好以后如下

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="david.mybatis.demo.IVisitorOperation">
        <!-- useGeneratedKeys="true"代表是否使用自增长序列, keyProperty="Id"指定自增长列是哪一列, parameterType="Visitor"指定IVisitorOperation接口类中定义中所传的相应类型 -->
        <insert id="add" parameterType="Visitor" useGeneratedKeys="true"
            keyProperty="Id">
            insert into Visitor (Name, Email, Status, CreateTime)
            values (#{name}, #{email}, #{status}, #{createTime})
        </insert>
        <delete id="delete" parameterType="int">
            delete from Visitor where
            status>0 and id = #{id}
        </delete>
        <update id="update" parameterType="Visitor">
            update Visitor set Name =
            #{name}, Email=#{email}, Status=#{status} where id=#{id} and Status>0;
        </update>
        <select id="query" parameterType="int" resultType="Visitor">
            select Id,
            Name, Email, Status, CreateTime from visitor where id=#{id} and
            Status>0 order by Id
        </select>
        <select id="basicQuery" parameterType="int" resultType="Visitor">
            select *
            from visitor where id=#{id} and
            Status>0 order by Id
        </select>
        <select id="getList" resultMap="visitorRs">
            <include refid="getListSql" />
        </select>
        <sql id="getListSql">
            select * from Visitor where
            status>0
        </sql>
        <!-- 以下为新增部分用来分页,orderBySql这个提取出来是为了后面有示例复用 -->
        <resultMap type="Visitor" id="visitorRs">
            <id column="Id" property="id" />
            <result column="Name" property="name" />
            <result column="Email" property="email" />
            <result column="Status" property="status" />
            <result column="CreateTime" property="createTime" />
        </resultMap>
        <select id="getListByPagenate" parameterType="PagenateArgs"
            resultType="Visitor">
            select * from (
            <include refid="getListSql" /> <include refid="orderBySql"/>
            ) t <!-- #{}表示参数化输出,${}表示直接输出不进行任何转义操作,自己进行转移 -->
            <if test="pageStart>-1 and pageSize>-1">
                limit #{pageStart}, #{pageSize}
            </if>
        </select>
        <sql id="orderBySql">
            order by ${orderFieldStr} ${orderDirectionStr}
        </sql>
    </mapper>
    修改后的VisitorMapper配置

      在上面你会发现有类似,下图中的配置,这些是属于后面一章会讲述的动态SQL问题,现在可以暂时不管,这里面的字段属性都是针对PagenateArgs参数类中的属性名,保持一致

    <if test="pageStart>-1 and pageSize>-1">
        limit #{pageStart}, #{pageSize}
    </if>

       在DemoRun类中创建测试方法:

    /*
     * 分页参数
     */
    public static void queryVisitorListWithPagenate(int pageIndex, int pageSize, String orderField, String orderDire) {
        PagenateArgs args = new PagenateArgs(pageIndex, pageSize, orderField, orderDire);
        SqlSession session = MybatisUtils.getSqlSession();
        IVisitorOperation vOperation = session.getMapper(IVisitorOperation.class);
        List<Visitor> visitors = vOperation.getListByPagenate(args);
        for (Visitor visitor : visitors) {
            System.out.println(visitor);
        }
        MybatisUtils.closeSession(session);
        MybatisUtils.showMessages(CRUD_Enum.List, visitors.size());
    }
    DemoRun分页
    DemoRun.queryVisitorListWithPagenate(0, 100, "id", SortDirectionEnum.DESC.toString());

    运行后下测试结果,先按Id倒序排列,查的Visitor表一共有14条记录,

    假设我们取在第2页取5条,执行下面也就是6-10条数据,这样传参数就行了

    DemoRun.queryVisitorListWithPagenate(1, 5, "id", SortDirectionEnum.DESC.toString());

    结果如下:

    这样就自己实现了的一个分页逻辑啦~^0^,这里需要注意的就是我这边orderFieldStr字段是没有做过任何判断的,理论上要处理下防止错误了列名传进去,不过现在网上应该有现成封装好的东西,大家也可以去google下,这里只是给个思路演示下怎么用mybatis分页。

      完成这个后,因为是Mysql的关系所以在查询结果里他没有自带rownum序列ID,所以查看测试数据是第几条的时候可能不明显,不zao急,我们可以自己动手丰衣足食改造下上面的方法,这里我重新在model包里新建一个一模一样的VisitorWithRn实体里面多带一个rownum参数持久化返回的RownumID,如下:

    package david.mybatis.model;
    
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class VisitorWithRn {
        private int id;
        private String name;
        private String email;
        private int status;
        private Date createTime;
        private int rownum;
    
        public VisitorWithRn() {
            // TODO Auto-generated constructor stub
            createTime = new Date();
        }
    
        public VisitorWithRn(String name, String email) {
            this.name = name;
            this.email = email;
            this.setStatus(1);
            this.createTime = new Date();
        }
    
        public int getId() {
            return id;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setEmail(String email) {
            this.email = email;
        }
    
        public String getEmail() {
            return email;
        }
    
        public Date getCreateTime() {
            return createTime;
        }
    
        public int getStatus() {
            return status;
        }
    
        public void setStatus(int status) {
            this.status = status;
        }
    
        public int getRownum() {
            return rownum;
        }
    
        public void setRownum(int rownum) {
            this.rownum = rownum;
        }
    
        @Override
        public String toString() {
            // TODO Auto-generated method stub
            return String.format("{Rownum:%d, Id: %d, Name: %s, CreateTime: %s}", rownum, id, name,
                    new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(createTime));
        }
    }
    VisitWithRn

    在IVisitorOperation里面在新建一个名为 public List<VisitorWithRn> getListByPagenateWithRn(PagenateArgs args)的方法,同样我们需要在VisitorMapper中配置下相应<select>节点与脚本,此处唯一的不同就是需要改下sql脚本,如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    <mapper namespace="david.mybatis.demo.IVisitorOperation">
        <!-- useGeneratedKeys="true"代表是否使用自增长序列, keyProperty="Id"指定自增长列是哪一列, parameterType="Visitor"指定IVisitorOperation接口类中定义中所传的相应类型 -->
        <insert id="add" parameterType="Visitor" useGeneratedKeys="true"
            keyProperty="Id">
            insert into Visitor (Name, Email, Status, CreateTime)
            values (#{name}, #{email}, #{status}, #{createTime})
        </insert>
        <delete id="delete" parameterType="int">
            delete from Visitor where
            status>0 and id = #{id}
        </delete>
        <update id="update" parameterType="Visitor">
            update Visitor set Name =
            #{name}, Email=#{email}, Status=#{status} where id=#{id} and Status>0;
        </update>
        <select id="query" parameterType="int" resultType="Visitor">
            select Id,
            Name, Email, Status, CreateTime from visitor where id=#{id} and
            Status>0 order by Id
        </select>
        <select id="basicQuery" parameterType="int" resultType="Visitor">
            select *
            from visitor where id=#{id} and
            Status>0 order by Id
        </select>
        <select id="getList" resultMap="visitorRs">
            <include refid="getListSql" />
        </select>
        <sql id="getListSql">
            select * from Visitor where
            status>0
        </sql>
        <resultMap type="Visitor" id="visitorRs">
            <id column="Id" property="id" />
            <result column="Name" property="name" />
            <result column="Email" property="email" />
            <result column="Status" property="status" />
            <result column="CreateTime" property="createTime" />
        </resultMap>
        <select id="getListByPagenate" parameterType="PagenateArgs"
            resultType="Visitor">
            select * from (
            <include refid="getListSql" /> <include refid="orderBySql"/>
            ) t <!-- #{}表示参数化输出,${}表示直接输出不进行任何转义操作,自己进行转移 -->
            <if test="pageStart>-1 and pageSize>-1">
                limit #{pageStart}, #{pageSize}
            </if>
        </select>
        <!--提炼出来为了2个示例共用下 -->
        <sql id="orderBySql">
            order by ${orderFieldStr} ${orderDirectionStr}
        </sql>
        <!-- 带rownum的SQL脚本书写方式 -->
        <resultMap type="VisitorWithRn" id="visitorWithRnRs">
            <id column="Id" property="id" />
            <result column="Name" property="name" />
            <result column="Email" property="email" />
            <result column="Status" property="status" />
            <result column="CreateTime" property="createTime" />
            <result column="Rownum" property="rownum" />
        </resultMap>
        <select id="getListByPagenateWithRn" resultMap="visitorWithRnRs">
            <!-- #{}表示参数化输出,${}表示直接输出不进行任何转义操作,自己进行转移 -->
            select t.Rownum, t.Id, t.Name, t.Email, t.Status, t.CreateTime from (<include refid="getListSqlContainsRn" /> <include refid="orderBySql"/>) t
            <if test="pageStart>-1 and pageSize>-1">
                limit #{pageStart}, #{pageSize}
            </if>
        </select>
        <sql id="getListSqlContainsRn">
            select @rownum:=@rownum+1 Rownum,
            result.id, result.name, result.email, result.status, result.createTime
            FROM (
            select @rownum:=0, Visitor.* from Visitor where
            status>0) result
        </sql>
    </mapper>
    添加具有Rn效果的配置文件

    接下来剩下的就是如刚才在DemoRun下面添加测试方法,这里就不贴图了,完成后你可以看到刚刚的6-10条数据会变成如下

     今天的东西就讲到这里啦,下一章继续讲述Mybatis里面常用的动态SQL使用方法,希望对园子上的朋友们有帮助~^0^~

  • 相关阅读:
    【今日CV 视觉论文速览】 19 Nov 2018
    【numpy求和】numpy.sum()求和
    【今日CV 视觉论文速览】16 Nov 2018
    【今日CV 视觉论文速览】15 Nov 2018
    poj 2454 Jersey Politics 随机化
    poj 3318 Matrix Multiplication 随机化算法
    hdu 3400 Line belt 三分法
    poj 3301 Texas Trip 三分法
    poj 2976 Dropping tests 0/1分数规划
    poj 3440 Coin Toss 概率问题
  • 原文地址:https://www.cnblogs.com/daviddai/p/3485591.html
Copyright © 2011-2022 走看看