带查询条件的分页

以前做的项目中,使用到分页都是通过封装一个页面类如 class page 来保存页面的信息,包括当前页码,每页显示页码数,总页数,总记录数,结果集

在SQL中通过当前页码和每页页码数来控制SQL,直接查询数据出来,然后挨着排的放到页面中,在页面加入链接或按钮来改变当前页码,实现分页

 

最近公司要求做的一个分页,页面中要有各种查询条件选项,可以实现查询功能,查询的同时要实现分页,这个还是有一点值得去思考的:

  首先是拼接SQL,带条件的分页我感觉是有一定难度的,也是因为之前没那么做过,也挺有挑战性;我选择的是select top 和 not in 的组合来完成,这样的SQL最重要的一点是你要保证 not in 后面所要执行的 select 语句与它之前的 select 语句所操作的数据区域是一致的,否则查询出来的数据是不正确的;我写的语句是 :

select top 条数 * from (select top NO2 * from message where 条件 order by createTime desc)

 t1 where t1.id not in (select top NO3 id from t1 order by createTime desc)

我的想法没错,但是t1在 not in 后的查询子句中引用无效,后来在老大的提示下,我在程序中改造了SQL,就是将各个区段的SQL封装成一个个体,然后对接他们,最后实现了功能。

  另一种SQL则是采用套三层的方式,倒转查询出来的结果集,如:

  select * from (select top 10 * from (select top 29 from message where 条件 order by id asc) 

     t1 ) t2 order by id desc

但是我将这条SQL的排序列改为其他的非标识列时,发现查询出的结果并非我想要的顺序,我也对这种语句操作方式理解不够,最后还是用自己的想法来实现了。

 

  程序中要保证查询与分页的同步,而且还要保证页面跳转不会影响查询结果集;我重新封装了一个条件类,用来储存条件信息,这样就把散落的各种条件集合在一起,易于管理,后来证明这种方式确实是带了很大的便利。后来也是图方便,我还把条件类做成了分页类的成员,这样我在拼接SQL的时候比较简单一些。

  页面的跳转我是通过按钮来实现的,起初设想的是,点击页面跳转按钮的时候触发表单提交,然后将表单信息发送过去,执行查询。这样要面对一个问题,之前点击查询按钮提交的表单数据需要记录下来,在页面跳转事件中要继续使用这些数据才能保证结果同步,否则表单提交完了以后就会清空,在提交就没有条件了,那后果可想而知。我选择session保存条件,判断用户按下的是不是查询按钮来决定是否要重新设定session中的条件值,然后分页信息需要通过 request来传递,分页按钮也不能触发表单提交了,而要改成链接参数的方式来传递分页信息,这样查询和分页互不干涉,同时能保证数据的正确性。

 

  感觉自己还是太菜了,需要向那个偶像程序员学习,努力。。

### 如何使用 JPA 实现条件查询分页功能 为了实现条件查询分页功能,在 `Spring Data JPA` 中可以利用 `JpaRepository` 和 `JpaSpecificationExecutor` 接口来完成此操作。通过继承这两个接口,可以在 Repository 层获得强大的 CRUD 功能以及动态构建复杂查询的能力。 #### 定义实体类 假设有一个名为 `User` 的实体类表示用户表: ```java @Entity public class User { @Id private Long id; private String name; private Integer age; // getters and setters omitted for brevity } ``` #### 创建自定义规格说明 (Specification) 在 Service 层创建一个用于封装查询逻辑的方法,该方法返回一个 `Specification<User>` 对象,这个对象可以根据传入参数动态生成 JPQL 查询语句[^1]。 ```java import org.springframework.data.jpa.domain.Specification; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; public static Specification<User> buildSpec(String userName, Integer minAge) { return new Specification<User>() { public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) { List<Predicate> predicates = new ArrayList<>(); if (userName != null && !"".equals(userName)) { predicates.add(cb.like(root.get("name"), "%" + userName + "%")); } if (minAge != null) { predicates.add(cb.ge(root.<Integer>get("age"), minAge)); } return cb.and(predicates.toArray(new Predicate[predicates.size()])); } }; } ``` #### 编写服务层业务逻辑 接下来是在 Service 类里边编写具体的服务端处理函数,这里会调用上面提到过的 `buildSpec()` 方法并将其传递给 Repository 进行实际的数据访问操作[^2]。 对于 **非分页查询** 可以这样执行: ```java List<User> findUsersByConditions(String userName, Integer minAge){ return userRepository.findAll(buildSpec(userName,minAge)); } ``` 而对于 **分页查询**, 则需引入 Pageable 参数以便控制每一页显示多少条记录及当前处于哪一页 : ```java Page<User> findPagedUsersByConditions(String userName, Integer minAge, int pageNumber,int pageSize){ PageRequest pageRequest= PageRequest.of(pageNumber-1,pageSize); return userRepository.findAll(buildSpec(userName,minAge),pageRequest); } ``` 上述代码片段展示了如何基于输入的名字和最小年龄作为过滤条件来进行用户的检索工作,并支持简单的分页机制。注意这里的 `pageNumber` 是从 1 开始计数的,而 Spring 默认是从 0 计算页面索引,因此需要减去 1 来调整为正确的起始位置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值