https://github.com/miemiedev/mybatis-paginator
写了一个Mybatis分页控件,在这记录一下使用方式。
在Maven中加入依赖:
1
2
3
4
5
6
7
8
9
|
<
dependencies
>
...
<
dependency
>
<
groupId
>com.github.miemiedev</
groupId
>
<
artifactId
>mybatis-paginator</
artifactId
>
<
version
>1.2.17</
version
>
</
dependency
>
...
</
dependencies
>
|
Mybatis配置文件添加分页插件:
1
2
3
4
5
6
7
8
9
10
11
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<!
DOCTYPE
configuration
PUBLIC "-//ibatis.apache.org//DTD Config 3.0//EN"
"http://ibatis.apache.org/dtd/ibatis-3-config.dtd">
<
configuration
>
<
plugins
>
<
plugin
interceptor
=
"com.github.miemiedev.mybatis.paginator.OffsetLimitInterceptor"
>
<
property
name
=
"dialectClass"
value
=
"com.github.miemiedev.mybatis.paginator.dialect.OracleDialect"
/>
</
plugin
>
</
plugins
>
</
configuration
>
|
创建一个查询,内容可以是任何Mybatis表达式,包括foreach和if等:
1
2
3
|
<
select
id
=
"findByCity"
resultType
=
"map"
>
select * from TEST_USER where city = #{city};
</
select
>
|
Dao中的方法或许是这样(用接口也是类似):
1
2
3
4
5
6
7
|
public
List findByCity(String city, PageBounds pageBounds){
Map<String, Object> params =
new
HashMap<String, Object>();
params.put(
"city"
,city);
return
getSqlSession().selectList(
"db.table.user.findByCity"
, params, pageBounds);
}
|
调用方式(分页加多列排序):
1
2
3
4
5
6
7
8
9
|
int
page =
1
;
//页号
int
pageSize =
20
;
//每页数据条数
String sortString =
"age.asc,gender.desc"
;
//如果你想排序的话逗号分隔可以排序多列
PageBounds pageBounds =
new
PageBounds(page, pageSize , Order.formString(sortString));
List list = findByCity(
"BeiJing"
,pageBounds);
//获得结果集条总数
PageList pageList = (PageList)list;
System.out.println(
"totalCount: "
+ pageList.getPaginator().getTotalCount());
|
PageList类是继承于ArrayList的,这样Dao中就不用为了专门分页再多写一个方法。
使用PageBounds这个对象来控制结果的输出,常用的使用方式一般都可以通过构造函数来配置。
1
2
3
4
5
6
7
|
new
PageBounds();
//默认构造函数不提供分页,返回ArrayList
new
PageBounds(
int
limit);
//取TOPN操作,返回ArrayList
new
PageBounds(Order... order);
//只排序不分页,返回ArrayList
new
PageBounds(
int
page,
int
limit);
//默认分页,返回PageList
new
PageBounds(
int
page,
int
limit, Order... order);
//分页加排序,返回PageList
new
PageBounds(
int
page,
int
limit, List<Order> orders,
boolean
containsTotalCount);
//使用containsTotalCount来决定查不查询totalCount,即返回ArrayList还是PageList
|
=========================================
如果用的是Spring MVC的话可以把JSON的配置写成这样:
1
2
3
4
5
6
7
8
9
10
11
12
|
<
mvc:annotation-driven
>
<
mvc:message-converters
register-defaults
=
"true"
>
<
bean
class
=
"org.springframework.http.converter.StringHttpMessageConverter"
>
<
constructor-arg
value
=
"UTF-8"
/>
</
bean
>
<
bean
class
=
"org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"
>
<
property
name
=
"objectMapper"
>
<
bean
class
=
"com.github.miemiedev.mybatis.paginator.jackson2.PageListJsonMapper"
/>
</
property
>
</
bean
>
</
mvc:message-converters
>
</
mvc:annotation-driven
>
|
那么在Controller就可以这样用了:
1
2
3
4
5
6
7
8
9
|
@ResponseBody
@RequestMapping
(value =
"/findByCity.json"
)
public
List findByCity(
@RequestParam
String city,
@RequestParam
(required =
false
,defaultValue =
"1"
)
int
page,
@RequestParam
(required =
false
,defaultValue =
"30"
)
int
limit,
@RequestParam
(required =
false
) String sort,
@RequestParam
(required =
false
) String dir) {
return
userService.findByCity(city,
new
PageBounds(page, limit, Order.create(sort,dir)));
}
|
然后序列化后的JSON字符串就会变成这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
{
"items"
:[
{
"NAME"
:
"xiaoma"
,
"AGE"
:30,
"GENDER"
:1,
"ID"
:3,
"CITY"
:
"BeiJing"
},
{
"NAME"
:
"xiaoli"
,
"AGE"
:30,
"SCORE"
:85,
"GENDER"
:1,
"ID"
:1,
"CITY"
:
"BeiJing"
},
{
"NAME"
:
"xiaowang"
,
"AGE"
:30,
"SCORE"
:92,
"GENDER"
:0,
"ID"
:2,
"CITY"
:
"BeiJing"
},
{
"NAME"
:
"xiaoshao"
,
"AGE"
:30,
"SCORE"
:99,
"GENDER"
:0,
"ID"
:4,
"CITY"
:
"BeiJing"
}
],
"slider"
: [1, 2, 3, 4, 5, 6, 7],
"hasPrePage"
:
false
,
"startRow"
: 1,
"offset"
: 0,
"lastPage"
:
false
,
"prePage"
: 1,
"hasNextPage"
:
true
,
"nextPage"
: 2,
"endRow"
: 30,
"totalCount"
: 40351,
"firstPage"
:
true
,
"totalPages"
: 1346,
"limit"
: 30,
"page"
: 1
}
|
=========================================
在SpringMVC中使用JSTL的话可以参考一下步骤(懒人用法)
在Spring配置文件中加入拦截器,或则参考拦截器实现定义自己的拦截器
1
2
3
4
5
6
|
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path=
"/**"
/>
<bean
class
=
"com.github.miemiedev.mybatis.paginator.springmvc.PageListAttrHandlerInterceptor"
/>
</mvc:interceptor>
</mvc:interceptors>
|
然后Controller方法可以这样写
1
2
3
4
5
6
7
8
9
|
@RequestMapping
(value =
"/userView.action"
)
public
ModelAndView userView(
@RequestParam
String city,
@RequestParam
(required =
false
,defaultValue =
"1"
)
int
page,
@RequestParam
(required =
false
,defaultValue =
"30"
)
int
limit,
@RequestParam
(required =
false
) String sort,
@RequestParam
(required =
false
) String dir) {
List users = userService.findByCity(city,
new
PageBounds(page, limit, Order.create(sort,dir)));
return
new
ModelAndView(
"account/user"
,
"users"
, users);
}
|
JSP中就可以这样用了,拦截器会将PageList分拆添加Paginator属性,默认命名规则为"原属性名称"+"Paginator"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<table>
<c:forEach items=
"${users}"
var=
"user"
>
<tr>
<td>${user[
'ID'
]}</td>
<td>${user[
'NAME'
]}</td>
<td>${user[
'AGE'
]}</td>
</tr>
</c:forEach>
</table>
上一页: ${usersPaginator.prePage}
当前页: ${usersPaginator.page}
下一页: ${usersPaginator.nextPage}
总页数: ${usersPaginator.totalPages}
总条数: ${usersPaginator.totalCount}
更多属性参考Paginator类提供的方法
|
=========================================
如果用如下方法设置pageBounds,当前这个查询就可以用两个线程同时查询list和totalCount了
1
|
pageBounds.setAsyncTotalCount(true);
|
如果所有的分页查询都是用异步的方式查询list和totalCount,可以在插件配置加入asyncTotalCount属性
1
2
3
4
|
<
plugin
interceptor
=
"com.github.miemiedev.mybatis.paginator.OffsetLimitInterceptor"
>
<
property
name
=
"dialectClass"
value
=
"com.github.miemiedev.mybatis.paginator.dialect.OracleDialect"
/>
<
property
name
=
"asyncTotalCount"
value
=
"true"
/>
</
plugin
>
|
但是你仍然可以用下面代码强制让这个查询不用异步
1
|
pageBounds.setAsyncTotalCount(false);
|
当然需要注意的是,只要你用到了异步查询,由于里面使用了线程池,所以在使用时就要加入清理监听器,以便在停止服务时关闭线程池。需要在web.xml中加入
1
2
3
|
<
listener
>
<
listener-class
>com.github.miemiedev.mybatis.paginator.CleanupMybatisPaginatorListener</
listener-class
>
</
listener
>
|
完。