zoukankan      html  css  js  c++  java
  • 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();
        }
    }
    

    最后

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

    程序yuan
  • 相关阅读:
    Java基础知识&面试题
    用例设计之API用例覆盖准则
    用例设计之APP用例覆盖准则
    Java的8种基本数据类型和3种引用数据类型
    并发concurrent---1
    Java运行时环境---ClassLoader类加载机制
    Java运行时环境---内存划分
    Java高阶语法---Volatile
    Java高阶语法---transient
    Java高阶语法---final
  • 原文地址:https://www.cnblogs.com/ooyhao/p/11589324.html
Copyright © 2011-2022 走看看