整合PageHelper實現分頁
由於為了后續使用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
這里由於循環打印才能看到Role對象的真實面部,個人覺得麻煩,所以使用了fastJson格式化為Json,但是發現一個之前沒有留意的問題:
通過上面打印出的結果可以發現,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();
}
}
最后
如果覺得不錯的話,那就關注一下小編哦!一起交流,一起學習