【Java 干货教程】Java实现分页的几种方式详解

这篇具有很好参考价值的文章主要介绍了【Java 干货教程】Java实现分页的几种方式详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

无论是自我学习中,还是在工作中,固然会遇到与前端搭配实现分页的功能,发现有几种方式,特此记录一下。

二、实现方式

2.1、分页功能直接交给前端实现

这种情况也是有的,(根据业务场景且仅仅只能用于数据量少的情况)。即后端不做任何数据的限制,直接把全部数据返回给前端,前端通过组件实现分页,筛选等功能。请不要轻视该方式,好处即只需要前后端交互一次。

2.2、数据库SQL的限制条件

即给搜索语句加上条件,限制查询出来的数据个数。(这里不同数据库可能sql语句写法不一样)

  • mysql数据库是使用 limit n,m 从第n个开始,往后取m个(注 不包括第n个数据)
  • oracle数据库是使用 OFFSET n ROWS FETCH NEXT m ROWS ONLY 从第n行开始,往后取m行(注 不包括第n行数据)

oracle的可以查看这篇文章:oracle中将数据进行排序之后,获取前几行数据的写法(rownum、fetch方式)

2.3、使用List集合的截取功能实现 

即将数据都查到内存中List集合,在内存中找到要的数据。当然有人说这种方式还不如第二点,但请具体情况具体分析,有可能需求要的数据,是从数据库中查询不到的需要将原始数据查到内存加工处理数据之后得到,才能进行分页处理。(同理,该方法,只能根据需求数据量少的情况)。

2.4、插件PageHelper

使用优秀的插件PageHelper,真的很不错。

如果想详细了解PageHelper插件的,可以访问:如何使用分页插件

2.5、SpringData 

SpringData我还没用过,这里就不展开详细说明了,后期如果业务使用到了,会更新到这篇文章。

三、详细介绍

分页功能交给前端实现的这里就不展示了,比较我们标题是后端实现分页功能。

3.1、数据库SQL的限制条件(limit,fetch)

sql语句

