Spring Data JPA實(shí)現(xiàn)動(dòng)態(tài)條件與范圍查詢實(shí)例代碼
Spring Data JPA為我們提供了Query With Example來(lái)實(shí)現(xiàn)動(dòng)態(tài)條件查詢,當(dāng)查詢條件為空的時(shí)候,我們不用做大量的條件判斷。但是Query With Example卻不支持范圍查詢(包括日期范圍,數(shù)值范圍查詢),本文通過(guò)Specification實(shí)現(xiàn)了既支持動(dòng)態(tài)條件查詢又支持范圍查詢的方法。
1 實(shí)現(xiàn)方式
1.1 范圍對(duì)象Range定義
import java.io.Serializable;
public class Range<E> implements Serializable {
private static final long serialVersionUID = 1L;
private String field;
private Comparable from;
private Comparable to;
private Boolean includeNull;
public Range(String field) {
this.field = field;
}
public Range(String field, Comparable from, Comparable to) {
this.field = field;
this.from = from;
this.to = to;
}
public Range(String field, Comparable from, Comparable to, Boolean includeNull) {
this.field = field;
this.from = from;
this.to = to;
this.includeNull = includeNull;
}
public Range(Range<E> other) {
this.field = other.getField();
this.from = other.getFrom();
this.to = other.getTo();
this.includeNull = other.getIncludeNull();
}
public String getField() {
return field;
}
public Comparable getFrom() {
return from;
}
public void setFrom(Comparable from) {
this.from = from;
}
public boolean isFromSet() {
return getFrom() != null;
}
public Comparable getTo() {
return to;
}
public void setTo(Comparable to) {
this.to = to;
}
public boolean isToSet() {
return getTo() != null;
}
public void setIncludeNull(boolean includeNull) {
this.includeNull = includeNull;
}
public Boolean getIncludeNull() {
return includeNull;
}
public boolean isIncludeNullSet() {
return includeNull != null;
}
public boolean isBetween() {
return isFromSet() && isToSet();
}
public boolean isSet() {
return isFromSet() || isToSet() || isIncludeNullSet();
}
public boolean isValid() {
if (isBetween()) {
return getFrom().compareTo(getTo()) <= 0;
}
return true;
}
}
1.2 example的Specification
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
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;
/**
* Created by wangyunfei on 2017/6/6.
*/
public class ByExampleSpecification<T> implements Specification<T> {
private final Example<T> example;
public ByExampleSpecification(Example<T> example) {
Assert.notNull(example, "Example must not be null!");
this.example = example;
}
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return QueryByExamplePredicateBuilder.getPredicate(root, cb, example);
}
}
1.3 Range的Specification
import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.List;
import static com.google.common.collect.Iterables.toArray;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.Boolean.FALSE;
import static java.lang.Boolean.TRUE;
/**
* Created by wangyunfei on 2017/6/6.
*/
public class ByRangeSpecification<T> implements Specification<T> {
private final List<Range<T>> ranges;
public ByRangeSpecification(List<Range<T>> ranges) {
this.ranges = ranges;
}
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
List<Predicate> predicates = newArrayList();
for (Range<T> range : ranges) {
if (range.isSet()) {
Predicate rangePredicate = buildRangePredicate(range, root, builder);
if (rangePredicate != null) {
if (!range.isIncludeNullSet() || range.getIncludeNull() == FALSE) {
predicates.add(rangePredicate);
} else {
predicates.add(builder.or(rangePredicate, builder.isNull(root.get(range.getField()))));
}
}
if (TRUE == range.getIncludeNull()) {
predicates.add(builder.isNull(root.get(range.getField())));
} else if (FALSE == range.getIncludeNull()) {
predicates.add(builder.isNotNull(root.get(range.getField())));
}
}
}
return predicates.isEmpty() ? builder.conjunction() : builder.and(toArray(predicates, Predicate.class));
}
private Predicate buildRangePredicate(Range<T> range, Root<T> root, CriteriaBuilder builder) {
if (range.isBetween()) {
return builder.between(root.get(range.getField()), range.getFrom(), range.getTo());
} else if (range.isFromSet()) {
return builder.greaterThanOrEqualTo(root.get(range.getField()), range.getFrom());
} else if (range.isToSet()) {
return builder.lessThanOrEqualTo(root.get(range.getField()), range.getTo());
}
return null;
}
}
1.4 自定義Repository與實(shí)現(xiàn)
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.io.Serializable;
import java.util.List;
@NoRepositoryBean
public interface WiselyRepository<E, PK extends Serializable> extends JpaRepository<E, PK> {
Page<E> queryByExampleWithRange(Example example,List<Range<E>> ranges, Pageable pageable);
}
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.io.Serializable;
import java.util.List;
import static org.springframework.data.jpa.domain.Specifications.where;
public class WiselyRepositoryImpl<E, PK extends Serializable> extends SimpleJpaRepository<E, PK> implements
WiselyRepository<E, PK> {
private final EntityManager entityManager;
public WiselyRepositoryImpl(JpaEntityInformation entityInformation, EntityManager entityManager) {
super(entityInformation, entityManager);
this.entityManager = entityManager;
}
@Override
public Page<E> queryByExampleWithRange(Example example, List<Range<E>> ranges, Pageable pageable) {
Specification<E> byExample = new ByExampleSpecification<>(example);
Specification<E> byRanges = new ByRangeSpecification<>(ranges);
return findAll(where(byExample).and(byRanges),pageable);
}
}
2 使用方式
2.1 開(kāi)啟支持
通過(guò)@EnableJpaRepositories(repositoryBaseClass = WiselyRepositoryImpl.class)開(kāi)啟對(duì)定義功能的支持。
2.2 示例
實(shí)體類
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {
@Id
@GeneratedValue
private Long id;
private String name;
private Integer height;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private Date birthday;
}
PersonRepository
public interface PersonRepository extends WiselyRepository<Person,Long> {
}
測(cè)試控制器
@RestController
@RequestMapping("/people")
public class PersonController {
@Autowired
PersonRepository personRepository;
@PostMapping
public ResponseEntity<Person> save(@RequestBody Person person){
Person p = personRepository.save(person);
return new ResponseEntity<Person>(p, HttpStatus.CREATED);
}
@GetMapping
public ResponseEntity<Page<Person>> query(Person person,
@DateTimeFormat(pattern = "yyyy-MM-dd")Date startDate,
@DateTimeFormat(pattern = "yyyy-MM-dd")Date endDate,
Integer startHeight,
Integer endHeight,
Pageable pageable){
Example<Person> personExample = Example.of(person);
List<Range<Person>> ranges = newArrayList();
Range<Person> birthRange = new Range<Person>("birthday",startDate,endDate);
Range<Person> heightRange = new Range<Person>("height",startHeight,endHeight);
ranges.add(birthRange);
ranges.add(heightRange);
Page<Person> page = personRepository.queryByExampleWithRange(personExample,ranges,pageable);
return new ResponseEntity<Page<Person>>(page,HttpStatus.OK);
}
}
源碼地址:https://github.com/wiselyman/query_with_example_and_range
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Spring Data JPA實(shí)現(xiàn)動(dòng)態(tài)查詢的兩種方法
- spring data jpa使用詳解(推薦)
- Spring Data Jpa的四種查詢方式詳解
- Spring Data JPA 實(shí)現(xiàn)多表關(guān)聯(lián)查詢的示例代碼
- Spring Data JPA 復(fù)雜/多條件組合分頁(yè)查詢
- Spring?Data?Jpa?復(fù)雜查詢方式總結(jié)(多表關(guān)聯(lián)及自定義分頁(yè))
- Spring Data JPA調(diào)用存儲(chǔ)過(guò)程實(shí)例代碼
- Spring Data JPA的作用和用法小結(jié)
相關(guān)文章
IntelliJ?IDEA?2022.2?正式發(fā)布新功能體驗(yàn)
IntelliJ?IDEA?2022.2為遠(yuǎn)程開(kāi)發(fā)功能帶來(lái)了多項(xiàng)質(zhì)量改進(jìn),使其更美觀、更穩(wěn)定,新版本還具有多項(xiàng)值得注意的升級(jí)和改進(jìn),下面跟隨小編一起看看IDEA?2022.2新版本吧2022-08-08
Trie樹(shù)(字典樹(shù))的介紹及Java實(shí)現(xiàn)
Trie樹(shù),又稱字典樹(shù)或前綴樹(shù),關(guān)于它的結(jié)構(gòu)就不詳細(xì)介紹了。Trie樹(shù)在單詞統(tǒng)計(jì)、前綴匹配等很多方面有很大用處。下面這篇文章主要介紹了Trie樹(shù),以及Java實(shí)現(xiàn)如何Trie樹(shù),有需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-02-02
Java Web請(qǐng)求與響應(yīng)實(shí)例詳解
這篇文章主要介紹了Java Web請(qǐng)求與響應(yīng)實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-05-05
Java Stream 流實(shí)現(xiàn)合并操作示例
這篇文章主要介紹了Java Stream 流實(shí)現(xiàn)合并操作,結(jié)合實(shí)例形式詳細(xì)分析了Java Stream 流實(shí)現(xiàn)合并操作原理與相關(guān)注意事項(xiàng),需要的朋友可以參考下2020-05-05
Java并發(fā)編程之阻塞隊(duì)列(BlockingQueue)詳解
這篇文章主要介紹了詳解Java阻塞隊(duì)列(BlockingQueue)的實(shí)現(xiàn)原理,阻塞隊(duì)列是Java util.concurrent包下重要的數(shù)據(jù)結(jié)構(gòu),有興趣的可以了解一下2021-09-09
Java數(shù)組與二維數(shù)組及替換空格實(shí)戰(zhàn)真題講解
數(shù)組對(duì)于每一門編程語(yǔ)言來(lái)說(shuō)都是重要的數(shù)據(jù)結(jié)構(gòu)之一,當(dāng)然不同語(yǔ)言對(duì)數(shù)組的實(shí)現(xiàn)及處理也不盡相同。Java?語(yǔ)言中提供的數(shù)組是用來(lái)存儲(chǔ)固定大小的同類型元素,這篇文章主要介紹了Java數(shù)組與二維數(shù)組及替換空格實(shí)戰(zhàn)真題講解2022-07-07

