扩展Spring Data QBE实现动态范围查询
发表于:2024-11-15 作者:千家信息网编辑
千家信息网最后更新 2024年11月15日,Spring Data JPA提供了Query by Example (QBE) 查询技术,实现了动态条件查询,不必再写烦琐的条件判断。但QBE不支持范围查询,本文结合QBE和Specificatio
千家信息网最后更新 2024年11月15日扩展Spring Data QBE实现动态范围查询
Spring Data JPA提供了Query by Example (QBE) 查询技术,实现了动态条件查询,不必再写烦琐的条件判断。但QBE不支持范围查询,本文结合QBE和Specification实现了动态范围查询。
本文以汪云飞-Spring Data JPA实现动态条件与范围查询实例代码为基础修改,利用org.springframework.data.domain.Range替换了自定义实现,支持Matching Any,保持了原代码的基本结构。源码地址 https://github.com/sunjc/heroes-api
实现代码
FieldRange
import org.springframework.data.domain.Range;import org.springframework.data.domain.Range.Bound;import static org.springframework.data.domain.Range.Bound.inclusive;public class FieldRange> { private String field; private Range range; public FieldRange(String field, T lower, T upper) { this.field = field; this.range = of(lower, upper); } private Range of(T lower, T upper) { Bound lowerBound = Bound.unbounded(); Bound upperBound = Bound.unbounded(); if (lower != null) { lowerBound = inclusive(lower); } if (upper != null) { upperBound = inclusive(upper); } return Range.of(lowerBound, upperBound); } public String getField() { return field; } public Range getRange() { return range; }}
ExampleSpecification
提取Example的Specification,SimpleJpaRepository内含有此类,是私有的。
import org.springframework.data.domain.Example;import org.springframework.data.jpa.domain.Specification;import org.springframework.util.Assert;import javax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Predicate;import javax.persistence.criteria.Root;import static org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder.getPredicate;public class ExampleSpecification implements Specification { private static final long serialVersionUID = 1L; private final Example example; //NOSONAR public ExampleSpecification(Example example) { Assert.notNull(example, "Example must not be null!"); this.example = example; } @Override public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder criteriaBuilder) { return getPredicate(root, criteriaBuilder, example); }}
RangeSpecification
import org.springframework.data.jpa.domain.Specification;import javax.persistence.criteria.*;import java.util.Optional;public class RangeSpecification> implements Specification { private FieldRange fieldRange; //NOSONAR public RangeSpecification(FieldRange fieldRange) { this.fieldRange = fieldRange; } @Override public Predicate toPredicate(Root root, CriteriaQuery> query, CriteriaBuilder builder) { Optional lower = fieldRange.getRange().getLowerBound().getValue(); Optional upper = fieldRange.getRange().getUpperBound().getValue(); Path path = root.get(fieldRange.getField()); if (lower.isPresent() && upper.isPresent()) { return builder.between(path, lower.get(), upper.get()); } if (lower.isPresent()) { return builder.greaterThanOrEqualTo(path, lower.get()); } if (upper.isPresent()) { return builder.lessThanOrEqualTo(path, upper.get()); } return null; }}
自定义Repository
WiselyRepository接口
import org.itrunner.heroes.repository.specifications.FieldRange;import org.springframework.data.domain.Example;import org.springframework.data.domain.Page;import org.springframework.data.domain.Pageable;import org.springframework.data.jpa.repository.JpaRepository;import org.springframework.data.repository.NoRepositoryBean;import java.util.List;@NoRepositoryBeanpublic interface WiselyRepository extends JpaRepository { //NOSONAR Page findByExampleAndRange(Example example, List> fieldRanges, Pageable pageable); List findByExampleAndRange(Example example, List> fieldRanges);}
WiselyRepository实现
import org.itrunner.heroes.repository.WiselyRepository;import org.itrunner.heroes.repository.specifications.ExampleSpecification;import org.itrunner.heroes.repository.specifications.FieldRange;import org.itrunner.heroes.repository.specifications.RangeSpecification;import org.springframework.data.domain.Example;import org.springframework.data.domain.Page;import org.springframework.data.domain.Pageable;import org.springframework.data.jpa.domain.Specification;import org.springframework.data.jpa.repository.support.JpaEntityInformation;import org.springframework.data.jpa.repository.support.SimpleJpaRepository;import javax.persistence.EntityManager;import java.util.ArrayList;import java.util.List;import static org.springframework.data.jpa.domain.Specification.where;public class WiselyRepositoryImpl extends SimpleJpaRepository implements WiselyRepository { //NOSONAR public WiselyRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) { super(entityInformation, entityManager); } @Override public Page findByExampleAndRange(Example example, List> fieldRanges, Pageable pageable) { return findAll(specifications(example, fieldRanges), pageable); } @Override public List findByExampleAndRange(Example example, List> fieldRanges) { return findAll(specifications(example, fieldRanges)); } private Specification specifications(Example example, List> fieldRanges) { boolean allMatching = example.getMatcher().isAllMatching(); Specification byExample = new ExampleSpecification<>(example); List> byRanges = getRangeSpecifications(fieldRanges); return conjunction(byExample, byRanges, allMatching); } private List> getRangeSpecifications(List> fieldRanges) { List> rangeSpecifications = new ArrayList<>(); for (FieldRange fieldRange : fieldRanges) { rangeSpecifications.add(new RangeSpecification<>(fieldRange)); } return rangeSpecifications; } private Specification conjunction(Specification byExample, List> byRanges, boolean allMatching) { Specification specification = where(byExample); for (Specification rangeSpecification : byRanges) { if (allMatching) { specification = specification.and(rangeSpecification); } else { specification = specification.or(rangeSpecification); } } return specification; }}
使用示例
启用WiselyRepositoryImpl:
@EnableJpaRepositories(repositoryBaseClass = WiselyRepositoryImpl.class)
调用范围查询:
public Page findHeroes(Hero hero, Date startDate, Date endDate, int minAge, int maxAge, Pageable pageable) { List> fieldRanges = new ArrayList<>(); fieldRanges.add(new FieldRange<>("birthday", startDate, endDate)); fieldRanges.add(new FieldRange<>("age", minAge, maxAge)); return heroRepository.findByExampleAndRange(of(hero), fieldRanges, pageable);}
查询
范围
动态
代码
条件
支持
烦琐
地址
基础
实例
技术
接口
源码
示例
结构
云飞
私有
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全公司宣传方式有哪些
网络安全文明校园演讲稿
太荒初境服务器版本过低
马里奥战争mc服务器
慈溪一站式软件开发教程
山东联通公司网络技术
学生服务器渗透测试
现场总线与网络技术
怎样共享服务器
重庆程序软件开发价钱
GCM服务器是什么
机器人软件开发是干什么的
肽图分析数据库
无线区域网络技术
相城区运营网络技术服务价格
中国网络安全技能大赛特色
软件开发课程与教学
sql数据库释放空间
天津渣打银行软件开发
服务器开启安全审计功能
黑客团伙入侵网站服务器
防火墙用服务器好还是软件好
网络技术要学什么软件
win7安装ftp服务器
食品外文数据库有哪些
现场总线与网络技术
厦门哪里招聘网络技术员
连接虚拟机的数据库
服务器8163
协同软件开发介绍