mysql写法:
SELECT * FROM user2
LIMIT (#{pageNum} - 1) * #{pageSize}, #{pageSize}

oracle写法:
SELECT * FROM user2
OFFSET (#{pageNum} - 1) * #{pageSize} ROWS FETCH NEXT #{pageSize} ROWS ONLY

Dao层(也可以叫Mapper层)

@Mapper
public interface PageTestDao {
	
	// 查数据
	// start:从第几条开始,向后要数据
	// pageSize:一页多少条数据
    List<UserEntity> getUserInfoByParams(@Param("nameParam") String name,
                                         @Param("start") int start,
                                         @Param("pageSize") int pageSize);
	// 返回总条数
    int getCountByParams(@Param("nameParam") String name);
}

Mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.csdn2.page_test.dao.PageTestDao">

    <sql id="nameCondition">
        <where>
            <if test="nameParam != null and nameParam != ''">
                name like CONCAT('%', #{nameParam}, '%')
            </if>
        </where>
    </sql>

    <select id="getUserInfoByParams" resultType="com.example.csdn2.page_test.entity.UserEntity">
        SELECT * FROM user2
        <include refid="nameCondition" />
        LIMIT #{start}, #{pageSize}
    </select>

    <select id="getCountByParams" resultType="int">
        SELECT COUNT(*) FROM user2
        <include refid="nameCondition" />
    </select>
</mapper>

Service实现层

@Service
@RequiredArgsConstructor
public class PageTestService {

    private final PageTestDao pageTestDao;

    public PageResponse<UserEntity> getPageTest(UserRequest userRequest) {
        final List<UserEntity> userEntityList = pageTestDao.getUserInfoByParams(userRequest.getNameParam(),
                userRequest.getStart(), userRequest.getPageSize());

        final int total = pageTestDao.getCountByParams(userRequest.getNameParam());

        return new PageResponse<>(userEntityList, total);
    }
}

PageRequest

// 若分页的需求很多,可把分页相关的参数抽出来
@Data
public class PageRequest {

    // 第几页
    private int pageNum;

    // 每页几行数据
    private int pageSize;

	// 计算从第几行开始
	// 无论是limit、还是fetch 都是从某一行数据开始,向后取 pageSize 条数据
    public int getStart() {
        if (pageNum <= 0) {
            return 0;
        }
        return (pageNum - 1) * pageSize;
    }
}

UserRequest

// 入参
@EqualsAndHashCode(callSuper = true)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRequest extends PageRequest {

    // 搜索参数
    private String nameParam;
}

PageResponse

我这边只返回给前端查询的某页数据、和一共多少条数据,如果前端需要知道可以分多少页,需要前端自己计算一下,当然后端其实也可以计算,只需要添加一个参数和一个方法。

// 返回实体类,因为分页需要返回总条数,前端好做下标第几页
@Data
@AllArgsConstructor
public class PageResponse<T> {

    private List<T> data;

	// 总条数
    private int total;
}

Controller层

@RestController
@RequestMapping("/pageTest")
public class PageTestController {

    private final PageTestService pageTestService;

    @PostMapping("/page-test")
    public PageResponse<UserEntity> getPageTest(@RequestBody UserRequest userRequest){
       return pageTestService.getPageTest(userRequest);
    }
}

运行结果

【Java 干货教程】Java实现分页的几种方式详解,Java干货,Java分页,PageHelper

3.2、使用List集合的截取功能(subList())实现

先看一下List的截取

// 从第几个下标,到第几个下标
List<E> subList(int fromIndex, int toIndex);
    public void test_ListSub() {
    	// 创建模拟数据,字符串 0-9的集合
        final List<String> list = IntStream.range(0, 10)
                .mapToObj(i -> i + "")
                .collect(Collectors.toList());
        System.out.println(list);
        // 截取从下标0到5的数据
        System.out.println(list.subList(0, 5));
        // 截取从下标3到5的数据
        System.out.println(list.subList(3, 5));
    }

【Java 干货教程】Java实现分页的几种方式详解,Java干货,Java分页,PageHelper

回归上述分页例子,代码改成如下:

dao层 不加 limit 条件

  SELECT * FROM user2
  name like CONCAT('%', #{nameParam}, '%')

server层

public PageResponse<UserEntity> getPageTestByListSub(UserRequest userRequest) {
        final List<UserEntity> allData = pageTestDao.getUserInfoByParamsNoLimit(userRequest.getNameParam());
        // 下标开始
        final int start = userRequest.getStart();
        // 下标结束
        final int end = start + userRequest.getPageSize();
        // 截取数据
        final List<UserEntity> userEntityList = allData.subList(start, end);

        final int total = pageTestDao.getCountByParams(userRequest.getNameParam());
        return new PageResponse<>(userEntityList, total);
    }

3.3、插件PageHelper

这是一个特别好用的分页插件。

其实PageHelper官网中有详细的文档以及例子:https://pagehelper.github.io/docs/howtouse/

下面例子只是讲其与springboot结合的核心内容,即快速开发

引入相关jar包坐标到pom.xml中

<dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.3.0</version>
</dependency>

配置项目application.yml文件

#bybatis分页插件配置
pagehelper:
  helper-dialect: mysql  #数据库
  reasonable: true
  support-methods-arguments: true
  params: count=countSql

3.3.1、案例1 

前端所需要的数据就是数据库中表的数据

dao层的sql不需要加 Limit 条件(因为PageHelper会自动帮忙加的)

  SELECT * FROM user2
  name like CONCAT('%', #{nameParam}, '%')

service层修改如下

   public PageInfo<UserEntity> getPageTest(UserRequest userRequest) {
        // 告诉PageHelper数据要从第几页,每页多少条数据
        // 注:一定要在select查询语句之前使用该方法,否则无效
        PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize());
        
        // 查询sql
        final List<UserEntity> userEntityList = 
pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam());

        // 返回dto,使用插件自带的PageInfo
        return new PageInfo<>(userEntityList);

		// 上述逻辑还可以简写为:
		// return PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize())
            // .doSelectPageInfo(() -> 
pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam()));
    }


结果如下(与之前查询结果一致,没问题)

{
    "total": 9,
    "list": [
        {
            "name": "4a",
            "pwd": "D"
        },
        {
            "name": "5a",
            "pwd": "E"
        },
        {
            "name": "6a",
            "pwd": "F"
        }
    ],
    "pageNum": 2,
    "pageSize": 3,
    "size": 3,
    "startRow": 4,
    "endRow": 6,
    "pages": 3,
    "prePage": 1,
    "nextPage": 3,
    "isFirstPage": false,
    "isLastPage": false,
    "hasPreviousPage": true,
    "hasNextPage": true,
    "navigatePages": 8,
    "navigatepageNums": [
        1,
        2,
        3
    ],
    "navigateFirstPage": 1,
    "navigateLastPage": 3
}

3.3.2、案例2

前端所需要的数据不只是数据库中表的数据,还有一些需要Java代码逻辑计算得到的数据。那么上面的PageHelper.startPage(userRequest.getPageNum(), userRequest.getPageSize());就失效了。

 public PageInfo<UserEntityResp> getPageTest(UserRequest userRequest) {
        //分页类的创建
        PageInfo<UserEntityResp> res = new PageInfo<>();
        
        // 查询sql
        List<UserEntity> userEntityList = 
pageTestDao.getUserInfoByParamsNotLimit(userRequest.getNameParam());

        //对userEntityList中的数据进行了一些算法操作,改变了原来从数据库中查询到的数据
        //或者以什么排序等等操作,最终得到result
        List<UserEntityResp> result = .....   ;              

        int total = result.size();

        //注意:这里的start,end是需要通过userRequest.getPageNum(), userRequest.getPageSize()
        //计算得到的
        Double index = (Double)Math.ceil(total * 1.0 / userRequest.getPageSize());
        
        if (index.intValue()>=userRequest.getPage()){
            start = (userRequest.getPage() - 1) * userRequest.getPageSize();
            end = Math.min(start + userRequest.getPageSize(), total);
        } else{
            start = 0;
            end = total;
        }
        
		List<InterfaceConfirmTimeResp> pageList = result.subList(start, end);

        //将分页相关对象的属性设置
        res.setList(pageList);
        res.setTotal(result.size());
        res.setPageNum(userRequest.getPage());
        res.setPageSize(userRequest.getPageSize());
        res.setPages((int)Math.ceil(result.size()*1.0/userRequest.getPageSize()));
        return res;
    }

这是通过PageHelp插件中的PageInfo类和List中的subList()方法实现的,其实一般这种情况用的也是比较多的。

3.3.3、为什么PageHelp插件优秀

为什么说该插件很优秀呢查看PageInfo的返回参数,核心内容:

	// 当前页
    private int pageNum;
    // 每页的数量
    private int pageSize;
    // 当前页的数量
    private int size;

    // 总记录数
    private long total;
    // 总页数
    private int pages;
    // 结果集
    private List<T> list;
 
 	// 以下内容都是其自动帮生成的
 	// 对于前端来说极其友好,前端分页功能的全部参数都包含了
    // 前一页的页码
    private int prePage;
    // 下一页的页码
    private int nextPage;
    // 是否为第一页
    private boolean isFirstPage = false;
    // 是否为最后一页
    private boolean isLastPage = false;
    // 是否有前一页
    private boolean hasPreviousPage = false;
    // 是否有下一页
    private boolean hasNextPage = false;
    // 导航条上的第一页的页码
    private int navigateFirstPage;
    // 导航条上的第一页的页码
    private int navigateLastPage;

查看PageHelper执行了什么sql语句

【Java 干货教程】Java实现分页的几种方式详解,Java干货,Java分页,PageHelper

3.3.4、spring结合mybatis整合PageHelper框架

Spring整合:导入pom.xml

<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
 <dependency>
      <groupId>com.github.pagehelper</groupId>
      <artifactId>pagehelper</artifactId>
      <version>5.1.2</version>
 </dependency>

配置项目配置文件(我在spring和mybatis整合的配置文件中配置的,如果在mybatis核心配置文件中配置,百度一下)

<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 依赖数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 注册加载myBatis映射文件 -->
        <property name="mapperLocations">
            <array>
                <value>classpath*:com/yyz/mapper/*Mapper.xml</value>
            </array>
        </property>
        <!-- PageHelper分页配置 -->
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageInterceptor">
                    <property name="properties">
                        <!--使用下面的方式配置参数,一行配置一个,后面会有所有的参数介绍 -->
                        <value>
                    <!--helperDialect属性来指定分页插件使用哪种方言。-->
                            helperDialect=mysql
                    <!--分页合理化参数,设置为true时,pageNum<=0时会查询第一页,pageNum>pages(超过总数时),会查询最后一页。-->
                            reasonable=true
                    <!--为了支持startPage(Object params)方法,增加了该参数来配置参数映射,用于从对象中根据属性名取值,
                        可以配置 pageNum,pageSize,count,pageSizeZero,reasonable-->
                            params=count=countSql
                    <!--支持通过Mapper接口参数来传递分页参数,默认值false,分页插件会从查询方法的参数值中,自动根据上面 params 配
                     置的字段中取值,查找到合适的值时就会自动分页。-->
                            supportMethodsArguments=true
                    <!--默认值为 false。设置为 true 时,允许在运行时根据多数据源自动识别对应方言的分页-->
                            autoRuntimeDialect=true
                        </value>
                    </property>
                </bean>
            </array>
        </property>
        <!-- 给数据库实体起别名 -->
        <property name="typeAliasesPackage" value="com.yyz.entity;"/>
 </bean>

以上就是Java实现分页的几种方式,希望对你有所帮助,如果有其它方式可以在评论区留言!!!

参考文章:java中实现分页的常见几种方式_java 分页-CSDN博客文章来源地址https://www.toymoban.com/news/detail-783819.html

到了这里,关于【Java 干货教程】Java实现分页的几种方式详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringBoot实现分页的三种方式

    一 自己封装Page对象实现 博客链接 二 使用sql实现分页 2.1 场景分析 前段传递给给后台什么参数? 当前页码 currentPage 每页显示条数 pageSize 后台给前端返回什么数据? 当前页数据 List 总记录数 totalCount 2.2 前段代码 2.3 后端代码 PageBean mapper service impl controller 三 使用PageHelper插件

    2024年02月10日
    浏览(50)
  • Java实现异步的几种方式

    普通线程实现异步,但频繁创建、销毁线程比较耗资源,所以一般交给线程池执行 结果: Future异步 和普通线程实现异步区别不大,只是使用Future是要获取执行后的返回值 结果: Spring的@Async异步 使用@Async注解实现异步的前提是需要在启动类上标注@EnableAsync来开启异步配置

    2024年02月04日
    浏览(66)
  • Java如何实现下载文件的几种方式

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/Boy_Martin/article/details/126058565

    2024年02月13日
    浏览(67)
  • java 实现开启异步线程的几种方式

    在Java中,有多种方式可以实现异步线程以避免在主线程中执行耗时操作导致界面卡顿的问题。以下是几种常用的方式: 使用 Thread 类:可以使用 Thread 类来创建一个新的线程,并在其 run() 方法中执行耗时操作。例如: 使用 Runnable 接口:可以通过实现 Runnable 接口并在其中实现

    2024年02月14日
    浏览(44)
  • Java实现字符串排序的几种方式

    创建实体类(此处引入了lombok) 一、使用List集合中自带的sort方法(字符串的位数保持一致,不一致的情况可以在左边补0,也可以使用String.format()方法补全) 1、在对象排序中使用 2、在字符串排序中使用 二、使用Stream流(字符串的位数保持一致,不一致的情况可以在左边补

    2024年02月11日
    浏览(52)
  • Java生成二维码的几种实现方式

    本文将基于Spring Boot介绍两种生成二维码的实现方式,一种是基于Google开发工具包,另一种是基于Hutool来实现; 下面我们将基于Spring Boot,并采用两种方式实现二维码的生成,对于每一种方式还提供两种类型的二维码返回形式,即:物理文件 和 图片响应流 一、基于Google开发

    2024年02月17日
    浏览(42)
  • java实现调用http请求的几种常见方式

    ------ Oracle中文开发者社区 ------ 如果你想要学习编程,关注本博客,持续获得技术支持,持续获得技术咨询 java开发·企业官方账号 Oracle中国官方账号 Java中国管理部 全网粉丝30万+ 华为云享专家 阿里专家博主 CSDN内容合伙人 CSDN原力计划作者 51CTO专家博主 CSDN博客V账号 毕业于四川

    2024年02月04日
    浏览(54)
  • Java实现HTTP请求的几种方式-HttpURLConnection(一)

    在实际开发过程中,我们经常需要调用对方提供的接口或测试自己写的接口是否合适。很多项目都会封装规定好本身项目的接口规范,所以大多数需要去调用对方提供的接口或第三方接口(短信、天气等)。 准备两个项目: 项目A: 服务提供者 项目B:服务消费者 在项目A中

    2024年02月16日
    浏览(43)
  • JAVA微服务分布式事务的几种实现方式

    一致性(Consistency) :在分布式系统中所有的数据备份,在同一时刻都保持一致状态,如无法保证状态一致,直接返回错误; 可用性(Availability):在集群中一部分节点故障,也能保证客户端访问系统并得到正确响应,允许一定时间内数据状态不一致; 分区容错性(Partiti

    2024年02月12日
    浏览(51)
  • Java实现HTTP请求的几种方式-CloseableHttpClient(三)

    CloseableHttpClient是在HttpClient的基础上修改更新而来的,这里还涉及到请求头token的设置(请求验证),利用fastjson转换请求或返回结果字符串为json格式,当然上面两种方式也是可以设置请求头token、json的,这里只在下面说明。 基于第一章的测试接口,建立以下程序 创建客户端

    2023年04月20日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包