Spring data jpa的使用與詳解(復(fù)雜動(dòng)態(tài)查詢及分頁,排序)
一、 使用Specification實(shí)現(xiàn)復(fù)雜查詢
(1) 什么是Specification
Specification是springDateJpa中的一個(gè)接口,他是用于當(dāng)jpa的一些基本CRUD操作的擴(kuò)展,可以把他理解成一個(gè)spring jpa的復(fù)雜查詢接口。其次我們需要了解Criteria 查詢,這是是一種類型安全和更面向?qū)ο蟮牟樵?。而Spring Data JPA支持JPA2.0的Criteria查詢,相應(yīng)的接口是JpaSpecificationExecutor。
而JpaSpecificationExecutor這個(gè)接口基本是圍繞著Specification接口來定義的,Specification接口中只定義了如下一個(gè)方法:
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
Criteria查詢基本概念:
Criteria 查詢是以元模型的概念為基礎(chǔ)的,元模型是為具體持久化單元的受管實(shí)體定義的,這些實(shí)體可以是實(shí)體類,嵌入類或者映射的父類。
CriteriaQuery接口:
代表一個(gè)specific的頂層查詢對(duì)象,它包含著查詢的各個(gè)部分,比如:select 、from、where、group by、order by等注意:CriteriaQuery對(duì)象只對(duì)實(shí)體類型或嵌入式類型的Criteria查詢起作用。
Root:
代表Criteria查詢的根對(duì)象,Criteria查詢的查詢根定義了實(shí)體類型,能為將來導(dǎo)航獲得想要的結(jié)果,它與SQL查詢中的FROM子句類似。Root實(shí)例是類型化的,且定義了查詢的FROM子句中能夠出現(xiàn)的類型。root代表查詢的實(shí)體類,query可以從中得到root對(duì)象,告訴jpa查詢哪一個(gè)實(shí)體類,還可以添加查詢條件,還可以結(jié)合EntityManager對(duì)象 得到最終查詢的 TypedQuery對(duì)象。
CriteriaBuilder接口:
用來構(gòu)建CritiaQuery的構(gòu)建器對(duì)象Predicate:一個(gè)簡單或復(fù)雜的謂詞類型,其實(shí)就相當(dāng)于條件或者是條件組合。 可通過 EntityManager.getCriteriaBuilder 而得。
二、使用Specification進(jìn)行復(fù)雜的動(dòng)態(tài)查詢
maven的依賴?yán)^續(xù)使用上一章的就可以,這里修改一下實(shí)體類和controller層。
請(qǐng)求實(shí)體類:
@Datapublic class AccountRequest { //從第幾頁開始 private Integer page; //每一頁查詢多少 private Integer limit; private String id; private String name; private String pwd; private String email; private Integer[] types;}
實(shí)體類:
@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<Account,String>, JpaSpecificationExecutor<Account> {}
controller層(還是直接略過service層)
@Autowired private AccountRepository repository; @PostMapping('/get') public List<Account> get(@RequestBody AccountRequest request){ Specification<Account> specification = new Specification<Account>() { @Override public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder builder) {//所有的斷言 及條件List<Predicate> predicates = new ArrayList<>();//精確匹配id pwdif (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()));}//模糊搜索 nameif (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<Object> 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<Account> accounts = repository.findAll(specification); return accounts; }
通過重寫Specification的toPredicate的方法,這樣一個(gè)復(fù)雜的動(dòng)態(tài)sql查詢就完成了,通過post請(qǐng)求直接就可以調(diào)用了。
三、分頁及排序
@PostMapping('/page') public List<Account> getPage(@RequestBody AccountRequest request){ Specification<Account> specification = new Specification<Account>() { @Override public Predicate toPredicate(Root<Account> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {List<Predicate> predicates = new ArrayList<>();//do anythingreturn criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()])); } }; //表示通過createTime進(jìn)行 ASC排序 PageRequest page = new PageRequest(request.getPage() - 1, request.getLimit(), Sort.Direction.ASC, 'createTime'); Page<Account> pageInfo = repository.findAll(specification, page); return pageInfo.getContent(); }
上面的代碼是在經(jīng)過復(fù)雜查詢并進(jìn)行分頁與排序,通過PageRequest來構(gòu)建分頁排序的規(guī)則。傳入起始頁及每頁的數(shù)量,還有排序的規(guī)則及以哪個(gè)屬性排序。jpa中是以第0頁開始的,所以傳參的時(shí)候需要注意!
當(dāng)然,如果你不需要進(jìn)行復(fù)雜的查詢也可以對(duì)數(shù)據(jù)進(jìn)行分頁及排序查詢。
修改repository,使其繼承PagingAndSortingRepository。
@Repositorypublic interface AccountRepository extends JpaRepository<Account,String>, JpaSpecificationExecutor<Account> , PagingAndSortingRepository<Account,String> { Page<Account> findByAge(int age, Pageable pageable);}
使用時(shí)先創(chuàng)建pageable參數(shù),然后傳進(jìn)去就可以了。
//顯示第1頁每頁顯示3條PageRequest pr = new PageRequest(1,3);//根據(jù)年齡進(jìn)行查詢Page<Account> stus = accountPageRepository.findByAge(22,pr);
排序也是一樣的,在repository中創(chuàng)建方法
List<Account> findByPwd(String pwd, Sort sort);
調(diào)用的時(shí)候傳入sort對(duì)象
//設(shè)置排序方式為username降序List<Account> accs = accountPageRepository.findByAge('123456',new Sort(Sort.Direction.DESC,'username'));//設(shè)置排序以u(píng)sername和type進(jìn)行升序acc = accountPageRepository.findByAge('123456',new Sort(Sort.Direction.ASC,'username','type'));//設(shè)置排序方式以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);
到此這篇關(guān)于Spring data jpa的使用與詳解(復(fù)雜動(dòng)態(tài)查詢及分頁,排序)的文章就介紹到這了,更多相關(guān)Spring data jpa內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
