Spring data jpa的使用与详解(复杂动态查询及分页,排序)

网友投稿 224 2023-02-27

Spring data jpa的使用与详解(复杂动态查询及分页,排序)

一、 使用Specification实现复杂查询

(1) 什么是Specification

Specification是springDateJpa中的一个接口,他是用于当jpa的一些基本CRUD操作的扩展,可以把他理解成一个spring jpa的复杂查询接口。其次我们需要了解Criteria 查询,这是是一种类型安全和更面向对象的查询。而Spring Data JPA支持JPA2.0的Criteria查询,相应的接口是JpaSpecificationExecutor。

而JpaSpecificationExecutor这个接口基本是围绕着Specification接口来定义的,Specification接口中只定义了如下一个方法:

Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder cb);

Criteria查询基本概念:

Criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。

CriteriaQuery接口:

代表一个specific的顶层查询对象,它包含着查询的各个部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery对象只对实体类型或嵌入式类型的Criteria查询起作用。

Root:

代表Criteria查询的根对象,Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似。

Root实例是类型化的,且定义了查询的FROM子句中能够出现的类型。root代表查询的实体类,query可以从中得到root对象,告诉jpa查询哪一个实体类,还可以添加查询条件,还可以结合EntityManager对象 得到最终查询的 TypedQuery对象。

CriteriaBuilder接口:

用来构建CritiaQuery的构建器对象Predicate:一个简单或复杂的谓词类型,其实就相当于条件或者是条件组合。 可通过 EntityManager.getCriteriaBuilder 而得。

二、使用Specification进行复杂的动态查询

maven的依赖继续使用上一章的就可以,这里修改一下实体类和controller层。

请求实体类:

@Data

public class AccountRequest {

//从第几页开始

private Integer page;

//每一页查询多少

private Integer limit;

private String id;

private String name;

private String pwd;

private String email;

private Integer[] types;

}

实体类:

@Data

@Entity

@Table(name = "account")

@ToString

@EntityListeners(AuditingEntityListener.class)

public class Account {

@Id

@GenericGenerator(name = "idGenerator", strategy = "uuid")

@GeneratedValue(generator = "idGenerator")

private String id;

@Column(name = "username", unique = true, nullable = false, length = 64)

private String username;

@Column(name = "password", nullable = false, length = 64)

private String password;

@Column(name = "email", length = 64)

private String email;

@Column(name = "type")

private Short type;

@CreatedDate

@Column(name = "create_time", nullable = false)

private LocalDateTime createTime;

}

Repository层:

public interface AccountRepository extends JpaRepository, JpaSpecificationExecutor {}

controller层(还是直接略过service层)

@Autowired

private AccountRepository repository;

@PostMapping("/get")

public List get(@RequestBody AccountRequest request){

Specification specification = new Specification() {

@Override

phttp://ublic Predicate toPredicate(Root root, CriteriaQuery> criteriaQuery, CriteriaBuilder builder) {

//所有的断言 及条件

List predicates = new ArrayList<>();

//精确匹配id pwd

if (request.getId() != null) {

predicates.add(builder.equal(root.get("id"), request.getId()));

}

if (request.getPwd() != null) {

predicates.add(builder.equal(root.get("password"), request.getPwd()));

}

//模糊搜索 name

if (request.getName() != null && !request.getName().equals("")) {

predicates.add(builder.like(root.get("username"), "%" + request.getName() + "%"));

}

if (request.getEmail() != null && !request.getEmail().equals("")) {

predicates.add(builder.like(root.get("email"), "%" + request.getEmail() + "%"));

}

//in范围查询

if (request.getTypes() != null) {

CriteriaBuilder.In types = builder.in(root.get("type"));

for (Integer type : request.getTypes()) {

types = types.value(type);

}

predicates.add(types);

}

return builder.and(predicates.toArray(new Predicate[predicates.size()]));

}

};

List accounts = repository.findAll(specification);

return accounts;

}

通过重写Specification的toPredicate的方法,这样一个复杂的动态sql查询就完成了,通过post请求直接就可以调用了。

三、分页及排序

@PostMapping("/page")

public List getPage(@RequestBody AccountRequest request){

Specification specification = new Specification() {

@Override

public Predicate toPredicate(Root root, CriteriaQuery> criteriaQuery, CriteriaBuilder criteriaBuilder) {

List predicates = new ArrayList<>();

//do anything

return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));

}

};

//表示通过createTime进行 ASC排序

PageRequest page = new PageRequest(request.getPage() - 1, request.getLimit(), Sort.Direction.ASC, "createTime");

Page pageInfo = repository.findAll(specification, page);

http:// return pageInfo.getContent();

}

上面的代码是在经过复杂查询并进行分页与排序,通过PageRequest来构建分页排序的规则。传入起始页及每页的数量,还有排序的规则及以哪个属性排序。jpa中是以第0页开始的,所以传参的时候需要注意!

当然,如果你不需要进行复杂的查询也可以对数据进行分页及排序查询。

修改repository,使其继承PagingAndSortingRepository。

@Repository

public interface AccountRepository extends JpaRepository, JpaSpecificationExecutor , PagingAndSortingRepository {

Page findByAge(int age, Pageable pageable);

}

使用时先创建pageable参数,然后传进去就可以了。

//显示第1页每页显示3条

PageRequest pr = new PageRequest(1,3);

//根据年龄进行查询

Page stus = accountPageRepository.findByAge(22,pr);

排序也是一样的,在repository中创建方法

List findByPwd(String pwd, Sort sort);

调用的时候传入sort对象

//设置排序方式为username降序

List accs = accountPageRepository.findByAge("123456",new Sort(Sort.Direction.DESC,"username"));

//设置排序以username和type进行升序

acc = accountPageRepository.findByAge("123456",new Sort(Sort.Direction.ASC,"username","type"));

//设置排序方式以name升序,以address降序

Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC,"name"),new Sort.Order(Sort.Direction.DESC,"type"));

accs = accountPageRepository.findByAge("123456",sort);

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:详解Java中方法next()和nextLine()的区别与易错点
下一篇:Compare And Swap底层原理及代码示例详解
相关文章

 发表评论

暂时没有评论,来抢沙发吧~