Mybatis (八) Mybatis整合PageHelper实现分页

整合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 list = pageInfo.getList();我们通过打印这个list对象是无法正常打印出Role对象的数据,是因为Page对象继承自ArrayList,并且重写了toString方法。我们可以通过迭代循环打印出来。如下图:

​ 这里由于循环打印才能看到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();
    }
}

最后

如果觉得不错的话,那就关注一下小编哦!一起交流,一起学习

posted @ 2019-09-26 10:28  ooyhao  阅读(2824)  评论(0编辑  收藏  举报