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的同学有所帮助,也算是我们对社区的回馈:)