整合PageHelper实现分页


☞ 博客导航,带你有序的阅读和学习!


文章目录

  • ​​整合PageHelper实现分页​​
  • ​​☞ [博客导航],`带你有序的阅读和学习!`​​
  • ​​XML配置方式​​
  • ​​Java配置类方式​​
  • ​​Page对象源码​​
  • ​​最后​​


由于为了后续使用SpringBoot,本人还是推荐使用Java配置类来操作,但是这里还是提一下XML配置。(本文项目基于第六节Mybatis集成Spring操作)

XML配置方式

使用XML文件来配置Mybatis的PageHelper分页插件:

mybatis-configuration:(mybatis的全局配置文件)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

<!--配置开启自动匹配驼峰-->
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<!--配置PageHelper分页插件拦截器-->
<plugins>
<plugin interceptor="com.github.pagehelper.PageInterceptor">
<property name="offsetAsPageNum" value="true"/>
<property name="helperDialect" value="mysql"/>
<property name="rowBoundsWithCount" value="true"/>
<property name="reasonable" value="true"/>
</plugin>
</plugins>
</configuration>

Java配置类方式

完整的配置类:

@Configuration //标注为一个配置类
@PropertySource(value = "classpath:application.properties") //加载属性文件
@ComponentScan(basePackages = "com.ooyhao.mybatis") //组件扫描
@MapperScan(basePackages = {"com.ooyhao.mybatis.mapper"}) //mapper文件的扫描
@EnableTransactionManagement //开启事务管理
public class AppConfig {

@Value("${jdbc.url}")
private String url;

@Value("${jdbc.driver}")
private String driverClassName;

@Value("${jdbc.username}")
private String username;

@Value("${jdbc.password}")
private String password;

@Value("${mybatis.configuration}")
private String mybatisConfiguration;

@Value("${mybatis.mapperLocations}")
private String mybatisMapperLocations;

@Value("${mybatis.typeAliasesPackage}")
private String mybatisTypeAliasesPackage;

/*配置数据源*/
@Bean
public DataSource dataSource(){
DruidDataSource druidDataSource = new DruidDataSource();
druidDataSource.setUrl(url);
druidDataSource.setDriverClassName(driverClassName);
druidDataSource.setUsername(username);
druidDataSource.setPassword(password);
return druidDataSource;
}

@Bean
public PageInterceptor pageInterceptor(){
PageInterceptor pageInterceptor = new PageInterceptor();
Properties properties = new Properties();
/*4.0.0版本之后可以不用配置*/
properties.setProperty("helperDialect","mysql");
/*默认为false,会将RowBounds第一个参数offset当成pageNum页面使用
* 和startPage中的pageNum效果一样*/
properties.setProperty("offsetAsPageNum","true");
/*RowBounds方式是否做count查询 默认false*/
properties.setProperty("rowBoundsWithCount","true");
/*分页合理化,true开启,如果分页参数不合理会自动修正。默认false不启用*/
properties.setProperty("reasonable","true");
/*是否允许接口方法参数来传递分页参数 默认false*/
properties.setProperty("supportMethodsArguments","true");
pageInterceptor.setProperties(properties);
/*当设置为true的时候,如果pageSize设置为0(或RowBounds的limit=0),就不执行分页*/
properties.setProperty("pageSizeZero","true");
return pageInterceptor;
}

/*Mybatis的全局配置*/
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
/*配置Mybatis的全局配置文件*/
ClassPathResource resource = new ClassPathResource(mybatisConfiguration);
sqlSessionFactoryBean.setConfigLocation(resource);
/*配置Mapper.xml文件的路径*/
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources(mybatisMapperLocations);
sqlSessionFactoryBean.setMapperLocations(resources);
/*配置别名包*/
sqlSessionFactoryBean.setTypeAliasesPackage(mybatisTypeAliasesPackage);
/*设置数据源,位置有要求,需要在下面几项之前*/
sqlSessionFactoryBean.setDataSource(dataSource);
/*将PageHelper分页插件以拦截器的形式配置*/
sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageInterceptor()});
/*配置驼峰命名*/
sqlSessionFactoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
/*配置日志类*/
sqlSessionFactoryBean.getObject().getConfiguration().setLogImpl(StdOutImpl.class);
/*设置开启缓存*/
sqlSessionFactoryBean.getObject().getConfiguration().setCacheEnabled(true);
return sqlSessionFactoryBean;
}

