四.繼承JpaSpecificationExecutor接口進行復雜查詢
spring data jpa 通過創建方法名來做查詢,只能做簡單的查詢,那如果我們要做複雜一些的查詢呢,多條件分頁怎麼辦,這裏,spring data jpa爲我們提供了JpaSpecificationExecutor接口,只要簡單實現toPredicate方法就可以實現複雜的查詢
參考:https://www.cnblogs.com/happyday56/p/4661839.html
1.首先讓我們的接口繼承於JpaSpecificationExecutor
public interface TaskDao extends JpaSpecificationExecutor<Task>{
}
2.JpaSpecificationExecutor提供了以下接口
public interface JpaSpecificationExecutor<T> {
T findOne(Specification<T> spec);
List<T> findAll(Specification<T> spec);
Page<T> findAll(Specification<T> spec, Pageable pageable);
List<T> findAll(Specification<T> spec, Sort sort);
long count(Specification<T> spec);
}
//其中Specification就是需要我們傳入查詢方法的參數,它是一個接口
public interface Specification<T> {
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
}
提供唯一的一個方法toPredicate,我們只要按照JPA 2.0 criteria api寫好查詢條件就可以了,關於JPA 2.0 criteria api的介紹和使用,歡迎參考
http://blog.csdn.net/dracotianlong/article/details/28445725
http://developer.51cto.com/art/200911/162722.htm
3.接下來我們在service bean
@Service
public class TaskService {
@Autowired TaskDao taskDao ;
/**
* 複雜查詢測試
* @param page
* @param size
* @return
*/
public Page<Task> findBySepc(int page, int size){
PageRequest pageReq = this.buildPageRequest(page, size);
Page<Task> tasks = this.taskDao.findAll(new MySpec(), pageReq);
//傳入了new MySpec() 既下面定義的匿名內部類 其中定義了查詢條件
return tasks;
}
/**
* 建立分頁排序請求
* @param page
* @param size
* @return
*/
private PageRequest buildPageRequest(int page, int size) {
Sort sort = new Sort(Direction.DESC,"createTime");
return new PageRequest(page,size, sort);
}
/**
* 建立查詢條件
*/
private class MySpec implements Specification<Task>{
@Override
public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
//1.混合條件查詢
Path<String> exp1 = root.get("taskName");
Path<Date> exp2 = root.get("createTime");
Path<String> exp3 = root.get("taskDetail");
Predicate predicate = cb.and(cb.like(exp1, "%taskName%"),cb.lessThan(exp2, new Date()));
return cb.or(predicate,cb.equal(exp3, "kkk"));
/* 類似的sql語句爲:
Hibernate:
select
count(task0_.id) as col_0_0_
from
tb_task task0_
where
(
task0_.task_name like ?
)
and task0_.create_time<?
or task0_.task_detail=?
*/
//2.多表查詢
Join<Task,Project> join = root.join("project", JoinType.INNER);
Path<String> exp4 = join.get("projectName");
return cb.like(exp4, "%projectName%");
/* Hibernate:
select
count(task0_.id) as col_0_0_
from
tb_task task0_
inner join
tb_project project1_
on task0_.project_id=project1_.id
where
project1_.project_name like ?*/
return null ;
}
}
}
4.實體類task代碼如下
@Entity
@Table(name = "tb_task")
public class Task {
private Long id ;
private String taskName ;
private Date createTime ;
private Project project;
private String taskDetail ;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "task_name")
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
@Column(name = "create_time")
@DateTimeFormat(pattern = "yyyy-MM-dd hh:mm:ss")
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
@Column(name = "task_detail")
public String getTaskDetail() {
return taskDetail;
}
public void setTaskDetail(String taskDetail) {
this.taskDetail = taskDetail;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "project_id")
public Project getProject() {
return project;
}
public void setProject(Project project) {
this.project = project;
}
}
通過重寫toPredicate方法,返回一個查詢 Predicate,spring data jpa會幫我們進行查詢。
也許你覺得,每次都要寫一個類來實現Specification很麻煩,那或許你可以這麼寫
public class TaskSpec {
public static Specification<Task> method1(){
return new Specification<Task>(){
@Override
public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return null;
}
};
}
public static Specification<Task> method2(){
return new Specification<Task>(){
@Override
public Predicate toPredicate(Root<Task> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return null;
}
};
}
}
那麼用的時候,我們就這麼用
Page<Task> tasks = this.taskDao.findAll(TaskSpec.method1(), pageReq);
最後,結合上一篇博客排除空值:https://blog.csdn.net/HD243608836/article/details/104562241
~~~~~~~~~~~~~~~~~~~~~~~~~~~
節選自:https://blog.csdn.net/qq_30054997/article/details/79420141