order
This paper mainly studies the dynamic query of jpa
javax.persistence.criteria
jpa absorbs criteria from hibernate, and it can also realize end-to-end dynamic query by using criteria and parsing url query syntax.
The following shows the implementation of spring side branch 4.
springside branch 4
SearchFilter
/******************************************************************************* * Copyright (c) 2005, 2014 springside.github.io * * Licensed under the Apache License, Version 2.0 (the "License"); *******************************************************************************/ package org.springside.modules.persistence; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.lang3.StringUtils; import com.google.common.collect.Maps; public class SearchFilter { public enum Operator { EQ, LIKE, GT, LT, GTE, LTE } public String fieldName; public Object value; public Operator operator; public SearchFilter(String fieldName, Operator operator, Object value) { this.fieldName = fieldName; this.value = value; this.operator = operator; } /** * searchParams The format of key in is operator? Fieldname */ public static Map<String, SearchFilter> parse(Map<String, Object> searchParams) { Map<String, SearchFilter> filters = Maps.newHashMap(); for (Entry<String, Object> entry : searchParams.entrySet()) { // Filter out null values String key = entry.getKey(); Object value = entry.getValue(); if (StringUtils.isBlank((String) value)) { continue; } // Split operator and filedAttribute String[] names = StringUtils.split(key, "_"); if (names.length != 2) { throw new IllegalArgumentException(key + " is not a valid search filter name"); } String filedName = names[1]; Operator operator = Operator.valueOf(names[0]); // Create searchFilter SearchFilter filter = new SearchFilter(filedName, operator, value); filters.put(key, filter); } return filters; } }
Several operators EQ, LIKE, GT, LT, GTE, LTE are defined here You can receive query conditions from the controller of mvc and convert them to SearchFilter
DynamicSpecifications
/******************************************************************************* * Copyright (c) 2005, 2014 springside.github.io * * Licensed under the Apache License, Version 2.0 (the "License"); *******************************************************************************/ package org.springside.modules.persistence; import java.util.Collection; import java.util.List; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.apache.commons.lang3.StringUtils; import org.springframework.data.jpa.domain.Specification; import org.springside.modules.utils.Collections3; import com.google.common.collect.Lists; public class DynamicSpecifications { public static <T> Specification<T> bySearchFilter(final Collection<SearchFilter> filters, final Class<T> entityClazz) { return new Specification<T>() { @Override public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) { if (Collections3.isNotEmpty(filters)) { List<Predicate> predicates = Lists.newArrayList(); for (SearchFilter filter : filters) { // The nested path translate, such as the filedName named "user. Name" of the Task, is converted to the Task.user.name attribute String[] names = StringUtils.split(filter.fieldName, "."); Path expression = root.get(names[0]); for (int i = 1; i < names.length; i++) { expression = expression.get(names[i]); } // logic operator switch (filter.operator) { case EQ: predicates.add(builder.equal(expression, filter.value)); break; case LIKE: predicates.add(builder.like(expression, "%" + filter.value + "%")); break; case GT: predicates.add(builder.greaterThan(expression, (Comparable) filter.value)); break; case LT: predicates.add(builder.lessThan(expression, (Comparable) filter.value)); break; case GTE: predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.value)); break; case LTE: predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.value)); break; } } // Combine all conditions with and if (!predicates.isEmpty()) { return builder.and(predicates.toArray(new Predicate[predicates.size()])); } } return builder.conjunction(); } }; } }
This is mainly to transform the query conditions constructed by SearchFilter into the corresponding Predicate, and then construct the Specification of jpa to complete the transformation of dynamic query conditions.
Summary
By using the dynamic specifications of springside and mapping the parameters of mvc to SearchFilter, you can also implement a set of end-to-end dynamic queries by yourself.
Note that springside has deleted these codes in the latest version. You need to find them in branch 4.