一、 使用Specification實作復雜查詢
(1) 什么是Specification
Specification是springDateJpa中的一個介面,他是用于當jpa的一些基本CRUD操作的擴展,可以把他理解成一個spring jpa的復雜查詢介面,其次我們需要了解Criteria 查詢,這是是一種型別安全和更面向物件的查詢,而Spring Data JPA支持JPA2.0的Criteria查詢,相應的介面是JpaSpecificationExecutor,
而JpaSpecificationExecutor這個介面基本是圍繞著Specification介面來定義的,Specification介面中只定義了如下一個方法:
Predicate toPredicate(Root<T> 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<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 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<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的方法,這樣一個復雜的動態sql查詢就完成了,通過post請求直接就可以呼叫了,
三、分頁及排序
@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 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<Account> pageInfo = repository.findAll(specification, page);
return pageInfo.getContent();
}
上面的代碼是在經過復雜查詢并進行分頁與排序,通過PageRequest來構建分頁排序的規則,傳入起始頁及每頁的數量,還有排序的規則及以哪個屬性排序,jpa中是以第0頁開始的,所以傳參的時候需要注意!
當然,如果你不需要進行復雜的查詢也可以對資料進行分頁及排序查詢,
修改repository,使其繼承PagingAndSortingRepository,
@Repository
public interface AccountRepository extends JpaRepository<Account,String>, JpaSpecificationExecutor<Account> , PagingAndSortingRepository<Account,String> {
Page<Account> findByAge(int age, Pageable pageable);
}
使用時先創建pageable引數,然后傳進去就可以了,
//顯示第1頁每頁顯示3條
PageRequest pr = new PageRequest(1,3);
//根據年齡進行查詢
Page<Account> stus = accountPageRepository.findByAge(22,pr);
排序也是一樣的,在repository中創建方法
List<Account> findByPwd(String pwd, Sort sort);
呼叫的時候傳入sort物件
//設定排序方式為username降序
List<Account> 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);
結語:
這個小內容在這里差不多就算結束了,如果還有需要更多Java方面的學習資料、學習教程的可以點擊進入,暗號:csbb , 免費提供,大家一起交流學習!
Java各方面的面試題

Java各方面的學習資料,考慮篇幅問題,這些都只能展示一小部分

Java方面的學習教程,只要是后端開發會以及架構需要的技能點,這里都有教程!

最后祝大家都能作業順利,年薪百萬!!!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/198605.html
標籤:其他
上一篇:swagger介面檔案使用
