Mybatis 数据库物理分页插件 PageHelper
以前使用 ibatis/mybatis,都是自己手写 sql 语句进行物理分页,虽然稍微有点麻烦,但是都习惯了。最近试用了下 mybatis 的分页插件 PageHelper, 感觉还不错吧。记录下其使用方法。
1. 引入依赖 jar 包:
<dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>3.7.5</version> </dependency>
2. 配置分页拦截器
PageHelper 的原理是基于拦截器实现的。拦截器的配置有两种方法,一种是在 mybatis 的配置文件中配置,一种是直接在 spring 的配置文件中进行:
1)在 mybatis-config.xml 文件中配置:
<plugins> <!-- com.github.pagehelper 为 PageHelper 类所在包名 --> <plugin interceptor="com.github.pagehelper.PageHelper"> <property name="dialect" value="mysql"/> <!-- 该参数默认为 false --> <!-- 设置为 true 时,会将 RowBounds 第一个参数 offset 当成 pageNum 页码使用 --> <!-- 和 startPage 中的 pageNum 效果一样--> <property name="offsetAsPageNum" value="true"/> <!-- 该参数默认为 false --> <!-- 设置为 true 时,使用 RowBounds 分页会进行 count 查询 --> <property name="rowBoundsWithCount" value="true"/><span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> (相当于没有执行分页查询,但是返回结果仍然是Page类型) <property name="pageSizeZero" value="true"/></span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 3.3.0版本可用 - 分页参数合理化,默认false禁用 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"><</span><span style="color: rgba(128, 0, 0, 1)">property </span><span style="color: rgba(255, 0, 0, 1)">name</span><span style="color: rgba(0, 0, 255, 1)">="reasonable"</span><span style="color: rgba(255, 0, 0, 1)"> value</span><span style="color: rgba(0, 0, 255, 1)">="true"</span><span style="color: rgba(0, 0, 255, 1)">/></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 3.5.0版本可用 - 为了支持startPage(Object params)方法 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值 </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 128, 0, 1)"><!--</span><span style="color: rgba(0, 128, 0, 1)"> 不理解该含义的前提下,不要随便复制该配置 <property name="params" value="pageNum=start;pageSize=limit;"/> </span><span style="color: rgba(0, 128, 0, 1)">--></span> <span style="color: rgba(0, 0, 255, 1)"></</span><span style="color: rgba(128, 0, 0, 1)">plugin</span><span style="color: rgba(0, 0, 255, 1)">></span>
</plugins>
这里要注意 <plugins> 在 mybatis-config.xml 文件中的位置,必须要符合 http://mybatis.org/dtd/mybatis-3-config.dtd 中指定的顺序:
<!ELEMENT configuration (properties?, settings?, typeAliases?, typeHandlers?,
objectFactory?, objectWrapperFactory?, plugins?, environments?, databaseIdProvider?, mappers?)>
不然会报错。
当然 mybatis-config.xml 的位置,我们需要在 spring 的配置文件中进行指定:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation" value="classpath:config/mybatis-config.xml" /> <property name="mapperLocations" value="classpath*:config/mappers/**/*.xml" /> </bean>
2)如果 mybatis 没有 mybatis-config.xml 文件,那么就只能直接在 spring 的配置文件中配置了:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"/> <property name="mapperLocations"> <array> <value>classpath:config/mapper/*.xml</value> </array> </property> <property name="typeAliasesPackage" value="com.test.pojo"/> <property name="plugins"> <array> <bean class="com.github.pagehelper.PageHelper"> <property name="properties"> <value> dialect=mysql </value> </property> </bean> </array> </property> </bean>
到这里 PageHelper 所需要的配置已经完成,下面还需要在 serviceImpl 类中加入分页参数的代码:
3. 向拦截器传递分页参数
我们首先看下不分页的 serviceImpl 代码:
@Override public List<User> getUserByNoAndEmail(String no, String email) { Map<String, Object> map = new HashMap<>(); map.put("no", no); map.put("email", email); return this.userMapper.getUserByNoAndEmail(map); }
然后我们将它改造成使用 PageHelper 分页:
1)首先我们根据自己项目的情况,定义一个 PageBean,来保存分页之后的结果,需要哪些属性,就加入哪些属性,具体可以参考源代码中的 PageInfo 类的定义,其实PageInfo 是插件作者给我们自己定义自己的 PageBean,提供的一个参考例子。PageInfo 代码如下:
@SuppressWarnings({"rawtypes", "unchecked"}) public class PageInfo<T> implements Serializable { private static final long serialVersionUID = 1L; //当前页 private int pageNum; //每页的数量 private int pageSize; //当前页的数量 private int size; //由于 startRow 和 endRow 不常用,这里说个具体的用法 //可以在页面中 "显示 startRow 到 endRow 共 size 条数据"</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当前页面第一个元素在数据库中的行号</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> startRow; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当前页面最后一个元素在数据库中的行号</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> endRow; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">总记录数</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> total; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">总页数</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pages; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">结果集</span> <span style="color: rgba(0, 0, 255, 1)">private</span> List<T><span style="color: rgba(0, 0, 0, 1)"> list; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">第一页</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> firstPage; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">前一页</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> prePage; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">下一页</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> nextPage; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">最后一页</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> lastPage; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">是否为第一页</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> isFirstPage = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">是否为最后一页</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> isLastPage = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">是否有前一页</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> hasPreviousPage = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">是否有下一页</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> hasNextPage = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">导航页码数</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> navigatePages; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">所有导航页号</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">[] navigatepageNums; </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 包装Page对象 * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> list </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> PageInfo(List<T><span style="color: rgba(0, 0, 0, 1)"> list) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>(list, 8<span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 包装Page对象 * * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> list page结果 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> navigatePages 页码数量 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> PageInfo(List<T> list, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> navigatePages) { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (list <span style="color: rgba(0, 0, 255, 1)">instanceof</span><span style="color: rgba(0, 0, 0, 1)"> Page) { Page page </span>=<span style="color: rgba(0, 0, 0, 1)"> (Page) list; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pageNum =<span style="color: rgba(0, 0, 0, 1)"> page.getPageNum(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pageSize =<span style="color: rgba(0, 0, 0, 1)"> page.getPageSize(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.total =<span style="color: rgba(0, 0, 0, 1)"> page.getTotal(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pages =<span style="color: rgba(0, 0, 0, 1)"> page.getPages(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.list =<span style="color: rgba(0, 0, 0, 1)"> page; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.size =<span style="color: rgba(0, 0, 0, 1)"> page.size(); </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">由于结果是>startRow的,所以实际的需要+1</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (<span style="color: rgba(0, 0, 255, 1)">this</span>.size == 0<span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.startRow = 0<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.endRow = 0<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.startRow = page.getStartRow() + 1<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">计算实际的endRow(最后一页的时候特殊)</span> <span style="color: rgba(0, 0, 255, 1)">this</span>.endRow = <span style="color: rgba(0, 0, 255, 1)">this</span>.startRow - 1 + <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.size; } </span><span style="color: rgba(0, 0, 255, 1)">this</span>.navigatePages =<span style="color: rgba(0, 0, 0, 1)"> navigatePages; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">计算导航页</span>
calcNavigatepageNums();
//计算前后页,第一页,最后一页
calcPage();
//判断页面边界
judgePageBoudary();
}
}</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 计算导航页 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> calcNavigatepageNums() { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当总页数小于或等于导航页码数时</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (pages <=<span style="color: rgba(0, 0, 0, 1)"> navigatePages) { navigatepageNums </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">[pages]; </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < pages; i++<span style="color: rgba(0, 0, 0, 1)">) { navigatepageNums[i] </span>= i + 1<span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 0, 255, 1)">else</span> { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">当总页数大于导航页码数时</span> navigatepageNums = <span style="color: rgba(0, 0, 255, 1)">new</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">[navigatePages]; </span><span style="color: rgba(0, 0, 255, 1)">int</span> startNum = pageNum - navigatePages / 2<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">int</span> endNum = pageNum + navigatePages / 2<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 0, 255, 1)">if</span> (startNum < 1<span style="color: rgba(0, 0, 0, 1)">) { startNum </span>= 1<span style="color: rgba(0, 0, 0, 1)">; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">(最前navigatePages页</span> <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < navigatePages; i++<span style="color: rgba(0, 0, 0, 1)">) { navigatepageNums[i] </span>= startNum++<span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (endNum ><span style="color: rgba(0, 0, 0, 1)"> pages) { endNum </span>=<span style="color: rgba(0, 0, 0, 1)"> pages; </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">最后navigatePages页</span> <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = navigatePages - 1; i >= 0; i--<span style="color: rgba(0, 0, 0, 1)">) { navigatepageNums[i] </span>= endNum--<span style="color: rgba(0, 0, 0, 1)">; } } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> { </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">所有中间页</span> <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < navigatePages; i++<span style="color: rgba(0, 0, 0, 1)">) { navigatepageNums[i] </span>= startNum++<span style="color: rgba(0, 0, 0, 1)">; } } } } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 计算前后页,第一页,最后一页 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> calcPage() { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (navigatepageNums != <span style="color: rgba(0, 0, 255, 1)">null</span> && navigatepageNums.length > 0<span style="color: rgba(0, 0, 0, 1)">) { firstPage </span>= navigatepageNums[0<span style="color: rgba(0, 0, 0, 1)">]; lastPage </span>= navigatepageNums[navigatepageNums.length - 1<span style="color: rgba(0, 0, 0, 1)">]; </span><span style="color: rgba(0, 0, 255, 1)">if</span> (pageNum > 1<span style="color: rgba(0, 0, 0, 1)">) { prePage </span>= pageNum - 1<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">if</span> (pageNum <<span style="color: rgba(0, 0, 0, 1)"> pages) { nextPage </span>= pageNum + 1<span style="color: rgba(0, 0, 0, 1)">; } } } </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 判定页面边界 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> judgePageBoudary() { isFirstPage </span>= pageNum == 1<span style="color: rgba(0, 0, 0, 1)">; isLastPage </span>= pageNum ==<span style="color: rgba(0, 0, 0, 1)"> pages; hasPreviousPage </span>= pageNum > 1<span style="color: rgba(0, 0, 0, 1)">; hasNextPage </span>= pageNum <<span style="color: rgba(0, 0, 0, 1)"> pages; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setPageNum(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pageNum) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pageNum =<span style="color: rgba(0, 0, 0, 1)"> pageNum; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPageNum() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> pageNum; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPageSize() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> pageSize; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getSize() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> size; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getStartRow() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> startRow; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getEndRow() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> endRow; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> getTotal() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> total; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPages() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> pages; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> List<T><span style="color: rgba(0, 0, 0, 1)"> getList() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> list; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getFirstPage() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> firstPage; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPrePage() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> prePage; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getNextPage() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> nextPage; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getLastPage() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> lastPage; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> isIsFirstPage() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> isFirstPage; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> isIsLastPage() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> isLastPage; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> isHasPreviousPage() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> hasPreviousPage; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span><span style="color: rgba(0, 0, 0, 1)"> isHasNextPage() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> hasNextPage; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getNavigatePages() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> navigatePages; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)">[] getNavigatepageNums() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> navigatepageNums; } @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString() { </span><span style="color: rgba(0, 0, 255, 1)">final</span> StringBuffer sb = <span style="color: rgba(0, 0, 255, 1)">new</span> StringBuffer("PageInfo{"<span style="color: rgba(0, 0, 0, 1)">); sb.append(</span>"pageNum="<span style="color: rgba(0, 0, 0, 1)">).append(pageNum); sb.append(</span>", pageSize="<span style="color: rgba(0, 0, 0, 1)">).append(pageSize); sb.append(</span>", size="<span style="color: rgba(0, 0, 0, 1)">).append(size); sb.append(</span>", startRow="<span style="color: rgba(0, 0, 0, 1)">).append(startRow); sb.append(</span>", endRow="<span style="color: rgba(0, 0, 0, 1)">).append(endRow); sb.append(</span>", total="<span style="color: rgba(0, 0, 0, 1)">).append(total); sb.append(</span>", pages="<span style="color: rgba(0, 0, 0, 1)">).append(pages); sb.append(</span>", list="<span style="color: rgba(0, 0, 0, 1)">).append(list); sb.append(</span>", firstPage="<span style="color: rgba(0, 0, 0, 1)">).append(firstPage); sb.append(</span>", prePage="<span style="color: rgba(0, 0, 0, 1)">).append(prePage); sb.append(</span>", nextPage="<span style="color: rgba(0, 0, 0, 1)">).append(nextPage); sb.append(</span>", lastPage="<span style="color: rgba(0, 0, 0, 1)">).append(lastPage); sb.append(</span>", isFirstPage="<span style="color: rgba(0, 0, 0, 1)">).append(isFirstPage); sb.append(</span>", isLastPage="<span style="color: rgba(0, 0, 0, 1)">).append(isLastPage); sb.append(</span>", hasPreviousPage="<span style="color: rgba(0, 0, 0, 1)">).append(hasPreviousPage); sb.append(</span>", hasNextPage="<span style="color: rgba(0, 0, 0, 1)">).append(hasNextPage); sb.append(</span>", navigatePages="<span style="color: rgba(0, 0, 0, 1)">).append(navigatePages); sb.append(</span>", navigatepageNums="<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (navigatepageNums == <span style="color: rgba(0, 0, 255, 1)">null</span>) sb.append("null"<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> { sb.append(</span>'['<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i < navigatepageNums.length; ++<span style="color: rgba(0, 0, 0, 1)">i) sb.append(i </span>== 0 ? "" : ", "<span style="color: rgba(0, 0, 0, 1)">).append(navigatepageNums[i]); sb.append(</span>']'<span style="color: rgba(0, 0, 0, 1)">); } sb.append(</span>'}'<span style="color: rgba(0, 0, 0, 1)">); </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> sb.toString(); }
}
因为 PageInfo.java 只是一个示例,所以他定义得有点重量级,属性有点多,我们可以参考它,定义适合我们自己的 PageBean, 比如如下定义:
public class PageBean<T> implements Serializable { private static final long serialVersionUID = 8656597559014685635L; private long total; //总记录数 private List<T> list; //结果集 private int pageNum; // 第几页 private int pageSize; // 每页记录数 private int pages; // 总页数 private int size; // 当前页的数量 <= pageSize,该属性来自 ArrayList 的 size 属性<span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * 包装Page对象,因为直接返回Page对象,在JSON处理以及其他情况下会被当成List来处理, * 而出现一些问题。 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> list page结果 * </span><span style="color: rgba(128, 128, 128, 1)">@param</span><span style="color: rgba(0, 128, 0, 1)"> navigatePages 页码数量 </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> PageBean(List<T><span style="color: rgba(0, 0, 0, 1)"> list) { </span><span style="color: rgba(0, 0, 255, 1)">if</span> (list <span style="color: rgba(0, 0, 255, 1)">instanceof</span><span style="color: rgba(0, 0, 0, 1)"> Page) { Page</span><T> page = (Page<T><span style="color: rgba(0, 0, 0, 1)">) list; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pageNum =<span style="color: rgba(0, 0, 0, 1)"> page.getPageNum(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pageSize =<span style="color: rgba(0, 0, 0, 1)"> page.getPageSize(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.total =<span style="color: rgba(0, 0, 0, 1)"> page.getTotal(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pages =<span style="color: rgba(0, 0, 0, 1)"> page.getPages(); </span><span style="color: rgba(0, 0, 255, 1)">this</span>.list =<span style="color: rgba(0, 0, 0, 1)"> page; </span><span style="color: rgba(0, 0, 255, 1)">this</span>.size =<span style="color: rgba(0, 0, 0, 1)"> page.size(); } } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> getTotal() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> total; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setTotal(<span style="color: rgba(0, 0, 255, 1)">long</span><span style="color: rgba(0, 0, 0, 1)"> total) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.total =<span style="color: rgba(0, 0, 0, 1)"> total; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> List<T><span style="color: rgba(0, 0, 0, 1)"> getList() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> list; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setList(List<T><span style="color: rgba(0, 0, 0, 1)"> list) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.list =<span style="color: rgba(0, 0, 0, 1)"> list; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPageNum() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> pageNum; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setPageNum(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pageNum) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pageNum =<span style="color: rgba(0, 0, 0, 1)"> pageNum; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPageSize() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> pageSize; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setPageSize(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pageSize) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pageSize =<span style="color: rgba(0, 0, 0, 1)"> pageSize; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPages() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> pages; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setPages(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pages) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.pages =<span style="color: rgba(0, 0, 0, 1)"> pages; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getSize() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> size; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setSize(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> size) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.size =<span style="color: rgba(0, 0, 0, 1)"> size; }
}
因为分页查询结果返回的是一个 Page 对象,而 Page 对象继承自 ArrayList,但是如果我们直接返回 ArrayList 的话,在一些场景下回遇到问题,比如在 JSON 处理 Page 类型的结果时,会被当成 List 来 JSON 格式化,会丢弃 Page 对象的所有扩展属性,所以这里我们要将分页的结果 Page 类型转换成我们自己定义的 PageBean. 我们自己定义的 PageBean 没有继承 ArrayList,而是包含一个 List 属性来保存分页结果。所以避免前面的问题。
2)修改 serviceImpl 中的代码:
@Override public PageBean<User> getUserByNoAndEmail(String no, String email) { Map<String, Object> map = new HashMap<>(); map.put("no", no); map.put("email", email);PageHelper.startPage(PaginationContext.getPageNum(), PaginationContext.getPageSize()); List</span><User> list = <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.userMapper.getUserByNoAndEmail(map); </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">new</span> PageBean<User><span style="color: rgba(0, 0, 0, 1)">(list); }</span></pre>
我们只需要使用 PageHelper.startPage(pageNum, pageSize); 函数来指定 pageNum(第几页) 和 pageSize(每页显示几条记录) 两个参数。然后调用原来的查询,就进行了分页。最后将返回的 List,转换成 PageBean 类型的结果即可。前台页面就可以根据 PageBean 中包括的属性来进行分页显示了。
上面的 PaginationContext 是基于 ThreadLocal 来传递分页参数的一个工具类,其实现如下:
public class PaginationContext { // 定义两个 threadLocal 变量:pageNum 和 pageSize private static ThreadLocal<Integer> pageNum = new ThreadLocal<Integer>(); // 保存第几页 private static ThreadLocal<Integer> pageSize = new ThreadLocal<Integer>(); // 保存每页记录条数<span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> * pageNum :get、set、remove </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPageNum() { Integer pn </span>=<span style="color: rgba(0, 0, 0, 1)"> pageNum.get(); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (pn == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">return</span> 0<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> pn; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setPageNum(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pageNumValue) { pageNum.set(pageNumValue); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> removePageNum() { pageNum.remove(); } </span><span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)"> * pageSize :get、set、remove </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getPageSize() { Integer ps </span>=<span style="color: rgba(0, 0, 0, 1)"> pageSize.get(); </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ps == <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">) { </span><span style="color: rgba(0, 0, 255, 1)">return</span> 0<span style="color: rgba(0, 0, 0, 1)">; } </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> ps; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setPageSize(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> pageSizeValue) { pageSize.set(pageSizeValue); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> removePageSize() { pageSize.remove(); }
}
实现了前台页面向 ServiceImpl 中传递分页参数: pageNum 和 pageSize.
当然从请求中获取分页参数 pageNum 和 pageSize 需要用到 filter:
public class PageFilter implements Filter {public PageFilter() {}
public void destroy() {}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
PaginationContext.setPageNum(getPageNum(httpRequest));
PaginationContext.setPageSize(getPageSize(httpRequest));
try {
chain.doFilter(request, response);
}
// 使用完Threadlocal,将其删除。使用finally确保一定将其删除
finally {
PaginationContext.removePageNum();
PaginationContext.removePageSize();
}
}
/**
* 获得pager.offset参数的值
*
* @param request
* @return
*/
protected int getPageNum(HttpServletRequest request) {
int pageNum = 1;
try {
String pageNums = request.getParameter("pageNum");
if (pageNums != null && StringUtils.isNumeric(pageNums)) {
pageNum = Integer.parseInt(pageNums);
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
return pageNum;
}
/**
* 设置默认每页大小
*
* @return
*/
protected int getPageSize(HttpServletRequest request) {
int pageSize = 10; // 默认每页10条记录
try {
String pageSizes = request.getParameter("pageSize");
if (pageSizes != null && StringUtils.isNumeric(pageSizes)) {
pageSize = Integer.parseInt(pageSizes);
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
return pageSize;
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {}
}
PageFilter 在 web.xml 中的配置:
<!-- pagination filter --> <filter> <filter-name>PageFilter</filter-name> <filter-class>com.ems.filter.PageFilter</filter-class> </filter> <filter-mapping> <filter-name>PageFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
OK,到此,PageHelper 的使用方法,基本结束。
PageHelper 项目地址:http://git.oschina.net/free/Mybatis_PageHelper
文档地址:http://git.oschina.net/free/Mybatis_PageHelper/blob/master/wikis/HowToUse.markdown