feat(查询): 实现通用过滤条件构建与解析功能

新增参数常量定义和查询条件构建工具,支持复杂条件组合
重构EntityService基类以支持通用过滤条件解析
优化SpecificationUtils工具类,增加搜索文本处理方法
This commit is contained in:
2025-12-13 16:48:54 +08:00
parent 72edb07798
commit 5d6fb961b6
5 changed files with 599 additions and 119 deletions

View File

@@ -4,7 +4,8 @@ import java.time.LocalDate;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.springframework.util.StringUtils;
import com.ecep.contract.constant.ParamConstant;
@@ -16,64 +17,65 @@ public class ParamUtils {
/**
* 创建日期范围查询参数
*
* @param key 查询字段名
* @param field 查询字段名
* @param begin 开始日期
* @param end 结束日期
* @return 包含日期范围的查询参数Map
*/
public static Map<String, Object> between(String key, LocalDate begin, LocalDate end) {
return Map.of(key, Map.of(
"begin", begin,
"end", end));
public static Map<String, Object> between(String field, LocalDate begin, LocalDate end) {
Builder builder = builder();
builder.between(field, begin, end);
return builder.build();
}
/**
* 创建等于条件查询参数
*
* @param key 查询字段名
* @param field 查询字段名
* @param value 查询值
* @return 包含等于条件的查询参数Map
*/
public static Map<String, Object> equal(String key, Object value) {
return Map.of(key, value);
public static Map<String, Object> equal(String field, Object value) {
Builder builder = builder();
builder.equals(field, value);
return builder.build();
}
/**
* 创建字符串模糊查询参数
*
* @param key 查询字段名
* @param field 查询字段名
* @param value 模糊查询的字符串值
* @return 包含模糊查询条件的查询参数Map
*/
public static Map<String, Object> like(String key, String value) {
Map<String, Object> params = new HashMap<>();
params.put(key, "%" + value + "%");
return params;
public static Map<String, Object> contains(String field, String value, boolean caseSensitive) {
Builder builder = builder();
builder.and().like(field, value, ParamConstant.Mode.CONTAINS, caseSensitive, false);
return builder.build();
}
/**
* 创建日期模糊查询参数
*
* @param key 查询字段名
* @param value 模糊查询的日期值
* @return 包含日期模糊查询条件的查询参数Map
*/
public static Map<String, Object> like(String key, LocalDate value) {
Map<String, Object> params = new HashMap<>();
params.put(key, "%" + value + "%");
return params;
public static Map<String, Object> startsWith(String field, String value, boolean caseSensitive) {
Builder builder = builder();
builder.and().like(field, value, ParamConstant.Mode.STARTS_WITH, caseSensitive, false);
return builder.build();
}
public static Map<String, Object> endsWith(String field, String value, boolean caseSensitive) {
Builder builder = builder();
builder.and().like(field, value, ParamConstant.Mode.ENDS_WITH, caseSensitive, false);
return builder.build();
}
/**
* 创建非空条件查询参数
*
* @param key 查询字段名
* @param field 查询字段名
* @return 包含非空条件的查询参数Map
*/
public static Map<String, Object> isNotNull(String key) {
Map<String, Object> params = new HashMap<>();
params.put(key, Map.of("isNotNull", true));
return params;
public static Map<String, Object> isNotNull(String field) {
Builder builder = builder();
builder.isNotNull(field);
return builder.build();
}
/**
@@ -84,9 +86,22 @@ public class ParamUtils {
* @return 包含小于条件的查询参数Map
*/
public static Map<String, Object> lessThan(String key, LocalDate value) {
Map<String, Object> params = new HashMap<>();
params.put(key, Map.of("lessThan", value));
return params;
Builder builder = builder();
builder.lessThan(key, value);
return builder.build();
}
/**
* 创建大于条件的日期查询参数
*
* @param key 查询字段名
* @param value 比较的日期值
* @return 包含大于条件的查询参数Map
*/
public static Map<String, Object> greaterThan(String key, LocalDate value) {
Builder builder = builder();
builder.greaterThan(key, value);
return builder.build();
}
/**
@@ -105,7 +120,7 @@ public class ParamUtils {
public static class Builder {
// 存储构建的查询参数
private String searchText;
private Map<String, Object> params = new HashMap<>();
private FilterGroup group;
/**
* 私有构造方法,防止外部直接实例化
@@ -114,18 +129,6 @@ public class ParamUtils {
private Builder() {
}
private void addParam(String field, String action, Object value) {
Object map = params.computeIfAbsent(field, k -> new HashMap<>());
if (map instanceof Map) {
((Map) map).put(action, value);
return;
}
HashMap<String, Object> m = new HashMap<>();
m.put(action, value);
m.put(ParamConstant.KEY_equal, map);
params.put(field, m);
}
/**
* 添加非空条件到构建器
*
@@ -133,7 +136,7 @@ public class ParamUtils {
* @return 当前Builder实例支持链式调用
*/
public Builder isNotNull(String key) {
addParam(key, ParamConstant.KEY_isNotNull, true);
getDefaultGroup().isNotNull(key);
return this;
}
@@ -145,7 +148,7 @@ public class ParamUtils {
* @return 当前Builder实例支持链式调用
*/
public Builder lessThan(String key, LocalDate value) {
addParam(key, ParamConstant.KEY_lessThan, value);
getDefaultGroup().lessThan(key, value);
return this;
}
@@ -157,7 +160,7 @@ public class ParamUtils {
* @return 当前Builder实例支持链式调用
*/
public Builder greaterThan(String key, LocalDate value) {
addParam(key, ParamConstant.KEY_greaterThan, value);
getDefaultGroup().greaterThan(key, value);
return this;
}
@@ -169,7 +172,7 @@ public class ParamUtils {
* @return 当前Builder实例支持链式调用
*/
public Builder equals(String key, Object value) {
addParam(key, ParamConstant.KEY_equal, value);
getDefaultGroup().equals(key, value);
return this;
}
@@ -182,10 +185,16 @@ public class ParamUtils {
* @return 当前Builder实例支持链式调用
*/
public Builder between(String key, LocalDate begin, LocalDate end) {
addParam(key, ParamConstant.KEY_between, new Object[]{begin, end});
getDefaultGroup().between(key, begin, end);
return this;
}
private FilterGroup getDefaultGroup() {
if (group != null) {
return group;
}
return and();
}
/**
* 添加全文搜索条件到构建器
@@ -200,56 +209,337 @@ public class ParamUtils {
/**
* 构建并返回查询参数Map
* 推荐的结构(仅为契约示例,服务端需配套解析):
*
* <pre>
* {
* searchText: "搜索文本",
* and: [
* {field: "字段名", action: "equal", value: "值"},
* {field: "字段名", action: "between", value: [begin, end]}
* {field: "字段名", action: "or", value: [
* {field: "字段名", action: "equal", value: "值"},
* ]}
* ],
* or: [
* {field: "字段名", action: "操作符", value: "值"}
* ]
* "searchText": "关键词",
* "filter": {
* "op": "and",
* "conditions": [
* { "field": "code", "op": "equal", "value": "V-0001" },
* {
* "field": "createdDate",
* "op": "between",
* "value": {
* "begin": "2024-01-01",
* "end": "2024-12-31",
* "includeBegin": true,
* "includeEnd": false
* }
* },
* {
* "field": "name",
* "op": "like",
* "value": "元素",
* "mode": "contains",
* "caseSensitive": false
* },
* {
* "op": "or",
* "conditions": [
* { "field": "name", "op": "like", "value": "元素", "mode": "contains", "caseSensitive": false },
* { "field": "abbName", "op": "like", "value": "元素", "mode": "contains", "caseSensitive": false }
* ]
* }
* ]
* }
* }
* </pre>
*
* 约定说明:
* - 分组节点:{ op: "and"|"or", conditions: [...] }
* - 叶子条件:{ field: "路径", op: "equal"|"between"|..., value: ... }
* - like 扩展:支持 mode("contains"|"startsWith"|"endsWith") 和
* caseSensitive(boolean)
* - between 扩展value 为对象,支持包含边界 includeBegin/includeEnd
*
* @return 包含所有添加条件的查询参数Map
*/
public Map<String, Object> build() {
Map<String, Object> map = new HashMap<>();
map.put(ParamConstant.KEY_SEARCH_TEXT, searchText);
if (StringUtils.hasText(searchText)) {
map.put(ParamConstant.KEY_SEARCH_TEXT, searchText);
}
if (group != null) {
Map<String, Object> filter = new HashMap<>();
filter.put(ParamConstant.KEY_OPERATOR, group.operator.name().toLowerCase());
filter.put(ParamConstant.KEY_CONDITIONS, group.conditions);
map.put(ParamConstant.KEY_FILTER, filter);
}
return map;
}
/**
* 添加AND逻辑条件组到构建器
*
* @param consumer Builder消费者用于构建子条件
* @return 当前Builder实例支持链式调用
* @return 新建的分组实例,支持链式调用添加子条件
*/
public Builder and(Consumer<Builder> consumer) {
Builder builder = new Builder();
consumer.accept(builder);
params.put(ParamConstant.KEY_AND, builder);
return this;
public FilterGroup and() {
if (group == null) {
group = new FilterGroup(ParamConstant.Operator.AND);
} else {
if (group.operator != ParamConstant.Operator.AND) {
throw new IllegalArgumentException(" 当前是 " + group.operator + " 条件组不允许修改为 AND 条件");
}
}
return group;
}
/**
* 添加OR逻辑条件组到构建器
*
* @param consumer Builder消费者用于构建子条件
* @return 当前Builder实例支持链式调用
* @return 新建的分组实例,支持链式调用添加子条件
*/
public Builder or(Consumer<Builder> consumer) {
Builder builder = new Builder();
consumer.accept(builder);
params.put(ParamConstant.KEY_OR, builder);
return this;
public FilterGroup or() {
if (group == null) {
group = new FilterGroup(ParamConstant.Operator.OR);
} else {
if (group.operator != ParamConstant.Operator.OR) {
throw new IllegalArgumentException(" 当前是 " + group.operator + " 条件组不允许修改为 OR 条件");
}
}
return group;
}
}
/**
* 过滤条件组,支持 AND/OR 逻辑组合
*/
public static class FilterGroup {
private ParamConstant.Operator operator = ParamConstant.Operator.AND;
List<Map<String, Object>> conditions = new java.util.ArrayList<>();
public FilterGroup(ParamConstant.Operator operator) {
this.operator = operator;
}
// 添加叶子条件equal支持 ignoreNull
public FilterGroup equals(String field, Object value) {
return equals(field, value, false);
}
public FilterGroup equals(String field, Object value, boolean ignoreNull) {
if (ignoreNull && isNullOrEmpty(value)) {
return this;
}
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_equal);
leaf.put(ParamConstant.KEY_VALUE, value);
if (ignoreNull) {
leaf.put(ParamConstant.KEY_IGNORE_NULL, true);
}
conditions.add(leaf);
return this;
}
// 添加叶子条件between对象形式 + 边界 + ignoreNull
public FilterGroup between(String field, LocalDate begin, LocalDate end) {
return between(field, begin, end, true, true, false);
}
public FilterGroup between(String field, LocalDate begin, LocalDate end,
boolean includeBegin, boolean includeEnd, boolean ignoreNull) {
boolean noBegin = begin == null;
boolean noEnd = end == null;
if (ignoreNull && noBegin && noEnd) {
return this;
}
Map<String, Object> value = new HashMap<>();
if (!noBegin) {
value.put(ParamConstant.KEY_between_begin, begin);
}
if (!noEnd) {
value.put(ParamConstant.KEY_between_end, end);
}
value.put(ParamConstant.KEY_INCLUDE_BEGIN, includeBegin);
value.put(ParamConstant.KEY_INCLUDE_END, includeEnd);
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_BETWEEN);
leaf.put(ParamConstant.KEY_VALUE, value);
if (ignoreNull) {
leaf.put(ParamConstant.KEY_IGNORE_NULL, true);
}
conditions.add(leaf);
return this;
}
// 添加叶子条件lessThan支持 ignoreNull
public FilterGroup lessThan(String field, LocalDate value) {
return lessThan(field, value, false);
}
public FilterGroup lessThan(String field, LocalDate value, boolean ignoreNull) {
if (ignoreNull && value == null) {
return this;
}
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_lessThan);
leaf.put(ParamConstant.KEY_VALUE, value);
if (ignoreNull) {
leaf.put(ParamConstant.KEY_IGNORE_NULL, true);
}
conditions.add(leaf);
return this;
}
// 添加叶子条件greaterThan支持 ignoreNull
public FilterGroup greaterThan(String field, LocalDate value) {
return greaterThan(field, value, false);
}
public FilterGroup greaterThan(String field, LocalDate value, boolean ignoreNull) {
if (ignoreNull && value == null) {
return this;
}
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_greaterThan);
leaf.put(ParamConstant.KEY_VALUE, value);
if (ignoreNull) {
leaf.put(ParamConstant.KEY_IGNORE_NULL, true);
}
conditions.add(leaf);
return this;
}
// 添加叶子条件isNotNull
public FilterGroup isNotNull(String field) {
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_isNotNull);
leaf.put(ParamConstant.KEY_VALUE, true);
conditions.add(leaf);
return this;
}
// 添加叶子条件like支持 mode/caseSensitive/ignoreNull
public FilterGroup like(String field, String value) {
return like(field, value, ParamConstant.Mode.CONTAINS, false, false);
}
public FilterGroup like(String field, String value, ParamConstant.Mode mode, boolean caseSensitive,
boolean ignoreNull) {
if (ignoreNull && isNullOrEmpty(value)) {
return this;
}
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_like);
leaf.put(ParamConstant.KEY_VALUE, value);
// 使用枚举值作为模式输出
leaf.put(ParamConstant.KEY_MODE, mode.name());
leaf.put(ParamConstant.KEY_CASE_SENSITIVE, caseSensitive);
if (ignoreNull) {
leaf.put(ParamConstant.KEY_IGNORE_NULL, true);
}
conditions.add(leaf);
return this;
}
// 添加叶子条件notLike支持 mode/caseSensitive/ignoreNull
public FilterGroup notLike(String field, String value) {
return notLike(field, value, ParamConstant.Mode.CONTAINS, false, false);
}
public FilterGroup notLike(String field, String value, ParamConstant.Mode mode, boolean caseSensitive,
boolean ignoreNull) {
if (ignoreNull && isNullOrEmpty(value)) {
return this;
}
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_notLike);
leaf.put(ParamConstant.KEY_VALUE, value);
// 使用枚举值作为模式输出
leaf.put(ParamConstant.KEY_MODE, mode.name());
leaf.put(ParamConstant.KEY_CASE_SENSITIVE, caseSensitive);
if (ignoreNull) {
leaf.put(ParamConstant.KEY_IGNORE_NULL, true);
}
conditions.add(leaf);
return this;
}
// 添加叶子条件in空集合防护 + ignoreNull
public FilterGroup in(String field, java.util.Collection<?> values) {
return in(field, values, false);
}
public FilterGroup in(String field, java.util.Collection<?> values, boolean ignoreNull) {
if (ignoreNull && (values == null || values.isEmpty())) {
return this;
}
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_in);
leaf.put(ParamConstant.KEY_VALUE, values);
if (ignoreNull) {
leaf.put(ParamConstant.KEY_IGNORE_NULL, true);
}
conditions.add(leaf);
return this;
}
// 添加叶子条件notIn空集合防护 + ignoreNull
public FilterGroup notIn(String field, java.util.Collection<?> values) {
return notIn(field, values, false);
}
public FilterGroup notIn(String field, java.util.Collection<?> values, boolean ignoreNull) {
if (ignoreNull && (values == null || values.isEmpty())) {
return this;
}
Map<String, Object> leaf = new HashMap<>();
leaf.put(ParamConstant.KEY_FIELD, field);
leaf.put(ParamConstant.KEY_OPERATOR, ParamConstant.KEY_notIn);
leaf.put(ParamConstant.KEY_VALUE, values);
if (ignoreNull) {
leaf.put(ParamConstant.KEY_IGNORE_NULL, true);
}
conditions.add(leaf);
return this;
}
// 嵌套分组and / or保持原有行为
public FilterGroup and() {
FilterGroup group = new FilterGroup(ParamConstant.Operator.AND);
Map<String, Object> child = new HashMap<>();
child.put(ParamConstant.KEY_OPERATOR, ParamConstant.Operator.AND.name().toLowerCase());
child.put(ParamConstant.KEY_CONDITIONS, group.conditions);
conditions.add(child);
return group;
}
public FilterGroup or() {
FilterGroup group = new FilterGroup(ParamConstant.Operator.OR);
Map<String, Object> child = new HashMap<>();
child.put(ParamConstant.KEY_OPERATOR, ParamConstant.Operator.OR.name().toLowerCase());
child.put(ParamConstant.KEY_CONDITIONS, group.conditions);
conditions.add(child);
return group;
}
// 辅助空值判断String/Collection/Array/null
private boolean isNullOrEmpty(Object value) {
if (value == null) {
return true;
}
if (value instanceof String s) {
return !org.springframework.util.StringUtils.hasText(s);
}
if (value instanceof java.util.Collection<?> c) {
return c.isEmpty();
}
if (value.getClass().isArray()) {
return java.lang.reflect.Array.getLength(value) == 0;
}
return false;
}
}
}