最近在项目中使用到了spring data,Spring Data是一个用于简化数据库访问,并支持云服务的开源框架。其主要目标是使得对数据的访问变得方便快捷,并支持map-reduce框架和云计算数据服务。
Spring提供了repository共我们使用,repository提供了几个诸如:findsave delete等方法来供我们在简单的操作数据库,但是当我们的程序中涉及到很多不确定项目的动态查询的时候,就需要我们动态的组建查询条件,可以使用jpa的Specification来实现,在Specification接口只定义了一个方法:
Predicate toPredicate(Root
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 方法构建。
我们可以重写这个方法来实现:
在reposity中定义find方法,传入参数类型为Specification
PagefindAll(Specification specification ,Pageable pageable);
我们定义一个类Criteria实现Specification接口,在类中重写方法toPredicate,动态拼接查询条件我在此自定义了一个类sqlMessageList,是一个SqlMessage类的list,SqlMessage类中包含查询的类型type,查询的字段名name,查询的值value,具体样例代码如下:
@Override public Predicate toPredicate(Root<Object> root, CriteriaQuery> query, CriteriaBuilder cb) { if (sqlMessageList.size() != 0) { String type1 = sqlMessageList.get(0).getType(); String name1 = sqlMessageList.get(0).getName(); String value1 = sqlMessageList.get(0).getValue(); PathpathName1 = root.get(name1) ; Predicate predicate; //根据入参sqlMessageList中type来匹配查询条件 //eq:等于 lk:模糊查询 neq:不等于 gt:大于 //lt:小于 lteq:小于等于 gteq:大于等于 switch (type1) { case "eq": predicate = cb.equal(pathName1, value1); break; case "lk": value1 = "%" + value1 + "%"; predicate = cb.like(pathName1, value1); break; case "neq": predicate = cb.notEqual(pathName1, value1); break; case "gt": predicate = cb.greaterThan(pathName1, value1); break; case "lt": predicate = cb.lessThan(pathName1, value1); break; case "lteq": predicate = cb.lessThanOrEqualTo(pathName1, value1); break; case "gteq": predicate = cb.greaterThanOrEqualTo(pathName1, value1); break; default: predicate = cb.equal(pathName1, value1); break; } for (int i = 1; i < sqlMessageList.size(); i++) { String type = sqlMessageList.get(i).getType(); String name = sqlMessageList.get(i).getName(); String value = sqlMessageList.get(i).getValue(); PathpathName = root.get(name) ; switch (type) { case "eq": predicate = cb.and(cb.equal(pathName, value), predicate); break; case "lk": value = "%" + value + "%"; predicate = cb.and(cb.like(pathName, value), predicate); break; case "neq": predicate = cb.and(cb.notEqual(pathName, value), predicate); break; case "gt": predicate = cb.and(cb.greaterThan(pathName, value), predicate); break; case "lt": predicate = cb.and(cb.lessThan(pathName, value), predicate); break; case "lteq": predicate = cb.and(cb.lessThanOrEqualTo(pathName, value), predicate); break; case "gteq": predicate = cb.and(cb.greaterThanOrEqualTo(pathName, value), predicate); break; default: predicate = cb.and(cb.equal(pathName, value), predicate); break; } } query.where(predicate); } return null; }
其中 predicate = cb.and()即实现拼接查询条件,实现查询条件的动态拼接。最终调用CriteriaQuery的where方法执行查询语句。
当我们在service层中调用repository查询方法findAll时,new一个Criteria对象并给其sqlMessageList成员初始化后将其作为参数传入findAll方法中即可。