mybaties-plus实现复杂的多分组多条件且支持多字段和json字段多属性的查询
mybaties-plus实现复杂的多分组多条件且支持多字段和json字段多属性的查询

实现方案说明
- 简单场景使用map集合接收参数,以BaseEntity为例(BaseEntity开源框架中很常见)
@TableField(exist = false)
private Map<String, Object> params = new HashMap<>();
- 复杂场景使用嵌套分组方案实现复杂查询,将BaseEntity实体下新增如下字段(新增是为了兼容params)
@TableField(exist = false)
private QueryParameter queryParameter;
- 实际上好的框架应该代码优雅并保持绝的的低耦合、通用性和扩展性,所以分三步构建查询条件:
3.1 使用Wrappers.lambdaQuery()构建实体相关的LambdaQueryWrapper实列,以实现基本查询
3.2 使用LambdaQueryWrapper实列构建params的较复杂的支持多字段和json字段多属性的查询语句
3.3 继续使用LambdaQueryWrapper实列构建复杂的多分组多条件且支持多字段和json字段多属性的查询语句
支持常见的操作符(比较运算符和逻辑运算符)
- 在构建查询条件时,常见的操作符(比较运算符和逻辑运算符)可以非常丰富,以下是完整的常用操作符分类整理,本工具实现了其中大部分:
- 基础比较运算符
| 操作符 | SQL 等价 | 说明 | 示例 |
|--------------|-------------------|--------------------------|-------------------------------|
|eq|=| 等于 |age = 18|
|ne|!=或<>| 不等于 |status != 0|
|gt|>| 大于 |price > 100|
|lt|<| 小于 |score < 60|
|ge|>=| 大于等于 |quantity >= 10|
|le|<=| 小于等于 |age <= 30|
- 模糊匹配与字符串操作
| 操作符 | SQL 等价 | 说明 | 示例 |
|----------------|------------------------|--------------------------|-------------------------------|
|like|LIKE| 模糊匹配 |name LIKE '%张%'|
|notLike|NOT LIKE| 模糊不匹配 |title NOT LIKE '%test%'|
|startsWith|LIKE 'value%'| 开头匹配 |code LIKE 'A00%'|
|endsWith|LIKE '%value'| 结尾匹配 |path LIKE '%/home'|
|contains|LIKE '%value%'| 包含(同like) |desc LIKE '%重要%'|
|in|IN (...)| 在列表中 |id IN (1, 2, 3)|
|notIn|NOT IN (...)| 不在列表中 |status NOT IN (0, 1)|
- 空值判断
| 操作符 | SQL 等价 | 说明 | 示例 |
|--------------|-------------------|--------------------------|-------------------------------|
|isNull|IS NULL| 为 NULL |address IS NULL|
|notNull|IS NOT NULL| 不为 NULL |phone IS NOT NULL|
|isEmpty|= ''或IS NULL| 空字符串或 NULL |comment = '' OR comment IS NULL|
|isNotEmpty|!= ''且IS NOT NULL| 非空且不为 NULL |comment != '' AND comment IS NOT NULL|
- 范围查询
| 操作符 | SQL 等价 | 说明 | 示例 |
|--------------|------------------------|--------------------------|-------------------------------|
|between|BETWEEN x AND y| 介于范围 |age BETWEEN 18 AND 30|
|notBetween|NOT BETWEEN x AND y| 不在范围内 |price NOT BETWEEN 50 AND 100|
- 集合操作
| 操作符 | SQL 等价 | 说明 | 示例 |
|--------------|------------------------|--------------------------|-------------------------------|
|in|IN (...)| 在集合内 |id IN (1, 2, 3)|
|notIn|NOT IN (...)| 不在集合内 |category NOT IN ('A', 'B')|
- JSON/数组字段操作
(适用于 MySQL、PostgreSQL 等支持 JSON 的数据库)
| 操作符 | SQL 等价 | 说明 | 示例 |
|----------------|-----------------------------------|--------------------------|-------------------------------|
|jsonContains|JSON_CONTAINS(field, 'value')| JSON 包含值 |tags JSON_CONTAINS '"VIP"'|
|jsonExists|JSON_EXISTS(field, '$.path')| JSON 路径存在 |profile JSON_EXISTS '$.address'|
- 逻辑组合运算符
| 操作符 | 说明 | 示例 |
|--------------|--------------------------|-------------------------------|
|AND| 逻辑与(默认) |status = 1 AND price > 100|
|OR| 逻辑或 |name LIKE '%张%' OR age < 18|
|NOT| 逻辑非 |NOT (deleted = 1)|
- 特殊场景操作符
| 操作符 | 说明 | 示例 |
|----------------|--------------------------|-------------------------------|
|regexp| 正则匹配(数据库支持时) |name REGEXP '^A.*'|
|exists| 子查询存在 |EXISTS (SELECT 1 FROM orders)|
|notExists| 子查询不存在 |NOT EXISTS (SELECT 1 FROM logs)|
- 示例(JSON 请求格式)
{
"conditions": [
{ "field": "age", "operator": "ge", "value": 18 },
{ "field": "name", "operator": "like", "value": "张%" },
{
"logic": "OR",
"conditions": [
{ "field": "vip", "operator": "eq", "value": true },
{ "field": "points", "operator": "ge", "value": 1000 }
]
}
]
}
简单场景使用map集合接收参数,如BaseEntity.java
package com.xxx.entity;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* Entity基类
*/
@Data
public class BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
// 其他需求字段
/**
* 请求参数
*/
@TableField(exist = false)
private Map<String, Object> params = new HashMap<>();
/**
* 请求参数,支持分组
*/
@TableField(exist = false)
private QueryParameter queryParameter;
}
新建一个条件嵌套参数QueryParameter.java
- 该类使用说明:
- 同一级别的多个条件conditions以及多个组groups之间由该级别的logic属性决定连接关系
- 每个组内group的多个子条件group.conditions和子组group.groups被视为平级,由组的group.logic属性决定连接关系
- 嵌套组自动添加括号,非嵌套条件不添加额外括号。如果是OR链接可能会由多个括号,因为OR链接时每个部分都会调用wrapper.or(part)
package com.xxx.entity;
import lombok.Data;
import java.util.List;
@Data
public class QueryParameter {
/**
* 逻辑操作符(AND/OR/NOT)
*/
private String logic;
/**
* 条件列表
*/
private List<Condition> conditions;
/**
* 嵌套的逻辑组
*/
private List<QueryParameter> groups;
@Data
public final static class Condition {
/**
* 字段名
*/
private String field;
/**
* 操作符(eq/ne/gt/ge/lt/le/like等)
*/
private String operator;
/**
* 值
*/
private Object value;
}
}
新建LambdaQuery构建工具类MixedQueryWrapper.java
package org.dromara.product.util;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.dromara.common.mybatis.core.domain.QueryParameter;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* 查询条件构建工具类
* 支持实体字段和JSON属性的混合查询
*/
@Slf4j
public class MixedQueryWrapper {
private static final Pattern PARAM_PATTERN = Pattern.compile("^(gt|lt|eq|ge|le|contains|like)([A-Z].*)$");
private static final Map<String, OperatorProcessor> OPERATOR_HANDLERS = new HashMap<>();
private static final Pattern RANGE_PATTERN = Pattern.compile("^(.+)~(.+)$");
// 操作符处理器接口
@FunctionalInterface
interface OperatorProcessor {
void apply(LambdaQueryWrapper<?> lqw, String column, Object value) throws IllegalArgumentException;
}
static {
// ========== 基础比较运算符 ==========
putOperator("eq", (lqw, c, v) -> lqw.apply(c + " = {0}", v));
putOperator("ne", (lqw, c, v) -> lqw.apply(c + " != {0}", v));
putOperator("gt", (lqw, c, v) -> lqw.apply(c + " > {0}", v));
putOperator("lt", (lqw, c, v) -> lqw.apply(c + " < {0}", v));
putOperator("ge", (lqw, c, v) -> lqw.apply(c + " >= {0}", v));
putOperator("le", (lqw, c, v) -> lqw.apply(c + " <= {0}", v));
// ========== 模糊匹配运算符 ==========
putOperator("like", (lqw, c, v) -> lqw.apply(c + " LIKE {0}", "%" + v + "%"));
putOperator("notLike", (lqw, c, v) -> lqw.apply(c + " NOT LIKE {0}", "%" + v + "%"));
putOperator("startsWith", (lqw, c, v) -> lqw.apply(c + " LIKE {0}", v + "%"));
putOperator("endsWith", (lqw, c, v) -> lqw.apply(c + " LIKE {0}", "%" + v));
putOperator("contains", (lqw, c, v) -> lqw.apply(c + " LIKE {0}", "%" + v + "%"));
// ========== 范围查询运算符 ==========
putOperator("between", (lqw, c, v) -> {
if (v instanceof String && RANGE_PATTERN.matcher((String) v).matches()) {
String[] range = ((String) v).split("~");
lqw.apply(c + " BETWEEN {0} AND {1}", range[0], range[1]);
} else if (v instanceof Object[] range && range.length == 2) {
lqw.apply(c + " BETWEEN {0} AND {1}", range[0], range[1]);
} else {
throw new IllegalArgumentException("Between operator requires 'min~max' format or 2-element array");
}
});
// ========== 集合运算符 ==========
putOperator("in", (lqw, c, v) -> {
if (v instanceof Iterable<?> iterable) {
String placeholders = String.join(",", Collections.nCopies(
size(iterable), "?"));
lqw.apply(c + " IN (" + placeholders + ")", toArray(iterable));
} else if (v instanceof Object[] array) {
String placeholders = String.join(",", Collections.nCopies(array.length, "?"));
lqw.apply(c + " IN (" + placeholders + ")", array);
} else {
throw new IllegalArgumentException("IN operator requires collection or array");
}
});
putOperator("notIn", (lqw, c, v) -> {
if (v instanceof Iterable<?> iterable) {
String placeholders = String.join(",", Collections.nCopies(
size(iterable), "?"));
lqw.apply(c + " NOT IN (" + placeholders + ")", toArray(iterable));
} else if (v instanceof Object[] array) {
String placeholders = String.join(",", Collections.nCopies(array.length, "?"));
lqw.apply(c + " NOT IN (" + placeholders + ")", array);
} else {
throw new IllegalArgumentException("NOT IN operator requires collection or array");
}
});
// ========== 空值判断运算符 ==========
putOperator("isNull", (lqw, column, value) -> lqw.apply("{0} IS NULL", column));
putOperator("isNotNull", (lqw, column, value) -> lqw.apply("{0} IS NOT NULL", column));
putOperator("isEmpty", (lqw, c, v) -> lqw.apply(c + " IS NULL OR " + c + " = ''"));
putOperator("isNotEmpty", (lqw, c, v) -> lqw.apply(c + " IS NOT NULL AND " + c + " != ''"));
// ========== JSON/特殊类型运算符 ==========
putOperator("jsonContains", (lqw, c, v) -> lqw.apply("JSON_CONTAINS(" + c + ", {0})", v));
putOperator("jsonExists", (lqw, c, v) -> lqw.apply("JSON_EXISTS(" + c + ", {0})", v));
}
private static void putOperator(String key, OperatorProcessor processor) {
OPERATOR_HANDLERS.put(key.toLowerCase(), processor);
// 添加别名
switch (key) {
case "eq":
OPERATOR_HANDLERS.put("=", processor);
break;
case "ne":
OPERATOR_HANDLERS.put("!=", processor);
break;
case "gt":
OPERATOR_HANDLERS.put(">", processor);
break;
case "lt":
OPERATOR_HANDLERS.put("<", processor);
break;
case "ge":
OPERATOR_HANDLERS.put(">=", processor);
break;
case "le":
OPERATOR_HANDLERS.put("<=", processor);
break;
}
}
private static int size(Iterable<?> iterable) {
if (iterable instanceof Collection) {
return ((Collection<?>) iterable).size();
}
int size = 0;
for (Object ignored : iterable) {
size++;
}
return size;
}
private static Object[] toArray(Iterable<?> iterable) {
if (iterable instanceof Collection) {
return ((Collection<?>) iterable).toArray();
}
List<Object> list = new ArrayList<>();
for (Object item : iterable) {
list.add(item);
}
return list.toArray();
}
public static <T> LambdaQueryWrapper<T> buildMixedQueryWrapper(
Class<T> entityClass,
QueryParameter queryParameter,
LambdaQueryWrapper<T> lqw) {
if (queryParameter == null ||
(CollectionUtils.isEmpty(queryParameter.getConditions()) &&
CollectionUtils.isEmpty(queryParameter.getGroups()))) {
return lqw;
}
// 获取实体类的所有字段名(驼峰式)
Set<String> entityFields = Arrays.stream(entityClass.getDeclaredFields())
.map(Field::getName)
.map(StringUtils::uncapitalize)
.collect(Collectors.toSet());
// 处理当前层条件
Consumer<LambdaQueryWrapper<T>> currentConsumer = wrapper -> {
String currentLogic = StringUtils.defaultIfBlank(queryParameter.getLogic(), "AND");
boolean isOrLogic = "OR".equalsIgnoreCase(currentLogic);
// 1. 处理直接条件
if (!CollectionUtils.isEmpty(queryParameter.getConditions())) {
for (QueryParameter.Condition condition : queryParameter.getConditions()) {
if (isOrLogic) {
wrapper.or(w -> addCondition(w, entityClass, condition, entityFields));
} else {
addCondition(wrapper, entityClass, condition, entityFields);
}
}
// if (isOrLogic) {
// // OR逻辑时,所有条件用OR连接
// for (QueryParameter.Condition condition : queryParameter.getConditions()) {
// wrapper.or(w -> addCondition(w, entityClass, condition, entityFields));
// }
// } else {
// // AND逻辑时,直接添加条件
// for (QueryParameter.Condition condition : queryParameter.getConditions()) {
// addCondition(wrapper, entityClass, condition, entityFields);
// }
}
// 2. 处理嵌套组
if (!CollectionUtils.isEmpty(queryParameter.getGroups())) {
for (QueryParameter group : queryParameter.getGroups()) {
String groupLogic = StringUtils.defaultIfBlank(group.getLogic(), "AND");
boolean isGroupOr = "OR".equalsIgnoreCase(groupLogic);
if (isOrLogic) {
wrapper.or(groupWrapper ->
processGroup(groupWrapper, entityClass, group, entityFields, isGroupOr)
);
} else {
wrapper.and(groupWrapper ->
processGroup(groupWrapper, entityClass, group, entityFields, isGroupOr)
);
}
}
}
};
currentConsumer.accept(lqw);
return lqw;
}
private static <T> void processGroup(
LambdaQueryWrapper<T> wrapper,
Class<T> entityClass,
QueryParameter group,
Set<String> entityFields,
boolean isGroupOr) {
// 处理组内条件
if (!CollectionUtils.isEmpty(group.getConditions())) {
for (QueryParameter.Condition condition : group.getConditions()) {
if (isGroupOr) {
wrapper.or(w -> addCondition(w, entityClass, condition, entityFields));
} else {
addCondition(wrapper, entityClass, condition, entityFields);
}
}
}
// 递归处理嵌套组
if (!CollectionUtils.isEmpty(group.getGroups())) {
for (QueryParameter subGroup : group.getGroups()) {
String subLogic = StringUtils.defaultIfBlank(subGroup.getLogic(), "AND");
boolean isSubOr = "OR".equalsIgnoreCase(subLogic);
if (isGroupOr) {
wrapper.or(subWrapper ->
processGroup(subWrapper, entityClass, subGroup, entityFields, isSubOr)
);
} else {
wrapper.and(subWrapper ->
processGroup(subWrapper, entityClass, subGroup, entityFields, isSubOr)
);
}
}
}
}
private static <T> void addCondition(
LambdaQueryWrapper<T> wrapper,
Class<T> entityClass,
QueryParameter.Condition condition,
Set<String> entityFields) {
if (condition == null ||
StringUtils.isBlank(condition.getField()) ||
condition.getValue() == null) {
return;
}
String fieldName = condition.getField();
String operator = StringUtils.defaultIfBlank(condition.getOperator(), "eq");
// 1. 处理实体字段查询
if (entityFields.contains(fieldName)) {
handleEntityFieldQuery(wrapper, entityClass, operator, fieldName, condition.getValue());
}
// 2. 处理JSON属性查询
else if (fieldName.contains(".")) {
String[] parts = fieldName.split("\\.", 2);
if (parts.length == 2 &&
!StringUtils.isBlank(parts[0]) &&
!StringUtils.isBlank(parts[1])) {
String snakeColumn = camelToSnake(parts[0]);
String propKey = parts[1];
// 转换蛇形命名到驼峰式
String camelJsonField = snakeToCamel(snakeColumn);
if (entityFields.contains(camelJsonField)) {
handleJsonPropertyQuery(wrapper, snakeColumn, operator, propKey, condition.getValue());
}
}
}
}
/**
* 单条件处理(保持兼容)
*/
public static <T> LambdaQueryWrapper<T> buildMixedQueryWrapper(Class<T> entityClass, Map<String, Object> params, LambdaQueryWrapper<T> lqw) {
// 获取参数Map
if (params == null || params.isEmpty()) {
return lqw;
}
// 获取实体类的所有字段名(小写驼峰)
Set<String> entityFields = Arrays.stream(entityClass.getDeclaredFields())
.map(Field::getName)
.map(StringUtils::uncapitalize)
.collect(Collectors.toSet());
// 处理查询参数
params.forEach((paramKey, paramValue) -> {
if (paramValue == null || StringUtils.isBlank(paramValue.toString())) {
return;
}
String operator = "eq"; // 默认操作符
String fieldName = paramKey;
// 改进后的正则匹配(允许小写字母开头)
Matcher matcher = PARAM_PATTERN.matcher(paramKey);
if (matcher.matches()) {
operator = matcher.group(1).toLowerCase(); // 统一小写
fieldName = StringUtils.uncapitalize(matcher.group(2));
}
// 判断是实体字段还是JSON属性
if (entityFields.contains(fieldName)) {
handleEntityFieldQuery(lqw, entityClass, operator, fieldName, paramValue);
}
// 处理JSON属性查询(带点号分隔符)
else if (fieldName.contains(".")) {
String[] parts = fieldName.split("\\.", 2);
// 确保分割有效且非空
if (parts.length == 2 && !parts[0].isEmpty() && !parts[1].isEmpty()) {
String jsonFieldName = camelToSnake(parts[0]);
String propKey = parts[1];
// 转换蛇形命名到驼峰式(根据实际需要)
String camelJsonField = snakeToCamel(jsonFieldName);
// 验证JSON字段名是否有效
if (entityFields.contains(camelJsonField)) {
handleJsonPropertyQuery(lqw, camelJsonField, operator, propKey, paramValue);
} else {
log.warn("Invalid JSON field: {}", jsonFieldName);
}
}
}
});
return lqw;
}
/**
* 处理实体字段查询
*/
private static <T> void handleEntityFieldQuery(LambdaQueryWrapper<T> lqw, Class<T> entityClass, String operator, String fieldName, Object value) {
if (StringUtils.isBlank(fieldName) || value == null) {
return;
}
// 获取字段的数据库列名(假设使用 MyBatis-Plus 的 @TableField 注解)
String columnName = getColumnName(entityClass, fieldName);
if (columnName == null) {
return;
}
OperatorProcessor handler = OPERATOR_HANDLERS.get(operator.toLowerCase());
if (handler != null) {
try {
handler.apply(lqw, columnName, value);
} catch (Exception e) {
log.error("Apply operator failed: {}{}{}", columnName, operator, value, e);
}
}
}
/**
* 处理JSON属性查询
*/
private static <T> void handleJsonPropertyQuery(LambdaQueryWrapper<T> lqw, String snakeColumn, String operator, String propKey, Object value) {
if (StringUtils.isBlank(propKey) || value == null) {
return;
}
// 构建JSON提取表达式(兼容不同数据库)
String jsonExtract = buildJsonExtractExpression(snakeColumn, propKey, operator);
// 获取对应的操作处理器
OperatorProcessor handler = OPERATOR_HANDLERS.get(operator.toLowerCase());
if (handler != null) {
try {
// 统一处理:使用JSON提取表达式作为列名
handler.apply(lqw, jsonExtract, value);
} catch (Exception e) {
log.error("Apply JSON operator failed: {}{}{}", propKey, operator, value, e);
}
}
}
/**
* 构建适合不同数据库的JSON提取表达式
*/
private static String buildJsonExtractExpression(String jsonFieldName, String propKey, String operator) {
// 基础JSON提取(MySQL风格)
String jsonPath = "$." + propKey;
String jsonExtract = String.format("JSON_UNQUOTE(JSON_EXTRACT(%s, '%s'))", jsonFieldName, jsonPath);
// 根据操作符调整表达式
return switch (operator.toLowerCase()) {
case "like", "notlike", "startswith", "endswith" ->
// 这些操作需要确保比较的是字符串
jsonExtract;
default ->
// 其他操作直接使用JSON提取值(可能包含类型转换)
String.format("JSON_EXTRACT(%s, '%s')", jsonFieldName, jsonPath);
};
}
private static <T> String getColumnName(Class<T> entityClass, String fieldName) {
try {
Field field = entityClass.getDeclaredField(fieldName);
TableField tableField = field.getAnnotation(TableField.class);
// 如果字段有 @TableField 注解,并且指定了列名,则使用它
if (tableField != null && StringUtils.isNotBlank(tableField.value())) {
return tableField.value();
}
// 否则默认使用字段名(驼峰转下划线)
return camelToSnake(fieldName);
} catch (NoSuchFieldException e) {
log.error("Field not found: {}", fieldName, e);
}
return null;
}
/**
* 实现的蛇形命名转驼峰命名
*/
private static String snakeToCamel(String str) {
if (StringUtils.isBlank(str)) {
return str;
}
String[] parts = str.split("_");
StringBuilder result = new StringBuilder(parts[0].toLowerCase());
for (int i = 1; i < parts.length; i++) {
result.append(StringUtils.capitalize(parts[i].toLowerCase()));
}
return result.toString();
}
/**
* 驼峰转蛇形工具方法
*/
private static String camelToSnake(String str) {
return str.replaceAll("([a-z])([A-Z])", "$1_$2").toLowerCase();
}
}
如何使用呢
后端service
// propertyData是json字段,knownPropKeys是json对应的key集合, bo.getParams()是map参数集合,bo.getQueryParameter()是更复杂的参数
LambdaQueryWrapper<Product> lqw = Wrappers.lambdaQuery();
// 1 使用*Wrappers.lambdaQuery()*构建实体相关的*LambdaQueryWrapper*实列,以实现基本查询
lqw.eq(StringUtils.isNotBlank(bo.getProductPropertyTemplate()), Product::getProductPropertyTemplate, bo.getProductPropertyTemplate());
// 2 使用*LambdaQueryWrapper*实列构建*params*的较复杂的支持多字段和json字段多属性的查询语句
lqw = MixedQueryWrapper.buildMixedQueryWrapper(Product.class, bo.getParams(), lqw);
// 3 继续使用*LambdaQueryWrapper*实列构建复杂的多分组多条件且支持多字段和json字段多属性的查询语句
lqw = MixedQueryWrapper.buildMixedQueryWrapper(Product.class, bo.getQueryParameter(), lqw);
前端参数示例
- 请求示例:/product/list?pageNum=1&pageSize=10&queryParameter%5Blogic%5D=AND&queryParameter%5Bconditions%5D=*****
- 参数如下:
{
"productPropertyTemplate": "product_property_template_001",
"queryParam": {
"logic": "AND",
"conditions": [
{
"field": "status",
"operator": "eq",
"value": "0"
}
],
"groups": [
{
"logic": "OR",
"conditions": [
{
"field": "nameSpec",
"operator": "like",
"value": "test"
},
{
"field": "approveStatus",
"operator": "eq",
"value": "123"
}
]
}
]
}
}
queryParameter.logic: AND
queryParameter.conditions[0].field: productPropertyTemplate
queryParameter.conditions[0].operator: eq
queryParameter.conditions[0].value: 432
queryParameter.conditions[1].field: originalProductId
queryParameter.conditions[1].operator: eq
queryParameter.conditions[1].value: 6456
queryParameter.groups[0].logic: OR
queryParameter.groups[0].conditions[0].field: nameSpec
queryParameter.groups[0].conditions[0].operator: like
queryParameter.groups[0].conditions[0].value: cs
queryParameter.groups[0].conditions[1].field: originalProductId
queryParameter.groups[0].conditions[1].operator: eq
queryParameter.groups[0].conditions[1].value: 44
queryParameter.groups[1].logic: AND
queryParameter.groups[1].conditions[0].field: nameSpec
queryParameter.groups[1].conditions[0].operator: eq
queryParameter.groups[1].conditions[0].value: dd
queryParameter.groups[1].conditions[1].field: status
queryParameter.groups[1].conditions[1].operator: startsWith
queryParameter.groups[1].conditions[1].value: 4
//queryParameter.groups[1].groups[0]....
- API请求如果是GET接口可能需要改造一下查询参数,以免出现参数为queryParameter.conditions: [jobect, object]导致请求失败,post接口无影响
export const listProduct = (query?: ProductQuery): AxiosPromise<ProductVO[]> => {
// 处理 queryParameter 参数
const params = new URLSearchParams();
// 添加基础参数
params.append('pageNum', query?.pageNum?.toString() || '1');
params.append('pageSize', query?.pageSize?.toString() || '10');
// 添加 queryParameter 参数
if (query?.queryParameter) {
const qp = query.queryParameter;
params.append('queryParameter.logic', qp.logic || 'AND');
// 处理 conditions
qp.conditions?.forEach((condition, index) => {
params.append(`queryParameter.conditions[${index}].field`, condition.field);
params.append(`queryParameter.conditions[${index}].operator`, condition.operator);
params.append(`queryParameter.conditions[${index}].value`, condition.value);
});
// 处理 groups
qp.groups?.forEach((group, gIndex) => {
params.append(`queryParameter.groups[${gIndex}].logic`, group.logic);
group.conditions?.forEach((condition, cIndex) => {
params.append(`queryParameter.groups[${gIndex}].conditions[${cIndex}].field`, condition.field);
params.append(`queryParameter.groups[${gIndex}].conditions[${cIndex}].operator`, condition.operator);
params.append(`queryParameter.groups[${gIndex}].conditions[${cIndex}].value`, condition.value);
});
});
}
return request({
url: '/product/product/list',
method: 'get',
params: params
});
};
生成SQL示例
SELECT COUNT(*) AS total
FROM product
WHERE (
product_property_template = '432'
AND original_product_id = '6456'
AND (name_spec LIKE '%cs%' OR original_product_id = '44')
AND (name_spec = 'dd' AND status LIKE '4%')
)
浙公网安备 33010602011771号