Spring data JPA中使用Specifications动态构建查询

有时我们在查询某个实体的时候,给定的条件是不固定的,这是我们就需要动态构建相应的查询语句,在JPA2.0中我们可以通过Criteria接口查询,JPA criteria查询.相比JPQL,其优势是类型安全,更加的面向对象.而在Spring data JPA中相应的接口是JpaSpecificationExecutor,这个接口基本是围绕着Specification接口来定义的。Specification接口中只定义了如下一个方法:

 
 
  1. Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);

我们只需要重写这个方法即可,相关知识请自行查阅JPA Criteria查询  

过滤条件

1:过滤条件会被应用到SQL语句的FROM子句中。在criteria 查询中,查询条件通过Predicate或Expression实例应用到CriteriaQuery对象上。

2:这些条件使用 CriteriaQuery .where 方法应用到CriteriaQuery 对象上

3:CriteriaBuilder也作为Predicate实例的工厂,通过调用CriteriaBuilder 的条件方法( equal,notEqual, gt, ge,lt, le,between,like等)创建Predicate对象。

4:复合的Predicate 语句可以使用CriteriaBuilder的and, or andnot 方法构建。

相关代码如下,在这个例子中我们定义了2个类Articel和User类

Article:

 
 
  1. @Entity
  2. @Table(name = "t_article")
  3. public class Article implements Serializable{
  4.     private static final long serialVersionUID = 6112067846581696118L;
  5.     @Id
  6.     @GeneratedValue
  7.     private Integer aid;
  8.     private String title;
  9.     @Temporal(TemporalType.TIMESTAMP)
  10.     private Date postTime;
  11.     @Temporal(TemporalType.TIMESTAMP)
  12.     private Date lastEditTime;
  13.     private String ip;
  14.     private String tag;
  15.     private boolean forbidComment;//禁止评论
  16.     @ManyToOne
  17.     @JoinColumn(name = "uid")
  18.     private User user;
  19.  
  20.     private boolean recommend;//是否是推荐
  21.     @Temporal(TemporalType.TIMESTAMP)
  22.     private Date recommendTime;//推荐时间
  23.  
  24.     //setter/getter略
  25. }

User:

 
 
  1. @Entity
  2. @Table(name = "t_user")
  3. public class User implements Serializable {
  4.  
  5.     private static final long serialVersionUID = 3703405133265901053L;
  6.     @Id
  7.     @GeneratedValue
  8.     private Integer uid;
  9.     private String nickname;
  10.     private String password;
  11.      //setter/getter略
  12. }

其中user和article是一对多的关系,是单向的

封装的查询实体SearchArticle

 
 
  1. public class SearchArticle implements Serializable{
  2.     private static final long serialVersionUID = -1082122462716689486L;
  3.     private int page = 1;
  4.     private int limit;
  5.     @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss")
  6.     private Date postTimeStart;
  7.     @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss")
  8.     private Date postTimeEnd;
  9.     @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss")
  10.     private Date recTimeStart;
  11.     @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME,pattern = "yyyy-MM-dd HH:mm:ss")
  12.     private Date recTimeEnd;
  13.  
  14.     private String nickname;
  15. }

下面是查询方法

 
 
  1.     @Autowired
  2.     private ArticleRepository articleRepository;
  3.     
  4. @Override
  5.     public QueryResult<ArticleModel> findArticle(SearchArticle searchArticle) {
  6.         Sort sort = new Sort(Sort.Direction.DESC,"postTime");
  7.         Specification<Article> specification = getWhereClause(searchArticle);
  8.         Page<Article> all = articleRepository.findAll(specification, new PageRequest(searchArticle.getPage() - 1, searchArticle.getLimit(),sort));
  9.         QueryResult<ArticleModel> result = new QueryResult<>();
  10.         List<ArticleModel> list = new ArrayList<>(searchArticle.getLimit());
  11.         for (Article article:all.getContent()){
  12.             ArticleModel model = new ArticleModel(article.getAid(),article.getTitle(),article.getPostTime(),article.isRecommend(),
  13.                     article.getRecommendTime(),article.getIp(),article.getUser().getUid(),article.getUser().getNickname());
  14.             list.add(model);
  15.         }
  16.         result.setRows(list);
  17.         result.setTotal(all.getTotalElements());
  18.         return result;
  19.     }
  20.  
  21.     /**
  22.      * 动态生成where语句
  23.      * @param searchArticle
  24.      * @return
  25.      */
  26.     private Specification<Article> getWhereClause(final SearchArticle searchArticle){
  27.         return new Specification<Article>() {
  28.             @Override
  29.             public Predicate toPredicate(Root<Article> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  30.                 List<Predicate> predicate = new ArrayList<>();
  31.                 if(searchArticle.getPostTimeStart()!=null){
  32.                     predicate.add(cb.greaterThanOrEqualTo(root.get("postTime").as(Date.class), searchArticle.getPostTimeStart()));
  33.                 }
  34.                 if(searchArticle.getPostTimeEnd()!=null){
  35.                     predicate.add(cb.lessThanOrEqualTo(root.get("postTime").as(Date.class), searchArticle.getPostTimeEnd()));
  36.                 }
  37.                 if(searchArticle.getRecTimeStart()!=null){
  38.                     predicate.add(cb.greaterThanOrEqualTo(root.get("recommendTime").as(Date.class), searchArticle.getRecTimeStart()));
  39.                 }
  40.                 if (searchArticle.getRecTimeEnd()!=null){
  41.                     predicate.add(cb.lessThanOrEqualTo(root.get("recommendTime").as(Date.class), searchArticle.getRecTimeEnd()));
  42.                 }
  43.                 if (StringUtils.isNotBlank(searchArticle.getNickname())){
  44.                     //两张表关联查询
  45.                     Join<Article,User> userJoin = root.join(root.getModel().getSingularAttribute("user",User.class),JoinType.LEFT);
  46.                     predicate.add(cb.like(userJoin.get("nickname").as(String.class), "%" + searchArticle.getNickname() + "%"));
  47.                 }
  48.                 Predicate[] pre = new Predicate[predicate.size()];
  49.                 return query.where(predicate.toArray(pre)).getRestriction();
  50.             }
  51.         };
  52.     }

其中的 ArticleRepository接口如下,spring data jpa不需要你自己实现dao的接口

 
 
  1. public interface ArticleRepository extends JpaRepository<Article,Integer>,JpaSpecificationExecutor<Article> {}

通过以上的步骤,我们就能构建相应的查询sql了,使用这个接口要对JPA2.0中Criteria查询有一定的了解

文章来源 java分享网 http://www.itjavaer.com/article/35

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值