jpa-spec github: https://github.com/wenhao/jpa-spec
使用这个框架可以简化我们拼条件的复杂度,如下代码:
public Page<Person> findAll(SearchRequest request) { Specification<Person> specification = Specifications.<Person>and() .eq(StringUtils.isNotBlank(request.getName()), "name", request.getName()) .gt("age", 18) .between("birthday", new Date(), new Date()) .like("nickName", "%og%") .build(); Sort sort = Sorts.builder() .desc(StringUtils.isNotBlank(request.getName()), "name") .asc("birthday") .build(); return personRepository.findAll(specification, new PageRequest(0, 15, sort)); }
这是一个分页+排序的查询。
但如果我们使用的是数据库特定的函数,这个框架提供的方法就不够用了,需要我们扩展:
我们使用的是oracle数据库,它的函数如bitand, instr就需要我们扩展:
jpa-spec bitand扩展:
/** * Oracle bitand函数 计算扣款规则rulebit * * @author :hkk * @date :Created in 2019/7/24 10:34 */ public class BitandSpecification<T> extends AbstractSpecification<T> { private String property; private List<BigDecimal> values; public BitandSpecification(String property, List<BigDecimal> values) { this.property = property; this.values = values; } @Override public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) { BigDecimal sum = values.stream().reduce(BigDecimal::add).get(); LiteralExpression<BigDecimal> literalExpression = new LiteralExpression<>(null, sum); Expression<BigDecimal> ruleBit = cb.function("bitand", BigDecimal.class, root.get(property), literalExpression); return cb.greaterThan(ruleBit, BigDecimal.ZERO); } }
jpa-spec instr扩展:
/** * Oracle instr函数 计算扣款规则rulebit * * @author :hkk * @date :Created in 2019/7/24 10:34 */ public class IntstrSpecification<T> extends AbstractSpecification<T> { private String property; private String value; public IntstrSpecification(String property, String value) { this.property = property; this.value = value; } @Override public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) { LiteralExpression literalExpression = new LiteralExpression(null, value); Expression<BigDecimal> instr = cb.function("instr", BigDecimal.class, root.get(property), literalExpression); return cb.greaterThan(instr, BigDecimal.ZERO); } }
然后,我们再修改PredicateBuilder类:增加两个方法:
/** * oracle 函数bitand * @param property * @param var * @return */ public PredicateBuilder<T> bitand(String property, List var) { if (!CollectionUtils.isEmpty(var)) { this.predicate(true, new BitandSpecification(property, var)); } return this; } /** * oracle 函数instr * @param property * @param var * @return */ public PredicateBuilder<T> instr(String property, String var) { if (StringUtils.isNotBlank(var)) { this.predicate(true, new IntstrSpecification(property, var)); } return this; }
同时我们增加了一些方法,传入参数为空时的判断,减少开发人员的代码量:
/** * value不为空时 in * @param property * @param values * @return */ public PredicateBuilder<T> inWhereHasValues(String property, List values) { if (!CollectionUtils.isEmpty(values)) { this.in(property, values); } return this; } /** * 当values为空是 is null * 当values不为空时 in * @param property * @param values * @return */ public PredicateBuilder<T> inAndNull(String property, List values) { if (CollectionUtils.isEmpty(values)) { return this.eq(property, values); } return in(property,values); } public PredicateBuilder<T> eqWhereHasValue(String property, Object... values) { if (values == null) { return this; } if (values.length == 1) { if (values[0] == null) { return this; } if (StringUtils.isBlank(String.valueOf(values[0]))) { return this; } } return eq(true, property, values); }
希望对刚入门jps的同学有所帮助,也算是我们对社区的回馈:)