MyPages是Java实现基于MyBatis的开源分页插件,最大程度简化数据库分页查询操作,支持市面上大部分数据库,如:MySQL、PostgreSQL、Oracle、SQLServer等。
请确保您的Java版本在1.8及以上。
<dependency>
<groupId>io.leego</groupId>
<artifactId>mypages</artifactId>
<version>${mypages.version}</version>
</dependency>
假设存在基于MySQL
的数据库和表:
create database mypages;
use mypages;
create table user
(
id bigint primary key auto_increment,
username varchar(20),
password varchar(40),
nickname varchar(20),
status tinyint default 1
);
假设存在如下定义的Mapper:
public interface UserMapper {
@Select("select * from user")
List<User> query(@Param("page") Integer page, @Param("size") Integer size);
}
public void query() {
DataSource dataSource = dataSource();
SqlSessionFactory sqlSessionFactory = sqlSessionFactory(dataSource);
try (SqlSession session = sqlSessionFactory.openSession(false)) {
UserMapper userMapper = session.getMapper(UserMapper.class);
List<User> list = userMapper.query(1, 10);
Page<User> page = Page.of(list);
}
}
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setJdbcUrl("jdbc:mysql://localhost:3306/mypages?serverTimezone=GMT%2B8");
config.setUsername("root");
config.setPassword("123456");
return new HikariDataSource(config);
}
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) {
TransactionFactory transactionFactory = new JdbcTransactionFactory();
Environment environment = new Environment(SqlSessionFactory.class.getSimpleName(), transactionFactory, dataSource);
Configuration configuration = new Configuration(environment);
configuration.setMapUnderscoreToCamelCase(true);
configuration.addMapper(UserMapper.class);
configuration.addInterceptor(paginationInterceptor(dataSource));
return new SqlSessionFactoryBuilder().build(configuration);
}
public PaginationInterceptor paginationInterceptor(DataSource dataSource) {
PaginationSettings settings = PaginationSettings.builder()
.database(Database.fromDataSource(dataSource))
.pageField("page")
.sizeField("size")
.build();
return new PaginationInterceptor(settings);
}
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/mypages?serverTimezone=GMT%2B8"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<bean id="paginationInterceptor" class="io.leego.mypages.interceptor.PaginationInterceptor">
<constructor-arg name="settings">
<bean class="io.leego.mypages.interceptor.PaginationSettings">
<property name="database" value="MYSQL"/>
<property name="pageField" value="page"/>
<property name="sizeField" value="size"/>
</bean>
</constructor-arg>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="plugins" ref="paginationInterceptor"/>
</bean>
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Page<User> query(int page, int size) {
List<User> list = userMapper.query(page, size);
return Page.of(list);
}
}
@Configuration
public class MybatisConfiguration {
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
Interceptor[] plugins = new Interceptor[]{paginationInterceptor(dataSource)};
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
sqlSessionFactoryBean.setPlugins(plugins);
return sqlSessionFactoryBean.getObject();
}
@Bean
public PaginationInterceptor paginationInterceptor(DataSource dataSource) {
PaginationSettings settings = PaginationSettings.builder()
.database(Database.fromDataSource(dataSource))
.pageField("page")
.sizeField("size")
.build();
return new PaginationInterceptor(settings);
}
}
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Page<User> query(int page, int size) {
List<User> list = userMapper.query(page, size);
return Page.of(list);
}
}
使用 @Pagination
、@Page
、@Size
、@Offset
、@Rows
等注解.
@Pagination
public class QueryParam {
@Page
private Integer page;
@Size
private Integer size;
@Offset
private Integer offset;
@Rows
private Integer rows;
/* getter setter */
}
更多注解: @CountExpr
、@CountMethodName
、@DisableCount
、@DisablePagination
通过反射获取分页参数
PaginationSettings settings = PaginationSettings.builder()
.database(Database.MYSQL)
.pageField("page")
.sizeField("size")
.build();
PaginationInterceptor interceptor = new PaginationInterceptor(settings);
假设存在如下定义的类和Mapper:
public class QueryParam {
private Integer page;
private Integer size;
public QueryParam(Integer page, Integer size) {
this.page = page;
this.size = size;
}
/* getter setter */
}
public interface UserMapper {
@Select("SELECT * FROM user")
List<User> query(QueryParam param);
}
假设存在如下定义的Mapper:
public interface UserMapper {
@Select("SELECT * FROM user")
List<User> query(@Param("page") Integer page, @Param("size") Integer size);
}
假设存在如下定义的Mapper:
public interface UserMapper {
@Select("SELECT * FROM user")
List<User> query(Map map);
}
调用查询方法:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Page<User> query() {
Map<String, Object> map = new HashMap<>();
map.put("size", 1);
map.put("page", 10);
return Page.of(userMapper.query(map));
}
}
PaginationSettings settings = PaginationSettings.builder()
.database(Database.MYSQL) // 指定数据库类型,如:`MySQL`、`PostgreSQL`、`Oracle`等
.countExpr("*") // 设置count表达式,默认值为`*`
.pageField("page") // 从参数字段中获取`page`值
.sizeField("size") // 从参数字段中获取`size`值
.offsetField("offset") // 从参数字段中获取`offset`值
.rowsField("rows") // 从参数字段中获取`rows`值
.countExprField("countExpr") // 从参数字段中获取count表达式
.countMethodNameField("countMethodName") // 从参数字段中获取自定义count方法名称
.enableCountField("enableCount") // 从参数字段中判断是否启用count
.skipQueryIfCountEqualsZero(true) // 是否跳过查询如果结果数量为`0`
.useGeneratedIfCountMethodIsMissing(true) // 是否使用自动生成的count方法如果指定count方法不存在
.useGracefulCountSql(true) // 是否使用优雅的Count-SQL
.keepSorting(false) // 是否保留排序
.defaultPage(1) // 如果`page`为空或小于`1`,则用`default-page`替换`page`
.defaultSize(10) // 如果`size`为空或小于`1`,则用`default-size`替换`size`
.maxPage(10000) // 如果`page`大于`max-page`,则用`max-page`替换`page`
.maxSize(10000) // 如果`size`大于`max-size`,则用`max-size`替换`size`
.build();
定义一个实现 io.leego.mypages.util.Pageable
接口的类.
public class QueryParam implements io.leego.mypages.util.Pageable {
private Integer page;
private Integer size;
private Integer offset;
private Integer rows;
@Override
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
@Override
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
@Override
public Integer getOffset() {
return offset;
}
public void setOffset(Integer offset) {
this.offset = offset;
}
@Override
public Integer getRows() {
return rows;
}
public void setRows(Integer rows) {
this.rows = rows;
}
}
详情请看:io.leego.mypages.util.SqlUtils#toCountSql
输入:
select * from user where status = ?
输出:
select count(*) from user where status = ?
输入:
select * from user where status = ? order by username desc
输出:
select count(*) from user where status = ?
输入:
select * from user where status = ? order by username desc
输出:
select count(*) from user where status = ? order by username desc
输入:
select nickname from user where status = ? group by nickname
输出:
select count(*) from (select nickname from user where status = ? group by nickname) mp_cta
输入:
with temp as (select * from user where status = ?)
select * from temp
输出:
with temp as (select * from user where status = ?)
select count(*) from temp
输入:
select *
from (select * from user) u
where u.status = ?
输出:
select count(*)
from (select * from user) u
where u.status = ?
@Pagination
public class QueryParam {
@Page
private Integer page;
@Size
private Integer size;
@CountMethodName
private String countMethodName;
public QueryParam(Integer page, Integer size, String countMethodName) {
this.page = page;
this.size = size;
this.countMethodName = countMethodName;
}
/* getter setter */
}
public class QueryParam {
private Integer page;
private Integer size;
private String countMethodName;
public QueryParam(Integer page, Integer size, String countMethodName) {
this.page = page;
this.size = size;
this.countMethodName = countMethodName;
}
/* getter setter */
}
PaginationSettings settings = PaginationSettings.builder()
.database(Database.MYSQL)
.pageField("page")
.sizeField("size")
.countMethodNameField("countMethodName")
.build();
PaginationInterceptor interceptor = new PaginationInterceptor(settings);
假设存在如下定义的Mapper:
public interface UserMapper {
@Select("SELECT * FROM user")
List<User> query(QueryParam param);
@Select("SELECT COUNT(*) FROM user")
long count(QueryParam param);
}
指定Count方法名称:
import io.leego.mypages.util.Page;
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public Page<User> query() {
// Specifies the count method name.
return Page.of(userMapper.query(new QueryParam(1, 10, "count")));
}
}
如果分页参数无效,需要合理化参数,可以设置以下参数:
defaultPage: 如果page为空或小于1,则用default-page替换page。
defaultSize: 如果size为空或小于1,则用default-size替换size。
maxPage: 如果page大于max-page,则用max-page替换page。
maxSize: 如果size大于max-size,则用max-size替换size。
@Pagination(defaultPage = 1, defaultSize = 10, maxPage = 10000, maxSize = 10000)
public class QueryParam {
}
PaginationSettings settings = PaginationSettings.builder()
.database(Database.MYSQL)
.defaultPage(1)
.defaultSize(10)
.maxPage(10000)
.maxSize(10000)
.build();
PaginationInterceptor interceptor = new PaginationInterceptor(settings);
Page<Foo> page = Page.of(mapper.query(param));
Page<Bar> page = Page.of(mapper.query(param), foo -> new Bar(foo));
Page<Bar> page = Page.of(mapper.query(param)).map(foo -> new Bar(foo));
List<Foo> list = mapper.query(param);
PaginationCollection pc = (PaginationCollection) list;
long total = pc.getTotal();
int page = pc.getPage();
int size = pc.getSize();
假设存在以下配置:
PaginationInterceptor interceptor = new PaginationInterceptor(PaginationSettings.builder()
.database(Database.MYSQL)
.pageField("page")
.sizeField("size")
.sizeField("size")
.offsetField("offset")
.build());
public interface UserMapper {
@Select("select * from user where status = #{status}")
List<User> findByStatusWithPageSizeParam(@Param("page") Integer page, @Param("size") Integer size, @Param("status") Integer status);
@Select("select * from user where status = #{status}")
List<User> findByStatusOffsetRowsWithParam(@Param("offset") Long offset, @Param("rows") Integer rows, @Param("status") Integer status);
}
@Pagination
public class PaginationFieldParam {
@Page
private Integer page;
@Size
private Integer size;
@Offset
private Long offset;
@Rows
private Integer rows;
private Integer status;
}
public interface UserMapper {
@Select("select * from user where status = #{status}")
List<User> findByPaginationField(PaginationFieldParam param);
@Select("select * from user where status = #{param.status}")
List<User> findByPaginationFieldWithParam0(@Param("param") PaginationFieldParam param);
@Select("select * from user where status = #{param1.status}")
List<User> findByPaginationFieldWithParam1(@Param("param1") PaginationFieldParam param);
}
@Pagination
public class PaginationMethodParam {
private Integer page;
private Integer size;
private Long offset;
private Integer rows;
private Integer status;
@Page
public Integer getPage() {
return page;
}
public void setPage(Integer page) {
this.page = page;
}
@Size
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
@Offset
public Long getOffset() {
return offset;
}
public void setOffset(Long offset) {
this.offset = offset;
}
@Rows
public Integer getRows() {
return rows;
}
public void setRows(Integer rows) {
this.rows = rows;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
}
public interface UserMapper {
@Select("select * from user where status = #{status}")
List<User> findByPaginationMethod(PaginationMethodParam param);
@Select("select * from user where status = #{param.status}")
List<User> findByPaginationMethodWithParam0(@Param("param") PaginationMethodParam param);
@Select("select * from user where status = #{param1.status}")
List<User> findByPaginationMethodWithParam1(@Param("param1") PaginationMethodParam param);
}
public class PageableParam implements Pageable {
private Integer page;
private Integer size;
private Long offset;
private Integer rows;
private Integer status;
}
public interface UserMapper {
@Select("select * from user where status = #{status}")
List<User> findByPageable(PageableParam param);
@Select("select * from user where status = #{param.status}")
List<User> findByPageableWithParam0(@Param("param") PageableParam param);
@Select("select * from user where status = #{param1.status}")
List<User> findByPageableWithParam1(@Param("param1") PageableParam param);
}
假设存在以下配置:
PaginationInterceptor interceptor = new PaginationInterceptor(PaginationSettings.builder()
.database(Database.MYSQL)
.pageField("page")
.sizeField("size")
.sizeField("size")
.offsetField("offset")
.build());
public class CustomClassParam {
private Integer page;
private Integer size;
private Long offset;
private Integer rows;
private Integer status;
}
public interface UserMapper {
@Select("select * from user where status = #{status}")
List<User> findByCustomClass(CustomClassParam param);
@Select("select * from user where status = #{param.status}")
List<User> findByCustomClassWithParam0(@Param("param") CustomClassParam param);
@Select("select * from user where status = #{param1.status}")
List<User> findByCustomClassWithParam1(@Param("param1") CustomClassParam param);
}
假设存在以下配置:
PaginationInterceptor interceptor = new PaginationInterceptor(PaginationSettings.builder()
.database(Database.MYSQL)
.pageField("page")
.sizeField("size")
.sizeField("size")
.offsetField("offset")
.build());
public interface UserMapper {
@Select("select * from user where status = #{status}")
List<User> findByCollectionMap(Map param);
@Select("select * from user where status = #{map.status}")
List<User> findByCollectionMapWithParam0(@Param("map") Map map);
@Select("select * from user where status = #{param1.status}")
List<User> findByCollectionMapWithParam1(@Param("param1") Map map);
}
public class CustomMapParam extends HashMap<String, Object> {
}
public interface UserMapper {
@Select("select * from user where status = #{status}")
List<User> findByCustomMap(CustomMapParam param);
@Select("select * from user where status = #{param.status}")
List<User> findByCustomMapWithParam0(@Param("param") CustomMapParam param);
@Select("select * from user where status = #{param1.status}")
List<User> findByCustomMapWithParam1(@Param("param1") CustomMapParam param);
}