mybatis框架分页实现,有几种方式,最简单的就是利用原生的sql关键字limit来实现,还有一种就是利用interceptor来拼接sql,实现和limit一样的功能,再一个就是利用PageHelper来实现。这里讲解这三种常见的实现方式:
无论哪种实现方式,我们返回的结果,不能再使用List了,需要一个自定义对象Pager。
package com.xxx.mybatis.bean;
import java.util.List;
public class Pager {
private int page;//分页起始页
private int size;//每页记录数
private List rows;//返回的记录集合
private long total;//总记录条数
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public List getRows() {
return rows;
}
public void setRows(List rows) {
this.rows = rows;
}
public long getTotal() {
return total;
}
public void setTotal(long total) {
this.total = total;
}
}
UserDao.java增加两个方法
public List findByPager(Map params);
public long count();
UserMapper.xml中增加两个查询
UserService.java中增加分页方法
public Pager findByPager(int page,int size){
Map params = new HashMap();
params.put("page", (page-1)*size);
params.put("size", size);
Pager pager = new Pager();
List list = userDao.findByPager(params);
pager.setRows(list);
pager.setTotal(userDao.count());
return pager;
}
这是最直观的实现方式,也是最简单的,不用任何插件或者工具就能够很方便的实现的方法。
需要定义一个类实现Interceptor接口
MyPageInterceptor.java
package com.xxx.mybatis.bean;
import java.sql.Connection;
import java.util.Map;
import java.util.Properties;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class,Integer.class})})
public class MyPageInterceptor implements Interceptor {
private int page;
private int size;
@SuppressWarnings("unused")
private String dbType;
@SuppressWarnings("unchecked")
@Override
public Object intercept(Invocation invocation) throws Throwable {
System.out.println("plugin is running...");
StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
MetaObject metaObject = SystemMetaObject.forObject(statementHandler);
while(metaObject.hasGetter("h")){
Object object = metaObject.getValue("h");
metaObject = SystemMetaObject.forObject(object);
}
while(metaObject.hasGetter("target")){
Object object = metaObject.getValue("target");
metaObject = SystemMetaObject.forObject(object);
}
MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");
String mapId = mappedStatement.getId();
if(mapId.matches(".+ByPager$")){
ParameterHandler parameterHandler = (ParameterHandler)metaObject.getValue("delegate.parameterHandler");
Map params = (Map)parameterHandler.getParameterObject();
page = (int)params.get("page");
size = (int)params.get("size");
String sql = (String) metaObject.getValue("delegate.boundSql.sql");
sql += " limit "+(page-1)*size +","+size;
metaObject.setValue("delegate.boundSql.sql", sql);
}
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
String limit = properties.getProperty("limit","10");
this.page = Integer.parseInt(limit);
this.dbType = properties.getProperty("dbType", "mysql");
}
}
我们之前在service的findByPager方法里面,为了给limit传入两个参数,其中page做了计算,这里使用拦截器的方式就无需计算了:
public Pager findByPager(int page,int size){
Map params = new HashMap();
params.put("page", page);
params.put("size", size);
Pager pager = new Pager();
List list = userDao.findByPager(params);
pager.setRows(list);
pager.setTotal(userDao.count());
return pager;
}
spring配置中,增加plugin设置:
到这里,你也许也猜到了MyPageInterceptor实际上是以一种拦截器的方式在程序执行findByPager方法的时候,对语句会增加limit page,size的拼接,还是和第一种原生实现思路一样,所以这里需要对UserMapper.xml配置文件中的findByPager这个查询对应的语句中的limit #{page},#{size}这部分去掉,变为如下的样子:
至此,通过拦截器插件的方式也实现了分页功能了。
这种方式实现需要我们引入maven依赖。
com.github.pagehelper
pagehelper
4.2.1
spring.xml配置文件做一下修改:
mysql
true
true
count=countSql
service层的方法,做一些修改:
public Pager findByPager(int page,int size){
Pager pager = new Pager();
Page res = PageHelper.startPage(page,size);
userDao.findAll();
pager.setRows(res.getResult());
pager.setTotal(res.getTotal());
return pager;
}
至此,PageHelper工具方法实现分页也实现了。其实PageHelper方法也是第二种使用Interceptor拦截器方式的一种三方实现,它内部帮助我们实现了Interceptor的功能。所以我们不用自定义MyPageInterceptor这个类了。实际上也是在运行查询方法的时候,进行拦截,然后设置分页参数。所以PageHelper.startPage(page,size)这一句需要显示调用,然后再执行userDao.findAll(),在查询所有用户信息的时候,会进行一个分页参数设置,让放回的结果只是分页的结果,而不是全部集合。