package com.nuzar.cloud.utils;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.nuzar.cloud.annotation.web.QueryParam;
import com.nuzar.cloud.common.exception.BizExceptionDef;
import com.nuzar.cloud.common.exception.BizExceptionGenerator;
import com.nuzar.cloud.common.exception.CommonExceptionDefs;
import com.nuzar.cloud.common.utils.ReflectionUtils;
import com.nuzar.cloud.common.utils.StringUtils;
import com.nuzar.cloud.web.model.QueryPage;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
* @author MadMax
* @date 2021/8/23 15:07
*/
public class QueryUtils {
public static final String BLANK_SPACE = " ";
public static final String ASC = "ASC";
static final String LIMIT_FIELD = "limit";
static final String ORDER_ITEMS = "orderItems";
public static DbType dbType;
static Logger logger = LoggerFactory.getLogger(QueryUtils.class);
public static <T> QueryWrapper<T> getQueryWrapperClassic(Object query, Class<T> clazz) {
if (query == null) {
Assert.notNull(query, "query should not null");
}
// init wrapper
QueryWrapper<T> wrapper = Wrappers.query();
// fill wrapper
Field[] sourceFields = ReflectionUtils.getAllFields(query.getClass());
Field[] targetFields = ReflectionUtils.getAllFields(clazz);
for (Field field : sourceFields) {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
boolean required = false;
String paramName = field.getName();
// 跳过limit
if (LIMIT_FIELD.equals(paramName) || ORDER_ITEMS.equals(paramName)) {
continue;
}
List<String> paramNames = new ArrayList<>();
QueryParam.FilterType filterType = QueryParam.FilterType.EQ;
QueryParam queryParam = field.getAnnotation(QueryParam.class);
if (queryParam != null) {
// 如果 exist == false, 不填入 queryWrapper
if (!queryParam.exist()) {
continue;
}
if (queryParam.name().length > 0) {
if (StringUtils.isNotEmpty(queryParam.name()[0])) {
paramName = queryParam.name()[0];
}
paramNames = Arrays.asList(queryParam.name());
}
required = queryParam.required();
filterType = queryParam.filterType();
}
if (paramNames.size() == 0) {
paramNames.add(paramName);
}
Map<String, Boolean> filterMap = new HashMap<>();
// process request
paramNames.forEach(f -> {
Optional<Field> curField = Arrays.stream(targetFields).filter(t -> t.getName().equals(f)).findFirst();
if (!curField.isPresent()) {
// 如果没有匹配到那么就忽略
filterMap.put(f, false);
logger.warn("QueryModel: " + query.getClass().getSimpleName() + " 中查询字段 " + f + " 无效!");
} else {
filterMap.put(f, true);
}
});
paramNames = paramNames.stream().filter(t -> filterMap.get(t)).collect(Collectors.toList());
if (paramNames.size() == 0) {
continue;
}
// 数组
Object value = null;
try {
ReflectionUtils.makeAccessible(field);
value = field.get(query);
if (required && value == null) {
BizExceptionGenerator.generateBizException(CommonExceptionDefs.COMM_ARGS_INCOMPLETE, field.getName());
}
if (field.getType().isArray()) {
Object[] values = (Object[]) value;
wrapper = fillWrapper(wrapper, paramNames, filterType, values);
} else {
wrapper = fillWrapper(wrapper, paramNames, filterType, value);
}
} catch (Exception e) {
}
}
return wrapper;
}
/**
* 根据当前实体获取 QueryWrapper类
*
* @param clazz
* @param <T>
* @return
*/
public static <T> QueryWrapper<T> getQueryWrapper(Object query, Class<T> clazz) {
if (query == null) {
Assert.notNull(query, "entity should not null");
}
// init wrapper
QueryWrapper<T> wrapper = Wrappers.query();
// fill wrapper
Field[] sourceFields = ReflectionUtils.getAllFields(query.getClass());
Field[] noCacheTargetFields = ReflectionUtils.getAllFields(clazz);
TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
String idColumn = null;
String idProperty = null;
List<TableFieldInfo> targetFields = null;
if (tableInfo != null) {
idColumn = tableInfo.getKeyColumn();
idProperty = tableInfo.getKeyProperty();
targetFields = tableInfo.getFieldList();
}
Object orderItems = null;
for (Field field : sourceFields) {
if (Modifier.isStatic(field.getModifiers())) {
continue;
}
boolean required = false;
String paramName = field.getName();
// 跳过limit
if (LIMIT_FIELD.equals(paramName) || ORDER_ITEMS.equals(paramName)) {
if (ORDER_ITEMS.equals(paramName)) {
try {
ReflectionUtils.makeAccessible(field);
orderItems = field.get(query);
} catch (Exception e) {
}
}
continue;
}
List<String> paramNames = new ArrayList<>();
QueryParam.FilterType filterType = QueryParam.FilterType.EQ;
QueryParam queryParam = field.getAnnotation(QueryParam.class);
if (queryParam != null) {
// 如果 exist == false, 不填入 queryWrapper
if (!queryParam.exist()) {
continue;
}
if (queryParam.name().length > 0) {
if (StringUtils.isNotEmpty(queryParam.name()[0])) {
paramName = queryParam.name()[0];
}
paramNames = Arrays.asList(queryParam.name());
}
required = queryParam.required();
filterType = queryParam.filterType();
}
if (paramNames.size() == 0) {
paramNames.add(paramName);
}
Map<String, Boolean> filterMap = new HashMap<>();
// process request
List<TableFieldInfo> finalTargetFields = targetFields;
String finalIdProperty = idProperty;
String finalIdColumn = idColumn;
paramNames.forEach(f -> {
Optional optional;
String column = "";
if (finalTargetFields != null) {
optional = finalTargetFields.stream().filter(t -> t.getProperty().equals(f)).findFirst();
if (optional.isPresent()) {
column = ((TableFieldInfo) optional.get()).getColumn();
}
} else {
optional = Arrays.stream(noCacheTargetFields).filter(t -> t.getName().equals(f)).findFirst();
if (optional.isPresent()) {
column = f;
if (!(f.indexOf("_") > 0)) {
column = StringUtils.humpToUnderline(f);
}
}
}
if (finalIdProperty != null && finalIdProperty.equals(f)) {
filterMap.put(finalIdColumn, true);
}
if (!optional.isPresent()) {
// 如果没有匹配到那么就忽略
// filterMap.put(f, false);
if (filterMap.get(finalIdColumn) == null) {
logger.warn("QueryModel: " + query.getClass().getSimpleName() + " 中查询字段 " + f + " 无效!");
}
} else {
filterMap.put(column, true);
}
});
paramNames = filterMap.keySet().stream().filter(t -> filterMap.get(t)).collect(Collectors.toList());
// paramNames = paramNames.stream().filter(t -> filterMap.get(t)).collect(Collectors.toList());
if (paramNames.size() == 0) {
continue;
}
// 数组
Object value = null;
try {
ReflectionUtils.makeAccessible(field);
value = field.get(query);
if (required && value == null) {
BizExceptionGenerator.generateBizException(CommonExceptionDefs.COMM_ARGS_INCOMPLETE, field.getName());
}
if (field.getType().isArray()) {
Object[] values = (Object[]) value;
wrapper = fillWrapper(wrapper, paramNames, filterType, values);
} else if ((field.getGenericType() instanceof ParameterizedType) && (((ParameterizedType) field.getGenericType()).getRawType().equals(List.class))) {
Object[] values = ((List) value).toArray();
wrapper = fillWrapper(wrapper, paramNames, filterType, values);
} else {
wrapper = fillWrapper(wrapper, paramNames, filterType, value);
}
} catch (Exception e) {
logger.warn("fillWrapper with error {}", e);
}
}
if (orderItems instanceof String[]) {
orderBy(wrapper, tableInfo, (String[]) orderItems, clazz);
}
return wrapper;
}
public static void orderBy(QueryWrapper wrapper, TableInfo tableInfo, String[] orderItems, Class clazz) {
if (ArrayUtils.isNotEmpty(orderItems)) {
List<OrderItem> orders = getOrderItem(tableInfo, orderItems, clazz);
orders.forEach(t -> {
wrapper.orderBy(true, t.isAsc(), t.getColumn());
});
}
}
public static List<OrderItem> getOrderItem(TableInfo tableInfo, String[] orderItems, Class clazz) {
List<OrderItem> orders = new ArrayList();
Field[] fields = null;
if (orderItems != null) {
if (clazz != null) {
fields = ReflectionUtils.getAllFields(clazz);
}
for (int i = 0; i < orderItems.length; ++i) {
String order = orderItems[i];
if (StringUtils.isNotBlank(order)) {
String[] tmps = order.split(BLANK_SPACE);
if (fields != null && tmps.length > 0) {
Optional<Field> f = Arrays.stream(fields).filter(t -> t.getName().equals(tmps[0])).findFirst();
if (!f.isPresent()) {
continue;
}
}
if (tmps.length == 1) {
OrderItem orderItem = new OrderItem(QueryPage.getColumnName(tableInfo, tmps[0]), true);
orders.add(orderItem);
} else if (tmps.length >= 2 && tmps[0].length() > 0) {
boolean asc = ASC.equalsIgnoreCase(tmps[1]);
OrderItem orderItem = new OrderItem(QueryPage.getColumnName(tableInfo, tmps[0]), asc);
orders.add(orderItem);
}
}
}
}
return orders;
}
/**
* 传入的wrapper类型为QueryWrapper或者LambdaQueryWrapper才能转换 其它不行
*/
public static <T> QueryWrapper<T> getQueryWrapper(Wrapper<T> wrapper) {
if (wrapper instanceof QueryWrapper) {
return (QueryWrapper<T>) wrapper;
}
throw BizExceptionGenerator.generateBizException(new BizExceptionDef("COMMON_MP001", "Wrapper类型转换不支持"));
}
/**
* 传入的wrapper类型为QueryWrapper或者LambdaQueryWrapper才能转换 其它不行
*/
public static <T> LambdaQueryWrapper<T> getLambdaQueryWrapper(Wrapper<T> wrapper) {
if (wrapper instanceof QueryWrapper) {
return ((QueryWrapper<T>) wrapper).lambda();
}
if (wrapper instanceof LambdaQueryWrapper) {
return (LambdaQueryWrapper<T>) wrapper;
}
throw BizExceptionGenerator.generateBizException(new BizExceptionDef("COMMON_MP001", "Wrapper类型转换不支持"));
}
public static <T> QueryWrapper<T> fillWrapper(QueryWrapper<T> wrapper,
String fieldName,
QueryParam.FilterType filterType,
boolean and,
Object... value) {
if (value == null || value.length == 0 || value[0] == null) {
return wrapper;
}
if (!and) {
wrapper = wrapper.or();
}
switch (filterType) {
case LIKE:
wrapper.like(fieldName, value[0]);
break;
case LIKE_FAST:
wrapper.likeRight(fieldName, value[0]);
break;
case EQ:
wrapper.eq(fieldName, value[0]);
break;
case GT:
wrapper.gt(fieldName, value[0]);
break;
case GTE:
wrapper.ge(fieldName, value[0]);
break;
case LT:
wrapper.lt(fieldName, value[0]);
break;
case LTE:
wrapper.le(fieldName, value[0]);
break;
case IN:
wrapper.in(fieldName, value);
break;
case NOT_IN:
wrapper.notIn(fieldName, value);
break;
default:
wrapper.eq(fieldName, value[0]);
break;
}
return wrapper;
}
/**
* 填充wrapper
*
* @param wrapper
* @param fieldName
* @param filterType
* @param value
* @param <T>
* @return
*/
public static <T> QueryWrapper<T> fillWrapper(QueryWrapper<T> wrapper,
String fieldName,
QueryParam.FilterType filterType,
Object... value) {
return fillWrapper(wrapper, fieldName, filterType, true, value);
}
/**
* @param wrapper
* @param fieldNames
* @param filterType
* @param value
* @param <T>
* @return
*/
public static <T> QueryWrapper<T> fillWrapper(QueryWrapper<T> wrapper,
List<String> fieldNames,
QueryParam.FilterType filterType,
Object... value) {
if (value == null || value.length == 0 || value[0] == null) {
return wrapper;
}
if (fieldNames.size() == 1) {
String fieldName = fieldNames.get(0);
return fillWrapper(wrapper, fieldName, filterType, value);
} else {
final QueryWrapper<T> orWrapper = Wrappers.query();
fieldNames.forEach(t -> {
fillWrapper(orWrapper, t, filterType, false, value);
});
Consumer<QueryWrapper<T>> consumer = t -> {
QueryWrapper<T> queryWrapper = t;
for (String fieldName : fieldNames) {
fillWrapper(queryWrapper, fieldName, filterType, false, value);
}
};
wrapper.and(consumer);
}
return wrapper;
}
// public static <T> JoinLambdaWrapper<T> getJoinLambdaWrapperr(Object query, Class<T> clazz) {
// if (query == null) {
// Assert.notNull(query, "entity should not null");
// }
// JoinWrapper<T> wrapper = new JoinWrapper();
//
// Field[] sourceFields = ReflectionUtils.getAllFields(query.getClass());
// Field[] noCacheTargetFields = ReflectionUtils.getAllFields(clazz);
// TableInfo tableInfo = TableInfoHelper.getTableInfo(clazz);
// String idColumn = null;
// String idProperty = null;
// List<TableFieldInfo> targetFields = null;
// if (tableInfo != null) {
// idColumn = tableInfo.getKeyColumn();
// idProperty = tableInfo.getKeyProperty();
// targetFields = tableInfo.getFieldList();
// }
// Object orderItems = null;
//
// for (Field field : sourceFields) {
// if (Modifier.isStatic(field.getModifiers())) {
// continue;
// }
// boolean required = false;
// String paramName = field.getName();
// // 跳过limit
// if (LIMIT_FIELD.equals(paramName) || ORDER_ITEMS.equals(paramName)) {
// if (ORDER_ITEMS.equals(paramName)) {
// try {
// ReflectionUtils.makeAccessible(field);
// orderItems = field.get(query);
// } catch (Exception e) {
//
// }
// }
// continue;
// }
//
// List<String> paramNames = new ArrayList<>();
// QueryParam.FilterType filterType = QueryParam.FilterType.EQ;
// QueryParam queryParam = field.getAnnotation(QueryParam.class);
// if (queryParam != null) {
// // 如果 exist == false, 不填入 queryWrapper
// if (!queryParam.exist()) {
// continue;
// }
// if (queryParam.name().length > 0) {
// if (StringUtils.isNotEmpty(queryParam.name()[0])) {
// paramName = queryParam.name()[0];
// }
// paramNames = Arrays.asList(queryParam.name());
// }
// required = queryParam.required();
// filterType = queryParam.filterType();
// }
// if (paramNames.size() == 0) {
// paramNames.add(paramName);
// }
// Map<String, Boolean> filterMap = new HashMap<>();
// // process request
// List<TableFieldInfo> finalTargetFields = targetFields;
// String finalIdProperty = idProperty;
// String finalIdColumn = idColumn;
// paramNames.forEach(f -> {
// Optional optional;
// String column = "";
// if (finalTargetFields != null) {
// optional = finalTargetFields.stream().filter(t -> t.getProperty().equals(f)).findFirst();
// if (optional.isPresent()) {
// column = ((TableFieldInfo) optional.get()).getColumn();
// }
// } else {
// optional = Arrays.stream(noCacheTargetFields).filter(t -> t.getName().equals(f)).findFirst();
// if (optional.isPresent()) {
// column = f;
// if (!(f.indexOf("_") > 0)) {
// column = StringUtils.humpToUnderline(f);
// }
// }
// }
// if (finalIdProperty != null && finalIdProperty.equals(f)) {
// filterMap.put(finalIdColumn, true);
// }
// if (!optional.isPresent()) {
// // 如果没有匹配到那么就忽略
filterMap.put(f, false);
// if (filterMap.get(finalIdColumn) == null) {
// logger.warn("QueryModel: " + query.getClass().getSimpleName() + " 中查询字段 " + f + " 无效!");
// }
// } else {
// filterMap.put(column, true);
// }
// });
// paramNames = filterMap.keySet().stream().filter(t -> filterMap.get(t)).collect(Collectors.toList());
paramNames = paramNames.stream().filter(t -> filterMap.get(t)).collect(Collectors.toList());
// if (paramNames.size() == 0) {
// continue;
// }
// // 数组
// Object value = null;
// try {
// ReflectionUtils.makeAccessible(field);
// value = field.get(query);
// if (required && value == null) {
// BizExceptionGenerator.generateBizException(CommonExceptionDefs.COMM_ARGS_INCOMPLETE, field.getName());
// }
// if (field.getType().isArray()) {
// Object[] values = (Object[]) value;
// wrapper = fillWrapper(wrapper, paramNames, filterType, values);
// } else {
// wrapper = fillWrapper(wrapper, paramNames, filterType, value);
// }
// } catch (Exception e) {
// }
//
// }
// if (orderItems instanceof String[]) {
// orderBy(wrapper, tableInfo, (String[]) orderItems);
// }
// return wrapper;
// }
}
注解
package com.nuzar.cloud.annotation.web;
import java.lang.annotation.*;
/**
* @author MadMax
* @date 2021/8/17 9:00
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface QueryParam {
/**
* The name of the request parameter to bind to.
* 如果配置多个 那么会拼接成 or group条件
*/
String[] name() default {};
/**
* 暂时不使用 如果后面有需要可以使用这个
* or 组合调教 同组的条件将会合并为 and ( condition1 or condition2) 请使用不同的 groupName区分
* @return
*/
// String orGroup() default "";
/**
* Whether the field is required.
*/
boolean required() default false;
/**
* 是否对应数据库字段, 默认true。表示对应数据库字段
*
* @return
*/
boolean exist() default true;
/**
* The default value to use as a fallback when the request parameter is
* not provided or has an empty value.
*/
String defaultValue() default "";
/**
* 日期转换格式
*
* @return
*/
String dateFormat() default "";
/**
* 查询类型 默认为 EQ
*
* @return
*/
FilterType filterType() default FilterType.EQ;
enum FilterType {
/**
* %value%
*/
LIKE,
/**
* 性能考虑
* LIKE_FAST 只支持 Left% 查询 不支持 %Right、 %Inner%
*/
LIKE_FAST,
/**
* 等于
*/
EQ,
/**
* In
*/
IN,
/**
* not in
*/
NOT_IN,
/**
* greater than and equals
*/
GTE,
/**
* greater than
*/
GT,
/**
* less than
*/
LT,
/**
* less than and equals
*/
LTE
}
// /**
// * 指定字段所属实体
// *
// * @return
// */
// Class joinClass() default Object.class;
}
查询类 继承此类
package com.nuzar.cloud.web.model;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.nuzar.cloud.utils.QueryUtils;
import java.io.Serializable;
import java.util.Optional;
/**
* @author MadMax
* @date 2021/8/23 14:12
*/
public class QueryModel implements Serializable {
/**
* 限制数量
*/
protected Integer limit;
/**
* 排序字段
*/
protected String[] orderItems;
protected static final String BLANK_SPACE = " ";
protected static final String ASC = "ASC";
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
public String[] getOrderItems() {
return orderItems;
}
public void setOrderItems(String[] orderItems) {
this.orderItems = orderItems;
}
/**
* 根据当前实体获取 Wrapper类 -允许字段排序
*
* @param clazz
* @param <T>
* @return
*/
public <T> QueryWrapper<T> getQueryWrapper(Class<T> clazz) {
QueryWrapper<T> wrapper = QueryUtils.getQueryWrapper(this, clazz);
if (this.limit != null) {
if (Optional.ofNullable(QueryUtils.dbType).orElse(DbType.POSTGRE_SQL).equals(DbType.ORACLE)
|| Optional.ofNullable(QueryUtils.dbType).orElse(DbType.POSTGRE_SQL).equals(DbType.ORACLE_12C)) {
wrapper.le("rownum", limit);
} else {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("limit " + limit);
wrapper.last(stringBuffer.toString());
}
}
return wrapper;
}
/**
* 返回lambdaQueryWrapper类型
*/
public <T> LambdaQueryWrapper<T> getLambdaQueryWrapper(Class<T> clazz) {
return getQueryWrapper(clazz).lambda();
}
}