有時咱們在查詢某個實體的時候,給定的條件是不固定的,這是咱們就須要動態 構建相應的查詢語句,在JPA2.0中咱們能夠經過Criteria接口查詢,JPA criteria查詢.相比JPQL,其優點是類型安全,更加的面向對象.而在Spring data JPA中相應的接口是JpaSpecificationExecutor,這個接口基本是圍繞着Specification接口來定義的。 Specification接口中只定義了以下一個方法:web
1
|
Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);
|
咱們只須要重寫這個方法便可,相關知識請自行查閱JPA Criteria查詢 spring
過濾條件sql
1:過濾條件會被應用到SQL語句的FROM子句中。在criteria 查詢中,查詢條件經過Predicate或Expression實例應用到CriteriaQuery對象上。安全
2:這些條件使用 CriteriaQuery .where 方法應用到CriteriaQuery 對象上less
3:CriteriaBuilder也做爲Predicate實例的工廠,經過調用CriteriaBuilder 的條件方法( equal,notEqual, gt, ge,lt, le,between,like等)建立Predicate對象。ide
4:複合的Predicate 語句能夠使用CriteriaBuilder的and, or andnot 方法構建。post
相關代碼以下,在這個例子中咱們定義了2個類Articel和User類ui
Article:spa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
@Entity
@Table(name = "t_article")
public class Article implements Serializable{
private static final long serialVersionUID = 6112067846581696118L;
@Id
@GeneratedValue
private Integer aid;
private String title;
@Temporal(TemporalType.TIMESTAMP)
private Date postTime;
@Temporal(TemporalType.TIMESTAMP)
private Date lastEditTime;
private String ip;
private String tag;
private boolean forbidComment;//禁止評論
@ManyToOne
@JoinColumn(name = "uid")
private User user;
private boolean recommend;//是不是推薦
@Temporal(TemporalType.TIMESTAMP)
private Date recommendTime;//推薦時間
//setter/getter略
}
|
User:code
1
2
3
4
5
6
7
8
9
10
11
12
|
@Entity
@Table(name = "t_user")
public class User implements Serializable {
private static final long serialVersionUID = 3703405133265901053L;
@Id
@GeneratedValue
private Integer uid;
private String nickname;
private String password;
//setter/getter略
}
|
其中user和article是一對多的關係,是單向的
封裝的查詢實體SearchArticle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class SearchArticle implements Serializable{
private static final long serialVersionUID = -1082122462716689486L;
private int page = 1;
private int limit;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss")
private Date postTimeStart;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss")
private Date postTimeEnd;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss")
private Date recTimeStart;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss")
private Date recTimeEnd;
private String nickname;
|
下面是查詢方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
@Autowired
private ArticleRepository articleRepository;
@Override
public QueryResult<ArticleModel> findArticle(SearchArticle searchArticle) {
Sort sort = new Sort(Sort.Direction.DESC,"postTime");
Specification<Article> specification = getWhereClause(searchArticle);
Page<Article> all = articleRepository.findAll(specification, new PageRequest(searchArticle.getPage() - 1, searchArticle.getLimit(),sort));
QueryResult<ArticleModel> result = new QueryResult<>();
List<ArticleModel> list = new ArrayList<>(searchArticle.getLimit());
for (Article article:all.getContent()){
ArticleModel model = new ArticleModel(article.getAid(),article.getTitle(),article.getPostTime(),article.isRecommend(),
article.getRecommendTime(),article.getIp(),article.getUser().getUid(),article.getUser().getNickname());
list.add(model);
}
result.setRows(list);
result.setTotal(all.getTotalElements());
return result;
}
/**
* 動態生成where語句
* @param searchArticle
* @return
*/
private Specification<Article> getWhereClause(final SearchArticle searchArticle){
return new Specification<Article>() {
@Override
public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> predicate = new ArrayList<>();
if(searchArticle.getPostTimeStart()!=null){
predicate.add(cb.greaterThanOrEqualTo(root.get("postTime").as(Date.class), searchArticle.getPostTimeStart()));
}
if(searchArticle.getPostTimeEnd()!=null){
predicate.add(cb.lessThanOrEqualTo(root.get("postTime").as(Date.class), searchArticle.getPostTimeEnd()));
}
if(searchArticle.getRecTimeStart()!=null){
predicate.add(cb.greaterThanOrEqualTo(root.get("recommendTime").as(Date.class), searchArticle.getRecTimeStart()));
}
if (searchArticle.getRecTimeEnd()!=null){
predicate.add(cb.lessThanOrEqualTo(root.get("recommendTime").as(Date.class), searchArticle.getRecTimeEnd()));
}
if (StringUtils.isNotBlank(searchArticle.getNickname())){
//兩張表關聯查詢
Join<Article,User> userJoin = root.join(root.getModel().getSingularAttribute("user",User.class),JoinType.LEFT);
predicate.add(cb.like(userJoin.get("nickname").as(String.class), "%" + searchArticle.getNickname() + "%"));
}
Predicate[] pre = new Predicate[predicate.size()];
return query.where(predicate.toArray(pre)).getRestriction();
}
};
}
|
其中的 ArticleRepository接口以下,spring data jpa不須要你本身實現dao的接口
1
|
public interface ArticleRepository extends JpaRepository<Article,Integer>,JpaSpecificationExecutor<Article> {}
|
經過以上的步驟,咱們就能構建相應的查詢sql了,使用這個接口要對JPA2.0中Criteria查詢有必定的瞭解