/*配置数据源事务管理器,需要将数据源注入*/
@Bean
public DataSourceTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager =
new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
}

提示

  • 添加了​​PageInterceptor​​ 组件
  • 通过 ​​sqlSessionFactoryBean.setPlugins(new Interceptor[]{pageInterceptor()});​​设置到SqlSessionFactoryBean中

开启了这个​​properties.setProperty("supportMethodsArguments","true");​​则表示可以通过Mapper来进行参数传递,实现分页,如下:

List<Role> findByPage(@Param("pageNum") int pageNum,@Param("pageSize") int pageSize);

xml文件不需要修改,只需要在参数上添加形参即可。

PageHelper的PageInterceptor的参数说明:一下是PageParams类中的setProperties方法的源码:

public void setProperties(Properties properties) {
//offset作为PageNum使用
String offsetAsPageNum = properties.getProperty("offsetAsPageNum");
this.offsetAsPageNum = Boolean.parseBoolean(offsetAsPageNum);
//RowBounds方式是否做count查询
String rowBoundsWithCount = properties.getProperty("rowBoundsWithCount");
this.rowBoundsWithCount = Boolean.parseBoolean(rowBoundsWithCount);
//当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页
String pageSizeZero = properties.getProperty("pageSizeZero");
this.pageSizeZero = Boolean.parseBoolean(pageSizeZero);
//分页合理化,true开启,如果分页参数不合理会自动修正。默认false不启用
String reasonable = properties.getProperty("reasonable");
this.reasonable = Boolean.parseBoolean(reasonable);
//是否支持接口参数来传递分页参数,默认false
String supportMethodsArguments = properties.getProperty("supportMethodsArguments");
this.supportMethodsArguments = Boolean.parseBoolean(supportMethodsArguments);
//默认count列
String countColumn = properties.getProperty("countColumn");
if(StringUtil.isNotEmpty(countColumn)){
this.countColumn = countColumn;
}
//当offsetAsPageNum=false的时候,不能
//参数映射
PageObjectUtil.setParams(properties.getProperty("params"));
}

测试:

下面是测试结果,以及获取PageInfo中的各个参数。

public class AppTest {
AnnotationConfigApplicationContext context = null;
@Before
public void init(){
context = new AnnotationConfigApplicationContext(AppConfig.class);
}

@Test
public void testFindByPage(){

RoleService bean = context.getBean(RoleService.class);
/*是否需要计算总条数*/
List<Role> page = bean.findByPage(2, 2, true);
PageInfo<Role> pageInfo = new PageInfo<>(page);
//返回的是Page对象,Page是ArrayList的子类。由于Page重写了toString方法
List<Role> list = pageInfo.getList();
System.out.println(JSONObject.toJSONString(list));
System.out.println(JSONObject.toJSON(list));
//SQL查询的数据总条数
System.out.println("total:"+pageInfo.getTotal());//22
//总分页数
System.out.println("pages:"+pageInfo.getPages());//8
//自动生成一个分页导航,大小为8(如果满足)[1, 2, 3, 4, 5, 6, 7, 8]
System.out.println("navigatepageNums:"+Arrays.toString(pageInfo.getNavigatepageNums()));
//分页导航的第一页
System.out.println("navigateFirstPage:"+pageInfo.getNavigateFirstPage());//1
//分页导航的最后一页
System.out.println("navigateLastPage:"+pageInfo.getNavigateLastPage());//8
//分页导航的总页数
System.out.println("navigatePages:"+pageInfo.getNavigatePages());//8
//当前页
System.out.println("pageNum:"+pageInfo.getPageNum());//2
//当前页的上一页
System.out.println("prePage:"+pageInfo.getPrePage());//1
//当前页的下一页
System.out.println("nextPage:"+pageInfo.getNextPage());//3
//每页的数据条数
System.out.println("pageSize:"+pageInfo.getPageSize());//3
//当前页的开始行号
System.out.println("startRow:"+pageInfo.getStartRow());//4
//当前页的结束行号
System.out.println("endRow:"+pageInfo.getEndRow());//6
}
}

提示:

List list = pageInfo.getList();我们通过打印这个list对象是无法正常打印出Role对象的数据,是因为Page对象继承自ArrayList,并且重写了toString方法。我们可以通过迭代循环打印出来。如下图:

