feat: 优化查询方法
This commit is contained in:
52
pom.xml
52
pom.xml
@@ -15,7 +15,7 @@
|
||||
|
||||
<spring-boot.version>3.4.3</spring-boot.version>
|
||||
<spring-cloud.version>2024.0.1</spring-cloud.version>
|
||||
<eclipse-collections.version>11.1.0</eclipse-collections.version>
|
||||
<querydsl.version>5.1.0</querydsl.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@@ -30,7 +30,21 @@
|
||||
<dependency>
|
||||
<groupId>com.blinkfox</groupId>
|
||||
<artifactId>fenix-spring-boot-starter</artifactId>
|
||||
<version>3.0.0</version>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-apt</artifactId>
|
||||
<version>${querydsl.version}</version>
|
||||
<scope>provided</scope>
|
||||
<classifier>jakarta</classifier>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.querydsl</groupId>
|
||||
<artifactId>querydsl-jpa</artifactId>
|
||||
<version>${querydsl.version}</version>
|
||||
<classifier>jakarta</classifier>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -60,6 +74,40 @@
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.mysema.maven</groupId>
|
||||
<artifactId>apt-maven-plugin</artifactId>
|
||||
<version>1.1.3</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile-dsl</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>process</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
|
||||
<outputDirectory>target/generated-sources/java</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile-dsl</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-process</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
|
||||
<outputDirectory>target/generated-test-sources/java</outputDirectory>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<distributionManagement>
|
||||
<repository>
|
||||
<id>${releases.id}</id>
|
||||
|
||||
@@ -210,22 +210,22 @@ public class Query {
|
||||
}
|
||||
|
||||
public static class Between {
|
||||
private String start;
|
||||
private String end;
|
||||
private Object start;
|
||||
private Object end;
|
||||
|
||||
public String getStart() {
|
||||
public Object getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public void setStart(String start) {
|
||||
public void setStart(Object start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public String getEnd() {
|
||||
public Object getEnd() {
|
||||
return end;
|
||||
}
|
||||
|
||||
public void setEnd(String end) {
|
||||
public void setEnd(Object end) {
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,19 +5,44 @@ import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class ObjectHelper {
|
||||
/**
|
||||
* 判断对象是否为null
|
||||
*
|
||||
* @param obj 待检查的对象
|
||||
* @return 如果对象为null返回true,否则返回false
|
||||
*/
|
||||
public static boolean isNull(Object obj) {
|
||||
return obj == null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断对象是否不为null
|
||||
*
|
||||
* @param obj 待判断的对象
|
||||
* @return 如果对象不为null则返回true,否则返回false
|
||||
*/
|
||||
public static boolean isNotNull(Object obj) {
|
||||
return !isNull(obj);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断对象是否为空
|
||||
*
|
||||
* @param obj 待判断的对象
|
||||
* @return 如果对象为null或为空则返回true,否则返回false
|
||||
*/
|
||||
public static boolean isEmpty(Object obj) {
|
||||
// 首先判断对象是否为null
|
||||
if (isNull(obj)) return true;
|
||||
// 判断是否为集合类型
|
||||
else if (obj instanceof Collection<?> collection) return collection.isEmpty();
|
||||
// 判断是否为Map类型
|
||||
else if (obj instanceof Map<?, ?> map) return map.isEmpty();
|
||||
// 判断是否为字符序列类型
|
||||
else if (obj instanceof CharSequence sequence) return sequence.isEmpty();
|
||||
// 判断是否为各种基本类型数组
|
||||
else if (obj instanceof Object[] array) return array.length == 0;
|
||||
else if (obj instanceof byte[] array) return array.length == 0;
|
||||
else if (obj instanceof short[] array) return array.length == 0;
|
||||
@@ -27,10 +52,13 @@ public class ObjectHelper {
|
||||
else if (obj instanceof double[] array) return array.length == 0;
|
||||
else if (obj instanceof char[] array) return array.length == 0;
|
||||
else if (obj instanceof boolean[] array) return array.length == 0;
|
||||
// 判断是否为Optional类型
|
||||
else if (obj instanceof Optional<?> optional) return optional.isEmpty();
|
||||
// 其他情况认为对象不为空
|
||||
else return false;
|
||||
}
|
||||
|
||||
|
||||
public static boolean isNotEmpty(Object obj) {
|
||||
return !isEmpty(obj);
|
||||
}
|
||||
@@ -38,4 +66,44 @@ public class ObjectHelper {
|
||||
public static <T> T defaultIfNull(final T object, final T defaultValue) {
|
||||
return isNull(object) ? defaultValue : object;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断给定的类是否可比较
|
||||
*
|
||||
* @param clazz 待判断的类对象
|
||||
* @return 如果类是枚举、字符序列、可比较接口的实现类或基本数据类型则返回true,否则返回false
|
||||
*/
|
||||
public static boolean isComparable(Class<?> clazz) {
|
||||
if (isNull(clazz)) return false;
|
||||
// 判断类是否为可比较类型:枚举、字符序列、可比较接口实现类或基本数据类型
|
||||
return clazz.isEnum() ||
|
||||
CharSequence.class.isAssignableFrom(clazz) ||
|
||||
Comparable.class.isAssignableFrom(clazz) ||
|
||||
clazz.isPrimitive();
|
||||
}
|
||||
|
||||
public static boolean isComparable(Object obj) {
|
||||
if (isNull(obj)) return false;
|
||||
return isComparable(obj.getClass());
|
||||
}
|
||||
|
||||
public static boolean isCollection(Class<?> clazz) {
|
||||
if (isNull(clazz)) return false;
|
||||
return Collection.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public static boolean isCollection(Object obj) {
|
||||
if (isNull(obj)) return false;
|
||||
return isCollection(obj.getClass());
|
||||
}
|
||||
|
||||
public static boolean isString(Class<?> clazz) {
|
||||
if (isNull(clazz)) return false;
|
||||
return String.class.isAssignableFrom(clazz);
|
||||
}
|
||||
|
||||
public static boolean isString(Object obj) {
|
||||
if (isNull(obj)) return false;
|
||||
return isString(obj.getClass());
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,10 @@ package com.lanyuanxiaoyao.service.template.repository;
|
||||
|
||||
import com.blinkfox.fenix.jpa.FenixJpaRepository;
|
||||
import com.blinkfox.fenix.specification.FenixJpaSpecificationExecutor;
|
||||
import org.springframework.data.querydsl.QuerydslPredicateExecutor;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
import org.springframework.data.repository.query.QueryByExampleExecutor;
|
||||
|
||||
@NoRepositoryBean
|
||||
public interface SimpleRepository<E, ID> extends FenixJpaRepository<E, ID>, FenixJpaSpecificationExecutor<E>, QueryByExampleExecutor<E> {
|
||||
public interface SimpleRepository<E, ID> extends FenixJpaRepository<E, ID>, FenixJpaSpecificationExecutor<E>, QueryByExampleExecutor<E>, QuerydslPredicateExecutor<E> {
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.criteria.Root;
|
||||
import jakarta.transaction.Transactional;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
@@ -101,7 +102,7 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
var enumType = (Class<Enum>) javaType;
|
||||
return Enum.valueOf(enumType, enumName);
|
||||
} else {
|
||||
throw new IllegalArgumentException("枚举类型字段需要String类型的值");
|
||||
throw new IllegalArgumentException("枚举类型字段需要 String 类型的值");
|
||||
}
|
||||
}
|
||||
return value;
|
||||
@@ -120,10 +121,18 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
queryable.getNotNullEqual().forEach(column -> predicates.add(builder.isNotNull(column(root, column))));
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getEmpty())) {
|
||||
queryable.getEmpty().forEach(column -> predicates.add(builder.isEmpty(column(root, column))));
|
||||
queryable.getEmpty().forEach(column -> {
|
||||
var path = this.<Collection<Object>>column(root, column);
|
||||
checkCollection(path, column);
|
||||
predicates.add(builder.isEmpty(path));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getNotEmpty())) {
|
||||
queryable.getNotEmpty().forEach(column -> predicates.add(builder.isNotEmpty(column(root, column))));
|
||||
queryable.getNotEmpty().forEach(column -> {
|
||||
var path = this.<Collection<Object>>column(root, column);
|
||||
checkCollection(path, column);
|
||||
predicates.add(builder.isNotEmpty(path));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getEqual())) {
|
||||
queryable.getEqual().forEach((column, value) -> {
|
||||
@@ -138,22 +147,52 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getLike())) {
|
||||
queryable.getLike().forEach((column, value) -> predicates.add(builder.like(column(root, column), value)));
|
||||
queryable.getLike().forEach((column, value) -> {
|
||||
var path = column(root, column);
|
||||
checkString(path, column);
|
||||
checkString(value, column);
|
||||
predicates.add(builder.like(column(root, column), value));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getNotLike())) {
|
||||
queryable.getNotLike().forEach((column, value) -> predicates.add(builder.notLike(column(root, column), value)));
|
||||
queryable.getNotLike().forEach((column, value) -> {
|
||||
var path = column(root, column);
|
||||
checkString(path, column);
|
||||
checkString(value, column);
|
||||
predicates.add(builder.notLike(column(root, column), value));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getGreat())) {
|
||||
queryable.getGreat().forEach((column, value) -> predicates.add(builder.greaterThan(column(root, column), (Comparable<Object>) value)));
|
||||
queryable.getGreat().forEach((column, value) -> {
|
||||
var path = this.<Comparable<Object>>column(root, column);
|
||||
checkComparable(path, column);
|
||||
checkComparable(value, column);
|
||||
predicates.add(builder.greaterThan(path, (Comparable<Object>) value));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getLess())) {
|
||||
queryable.getLess().forEach((column, value) -> predicates.add(builder.lessThan(column(root, column), (Comparable<Object>) value)));
|
||||
queryable.getLess().forEach((column, value) -> {
|
||||
var path = this.<Comparable<Object>>column(root, column);
|
||||
checkComparable(path, column);
|
||||
checkComparable(value, column);
|
||||
predicates.add(builder.lessThan(path, (Comparable<Object>) value));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getGreatEqual())) {
|
||||
queryable.getGreatEqual().forEach((column, value) -> predicates.add(builder.greaterThanOrEqualTo(column(root, column), (Comparable<Object>) value)));
|
||||
queryable.getGreatEqual().forEach((column, value) -> {
|
||||
var path = this.<Comparable<Object>>column(root, column);
|
||||
checkComparable(path, column);
|
||||
checkComparable(value, column);
|
||||
predicates.add(builder.greaterThanOrEqualTo(path, (Comparable<Object>) value));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getLessEqual())) {
|
||||
queryable.getLessEqual().forEach((column, value) -> predicates.add(builder.lessThanOrEqualTo(column(root, column), (Comparable<Object>) value)));
|
||||
queryable.getLessEqual().forEach((column, value) -> {
|
||||
var path = this.<Comparable<Object>>column(root, column);
|
||||
checkComparable(path, column);
|
||||
checkComparable(value, column);
|
||||
predicates.add(builder.lessThanOrEqualTo(path, (Comparable<Object>) value));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getIn())) {
|
||||
queryable.getIn().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value)));
|
||||
@@ -162,14 +201,65 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
queryable.getNotIn().forEach((column, value) -> predicates.add(builder.in(column(root, column)).value(value).not()));
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getBetween())) {
|
||||
queryable.getBetween().forEach((column, value) -> predicates.add(builder.between(column(root, column), value.getStart(), value.getEnd())));
|
||||
queryable.getBetween().forEach((column, value) -> {
|
||||
var path = this.<Comparable<Object>>column(root, column);
|
||||
checkComparable(path, column);
|
||||
checkComparable(value, column);
|
||||
predicates.add(builder.between(column(root, column), (Comparable<Object>) value.getStart(), (Comparable<Object>) value.getEnd()));
|
||||
});
|
||||
}
|
||||
if (ObjectHelper.isNotEmpty(queryable.getNotBetween())) {
|
||||
queryable.getNotBetween().forEach((column, value) -> predicates.add(builder.between(column(root, column), value.getStart(), value.getEnd())));
|
||||
queryable.getNotBetween().forEach((column, value) -> {
|
||||
var path = this.<Comparable<Object>>column(root, column);
|
||||
checkComparable(path, column);
|
||||
checkComparable(value, column);
|
||||
predicates.add(builder.between(column(root, column), (Comparable<Object>) value.getStart(), (Comparable<Object>) value.getEnd()).not());
|
||||
});
|
||||
}
|
||||
return predicates;
|
||||
}
|
||||
|
||||
private void checkComparable(Path<?> path, String column) {
|
||||
if (!ObjectHelper.isComparable(path.getJavaType())) {
|
||||
throw new NotComparableException(column);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkComparable(Object value, String column) {
|
||||
if (!ObjectHelper.isComparable(value)) {
|
||||
throw new NotComparableException(column);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkComparable(Query.Queryable.Between value, String column) {
|
||||
checkComparable(value.getStart(), column);
|
||||
checkComparable(value.getEnd(), column);
|
||||
}
|
||||
|
||||
private void checkCollection(Path<?> path, String column) {
|
||||
if (!ObjectHelper.isCollection(path.getJavaType())) {
|
||||
throw new NotCollectionException(column);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCollection(Object value, String column) {
|
||||
if (!ObjectHelper.isCollection(value)) {
|
||||
throw new NotCollectionException(column);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkString(Path<?> path, String column) {
|
||||
if (!ObjectHelper.isString(path.getJavaType())) {
|
||||
throw new NotStringException(column);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkString(Object value, String column) {
|
||||
if (!ObjectHelper.isString(value)) {
|
||||
throw new NotStringException(column);
|
||||
}
|
||||
}
|
||||
|
||||
protected List<Predicate> listPredicate(Root<ENTITY> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
|
||||
return new ArrayList<>(0);
|
||||
}
|
||||
@@ -237,7 +327,25 @@ public abstract class SimpleServiceSupport<ENTITY extends SimpleEntity> implemen
|
||||
}
|
||||
|
||||
public IdNotFoundException(Long id) {
|
||||
super("ID为%d的资源不存在".formatted(id));
|
||||
super("ID为 %d 的资源不存在".formatted(id));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NotComparableException extends RuntimeException {
|
||||
public NotComparableException(String variable) {
|
||||
super("变量 %s 不能比较".formatted(variable));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NotCollectionException extends RuntimeException {
|
||||
public NotCollectionException(String variable) {
|
||||
super("变量 %s 不是集合".formatted(variable));
|
||||
}
|
||||
}
|
||||
|
||||
public static final class NotStringException extends RuntimeException {
|
||||
public NotStringException(String variable) {
|
||||
super("变量 %s 不是字符串".formatted(variable));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import org.hibernate.annotations.Comment;
|
||||
import org.hibernate.annotations.DynamicUpdate;
|
||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
||||
|
||||
|
||||
@Entity
|
||||
@DynamicUpdate
|
||||
@EntityListeners(AuditingEntityListener.class)
|
||||
|
||||
Reference in New Issue
Block a user