[JavaWeb] 集成通用 Mapper 与 分页插件PageHelper

MyBatis 工具

这次介绍两个 Mybatis 的两个工具:通用 Mapper 与 分页插件PageHelper

都是 Github 上面的 abel533 作者写的

通用 Mapper

极其方便的使用MyBatis单表的增删改查。(支持单表操作,不支持通用的多表联合查询)

分页插件 - PageHelper

PageHelper 是一款非常方便的分页插件,是物理分页。支持复杂的单表、多表分页。

Maven 引入

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--Mybatis 通用 Mapper -->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper</artifactId>
<version>3.3.7</version>
</dependency>

<!--分页助手-->
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>4.1.6</version>
</dependency>

在 Mybatis 配置中配置拦截器插件

pagehelper 的相关配置

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
<!-- 
plugins在配置文件中的位置必须符合要求,否则会报错,顺序如下:
properties?, settings?,
typeAliases?, typeHandlers?,
objectFactory?,objectWrapperFactory?,
plugins?,
environments?, databaseIdProvider?, mappers?
-->

<plugins>
<!-- com.github.pagehelper为PageHelper类所在包名 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
<!-- 4.0.0以后版本可以不设置该参数 -->
<property name="dialect" value="mysql"/>
<!-- 该参数默认为false -->
<!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 -->
<!-- 和startPage中的pageNum效果一样-->
<property name="offsetAsPageNum" value="true"/>
<!-- 该参数默认为false -->
<!-- 设置为true时,使用RowBounds分页会进行count查询 -->
<property name="rowBoundsWithCount" value="true"/>
<!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 -->
<!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型)-->
<property name="pageSizeZero" value="true"/>
<!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 -->
<!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 -->
<!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 -->
<property name="reasonable" value="false"/>
<!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 -->
<!-- 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 -->
<!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,orderBy,不配置映射的用默认值 -->
<!-- 不理解该含义的前提下,不要随便复制该配置 -->
<property name="params" value="pageNum=pageHelperStart;pageSize=pageHelperRows;"/>
<!-- 支持通过Mapper接口参数来传递分页参数 -->
<property name="supportMethodsArguments" value="false"/>
<!-- always总是返回PageInfo类型,check检查返回类型是否为PageInfo,none返回Page -->
<property name="returnPageInfo" value="none"/>
</plugin>
</plugins>

pagehelper 使用示例

Service 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* 采用 PageHelper 分页
* 紧跟在 PageHelper.startPage 方法后的第一个 Mybatis 查询方法会被进行分页。
* @param country 国家的实体类,Countryname 代表国家的名字
* @param pageNum 页码
* @param pageSize 每页显示数量
* @return
*/

@Override
public List<Country> selectByModelAndPage(Country country, int pageNum, int pageSize) {
CountryExample countryExample = new CountryExample();
CountryExample.Criteria criteria = countryExample.createCriteria();

if (StringUtils.isNotBlank(country.getCountryname())) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append('%').append(country.getCountryname()).append('%');
criteria.andCountrynameLike(stringBuilder.toString());
}
//分页查询 ,紧跟在 PageHelper.startPage 方法后的第一个Mybatis查询方法会被进行分页
PageHelper.startPage(pageNum, pageSize);
return countryMapper.selectByExample(countryExample);
}

Controller 类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Autowired
private CountryService countryService;

private String page_list = "index";

private String redirect_list = "redirect:list";

@RequestMapping(value = {"list", "index", "index.html", ""})
public ModelAndView getList(Country country,
@RequestParam(required = false, defaultValue = "1") int page,

@RequestParam(required = false, defaultValue = "10") int rows) {

ModelAndView result = new ModelAndView(page_list);
List<Country> countryList = countryService.selectByCountry(country, page, rows);
result.addObject("pageInfo", new PageInfo<Country>(countryList));
result.addObject("queryParam", country);
result.addObject("page", page);
result.addObject("rows", rows);
return result;
}

jsp 页面中

可以根据需要获取下列信息

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
${pageInfo.list} 数据 List

当前页号
${pageInfo.pageNum}
页面大小
${pageInfo.pageSize}
起始行号(>=)
${pageInfo.startRow}
终止行号(<=)
${pageInfo.endRow}
总结果数
${pageInfo.total}
总页数
${pageInfo.pages}
第一页
${pageInfo.firstPage}
前一页
${pageInfo.prePage}
下一页
${pageInfo.nextPage}
最后一页
${pageInfo.lastPage}
是否为第一页
${pageInfo.isFirstPage}
是否为最后一页
${pageInfo.isLastPage}
是否有前一页
${pageInfo.hasPreviousPage}
是否有下一页
${pageInfo.hasNextPage}

通用 Mapper 配置

个人在 Spring 的 xml 配置的

1
2
3
4
5
6
7
8
9
10
11
12
<bean class="tk.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.isea533.mybatis.mapper"/>
<!-- 3.2.2版本新特性,markerInterface可以起到mappers配置的作用,详细情况需要看Marker接口类 -->
<property name="markerInterface" value="com.isea533.mybatis.util.MyMapper"/>
<!-- 通用Mapper通过属性注入进行配置,默认不配置时会注册Mapper<T>接口
<property name="properties">
<value>
mappers=tk.mybatis.mapper.common.Mapper
</value>
</property>
-->

</bean>

继承通用的 Mapper,必须指定泛型

公共 Mapper

1
2
3
public interface MyMapper<T> extends Mapper<T>, MySqlMapper<T> {

}

自己的Mapper

1
2
3
public interface CountryMapper extends MyMapper<Country> {

}

Service 中使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Service("countryService")
public class CountryServiceImpl extends BaseService<Country> implements CountryService {
@Override
public List<Country> selectByCountry(Country country, int page, int rows) {
Example example = new Example(Country.class);
Example.Criteria criteria = example.createCriteria();
if (StringUtil.isNotEmpty(country.getCountryname())) {
criteria.andLike("countryname", "%" + country.getCountryname() + "%");
}
if (StringUtil.isNotEmpty(country.getCountrycode())) {
criteria.andLike("countrycode", "%" + country.getCountrycode() + "%");
}
if (country.getId() != null) {
criteria.andEqualTo("id", country.getId());
}
//分页查询
PageHelper.startPage(page, rows);
return selectByExample(example);
}
}

小结

在作者的 Mybatis-Spring 示例项目中自动生成的 Mapper 接口需要手动继承 MyMapper,不然会报错

参考资料