Mybatis (八) Mybatis整合PageHelper实现分页_sql

这里由于循环打印才能看到Role对象的真实面部,个人觉得麻烦,所以使用了fastJson格式化为Json,但是发现一个之前没有留意的问题:

Mybatis (八) Mybatis整合PageHelper实现分页_System_02

通过上面打印出的结果可以发现,list既然是Page对象,但是我们可以看到Page类中有诸多属性,为何通过JSON格式化工具之后,就没有了呢?通过查询fastJson的toJson源码就可以发现奥秘了,如下:

public static Object toJSON(Object javaObject, SerializeConfig config) {
......
if (javaObject instanceof Collection) {
Collection<Object> collection = (Collection<Object>) javaObject;
JSONArray array = new JSONArray(collection.size());
for (Object item : collection) {
Object jsonValue = toJSON(item, config);
array.add(jsonValue);
}
return array;
}
......
String text = JSON.toJSONString(javaObject);
return JSON.parse(text);
}

里面有这样一个判断,如果对象是Collection或其子类,则强转为Collection,所以我们会发现,在使用JSONObject.toJson或是toJsonString的时候,不管是ArrayList还是Page中的属性都没有了,这是因为取的是Collection。对于数据存储,需要进一步研究Collection系列集合,暂不涉及。

Page对象源码

下面我们看一下Page对象源码:

