扩展Spring Data QBE实现动态范围查询
发表于:2025-01-29 作者:千家信息网编辑
千家信息网最后更新 2025年01月29日,Spring Data JPA提供了Query by Example (QBE) 查询技术,实现了动态条件查询,不必再写烦琐的条件判断。但QBE不支持范围查询,本文结合QBE和Specificatio
千家信息网最后更新 2025年01月29日扩展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安全错误
数据库的锁怎样保障安全
网络安全法草案英文版
数据库级联设计
云计算数据库工程师
2821网络安全宣传周宣传视频
江苏网络技术服务价目表
xsx设置代理服务器
贵州语音网络技术服务市场价
青岛阿里巴巴网络技术公司
司法网络安全战
重庆高科技软件开发
七日杀服务器时间流逝
网络安全与技术视频教程
高新区远程指导软件开发代理商
依玛士电话卡喷码软件开发包
禄劝天气预报软件开发
概要设计是数据库设计吗
隶书下载软件开发
即时通讯软件开发文档
软件开发哪家好找聚顶科技在线
oracle数据库生僻字
关于网络安全的设计论文
数据库级联设计
2014年 网络安全
天使之战抖音服务器有脚本吗
常见的软件开发类型
如何用数据库生成花名册
网络安全监测必须具备资质
软件开发交接文档模板下载
网络安全监控漏洞
app 如何上传服务器