九、整合PageHelper实现分页

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

XML配置方式

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?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配置类方式

完整的配置类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
@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来进行参数传递,实现分页,如下:

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

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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中的各个参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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方法。我们可以通过迭代循环打印出来。如下图:

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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对象源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
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();
}
}

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×