public class Page<E> extends ArrayList<E> implements Closeable {
private static final long serialVersionUID = 1L;

/**
* 页码,从1开始
*/
private int pageNum;
/**
* 页面大小
*/
private int pageSize;
/**
* 起始行
*/
private int startRow;
/**
* 末行
*/
private int endRow;
/**
* 总数
*/
private long total;
/**
* 总页数
*/
private int pages;
/**
* 包含count查询
*/
private boolean count = true;
/**
* 分页合理化
*/
private Boolean reasonable;
/**
* 当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页,返回全部结果
*/
private Boolean pageSizeZero;
/**
* 进行count查询的列名
*/
private String countColumn;
/**
* 排序
*/
private String orderBy;
/**
* 只增加排序
*/
private boolean orderByOnly;

public Page() {
super();
}

public Page(int pageNum, int pageSize) {
this(pageNum, pageSize, true, null);
}

public Page(int pageNum, int pageSize, boolean count) {
this(pageNum, pageSize, count, null);
}

private Page(int pageNum, int pageSize, boolean count, Boolean reasonable) {
super(0);
if (pageNum == 1 && pageSize == Integer.MAX_VALUE) {
pageSizeZero = true;
pageSize = 0;
}
this.pageNum = pageNum;
this.pageSize = pageSize;
this.count = count;
calculateStartAndEndRow();
setReasonable(reasonable);
}

/**
* int[] rowBounds
* 0 : offset
* 1 : limit
*/
public Page(int[] rowBounds, boolean count) {
super(0);
if (rowBounds[0] == 0 && rowBounds[1] == Integer.MAX_VALUE) {
pageSizeZero = true;
this.pageSize = 0;
} else {
this.pageSize = rowBounds[1];
this.pageNum = rowBounds[1] != 0
? (int) (Math.ceil(((double) rowBounds[0] + rowBounds[1]) / rowBounds[1])) : 0;
}
this.startRow = rowBounds[0];
this.count = count;
this.endRow = this.startRow + rowBounds[1];
}

public List<E> getResult() {
return this;
}

public int getPages() {
return pages;
}

public Page<E> setPages(int pages) {
this.pages = pages;
return this;
}

public int getEndRow() {
return endRow;
}

public Page<E> setEndRow(int endRow) {
this.endRow = endRow;
return this;
}

public int getPageNum() {
return pageNum;
}

public Page<E> setPageNum(int pageNum) {
//分页合理化,针对不合理的页码自动处理
this.pageNum = ((reasonable != null && reasonable) && pageNum <= 0) ? 1 : pageNum;
return this;
}

public int getPageSize() {
return pageSize;
}

public Page<E> setPageSize(int pageSize) {
this.pageSize = pageSize;
return this;
}

public int getStartRow() {
return startRow;
}

public Page<E> setStartRow(int startRow) {
this.startRow = startRow;
return this;
}

public long getTotal() {
return total;
}

public void setTotal(long total) {
this.total = total;
if (total == -1) {
pages = 1;
return;
}
if (pageSize > 0) {
pages = (int) (total / pageSize + ((total % pageSize == 0) ? 0 : 1));
} else {
pages = 0;
}
//分页合理化,针对不合理的页码自动处理
if ((reasonable != null && reasonable) && pageNum > pages) {
pageNum = pages;
calculateStartAndEndRow();
}
}

public Boolean getReasonable() {
return reasonable;
}

public Page<E> setReasonable(Boolean reasonable) {
if (reasonable == null) {
return this;
}
this.reasonable = reasonable;
//分页合理化,针对不合理的页码自动处理
if (this.reasonable && this.pageNum <= 0) {
this.pageNum = 1;
calculateStartAndEndRow();
}
return this;
}

public Boolean getPageSizeZero() {
return pageSizeZero;
}

public Page<E> setPageSizeZero(Boolean pageSizeZero) {
if (pageSizeZero != null) {
this.pageSizeZero = pageSizeZero;
}
return this;
}
public String getOrderBy() {
return orderBy;
}

public <E> Page<E> setOrderBy(String orderBy) {
this.orderBy = orderBy;
return (Page<E>) this;
}

public boolean isOrderByOnly() {
return orderByOnly;
}

public void setOrderByOnly(boolean orderByOnly) {
this.orderByOnly = orderByOnly;
}

/**
* 计算起止行号
*/
private void calculateStartAndEndRow() {
this.startRow = this.pageNum > 0 ? (this.pageNum - 1) * this.pageSize : 0;
this.endRow = this.startRow + this.pageSize * (this.pageNum > 0 ? 1 : 0);
}

public boolean isCount() {
return this.count;
}

public Page<E> setCount(boolean count) {
this.count = count;
return this;
}

/**
* 设置页码
*
* @param pageNum
* @return
*/
public Page<E> pageNum(int pageNum) {
//分页合理化,针对不合理的页码自动处理
this.pageNum = ((reasonable != null && reasonable) && pageNum <= 0) ? 1 : pageNum;
return this;
}

/**
* 设置页面大小
*
* @param pageSize
* @return
*/
public Page<E> pageSize(int pageSize) {
this.pageSize = pageSize;
calculateStartAndEndRow();
return this;
}

/**
* 是否执行count查询
*
* @param count
* @return
*/
public Page<E> count(Boolean count) {
this.count = count;
return this;
}

/**
* 设置合理化
*
* @param reasonable
* @return
*/
public Page<E> reasonable(Boolean reasonable) {
setReasonable(reasonable);
return this;
}

/**
* 当设置为true的时候,如果pagesize设置为0(或RowBounds的limit=0),就不执行分页,返回全部结果
*
* @param pageSizeZero
* @return
*/
public Page<E> pageSizeZero(Boolean pageSizeZero) {
setPageSizeZero(pageSizeZero);
return this;
}

/**
* 指定 count 查询列
*
* @param columnName
* @return
*/
public Page<E> countColumn(String columnName) {
this.countColumn = columnName;
return this;
}


/**
* 转换为PageInfo
*
* @return
*/
public PageInfo<E> toPageInfo() {
PageInfo<E> pageInfo = new PageInfo<E>(this);
return pageInfo;
}

public <E> Page<E> doSelectPage(ISelect select) {
select.doSelect();
return (Page<E>) this;
}

public <E> PageInfo<E> doSelectPageInfo(ISelect select) {
select.doSelect();
return (PageInfo<E>) this.toPageInfo();
}

public long doCount(ISelect select) {
this.pageSizeZero = true;
this.pageSize = 0;
select.doSelect();
return this.total;
}

public String getCountColumn() {
return countColumn;
}

public void setCountColumn(String countColumn) {
this.countColumn = countColumn;
}

@Override
public String toString() {
return "Page{" +
"count=" + count +
", pageNum=" + pageNum +
", pageSize=" + pageSize +
", startRow=" + startRow +
", endRow=" + endRow +
", total=" + total +
", pages=" + pages +
", reasonable=" + reasonable +
", pageSizeZero=" + pageSizeZero +
'}';
}

@Override
public void close() {
PageHelper.clearPage();
}
}

最后

如果觉得不错的话,那就关注一下小编哦!一起交流,一起学习

Mybatis (八) Mybatis整合PageHelper实现分页_PageHelper_03