Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.zodiac.mybatisplus.binding.QueryBuilder Maven / Gradle / Ivy
package org.zodiac.mybatisplus.binding;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.core.conditions.ISqlSegment;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.segments.NormalSegmentList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zodiac.commons.support.SpringContextHolder;
import org.zodiac.commons.util.BeanUtil;
import org.zodiac.commons.util.Colls;
import org.zodiac.commons.util.ObjectUtil;
import org.zodiac.commons.util.lang.Strings;
import org.zodiac.core.data.ProtectFieldHandler;
import org.zodiac.core.data.annotation.Comparison;
import org.zodiac.core.data.annotation.Strategy;
import org.zodiac.mybatisplus.binding.parser.ParserCache;
import org.zodiac.mybatisplus.binding.query.BindQuery;
import org.zodiac.mybatisplus.binding.query.dynamic.AnnoJoiner;
import org.zodiac.mybatisplus.binding.query.dynamic.DynamicJoinQueryWrapper;
import org.zodiac.mybatisplus.binding.query.dynamic.ExtQueryWrapper;
import org.zodiac.mybatisplus.model.MyBatisPlusPagination;
import org.zodiac.mybatisplus.util.MyBatisPlusUtil;
import org.zodiac.sdk.toolkit.util.lang.ObjUtil;
import org.zodiac.sdk.toolkit.util.lang.StrUtil;
import javax.lang.model.type.NullType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* QueryWrapper构建器。
*
*/
@SuppressWarnings({"rawtypes"})
public class QueryBuilder {
private static Logger log = LoggerFactory.getLogger(QueryBuilder.class);
private QueryBuilder() {
super();
}
/**
* Entity或者DTO对象转换为QueryWrapper。
*
* @param dto 参数对象
* @param 参数类型
* @return 结果
*/
public static QueryWrapper toQueryWrapper(DTO dto) {
return dtoToWrapper(dto, null, null);
}
/**
* Entity或者DTO对象转换为QueryWrapper。
*
* @param 参数类型
* @param dto 参数对象
* @param myBatisPlusPagination 分页
* @return 结果
*/
public static QueryWrapper toQueryWrapper(DTO dto, MyBatisPlusPagination myBatisPlusPagination) {
return dtoToWrapper(dto, null, myBatisPlusPagination);
}
/**
* Entity或者DTO对象转换为QueryWrapper。
*
* @param dto 参数对象
* @param fields 字段列表 指定参与转换的属性值
* @param 参数类型
* @return 结果
*/
public static QueryWrapper toQueryWrapper(DTO dto, Collection fields) {
return dtoToWrapper(dto, fields, null);
}
/**
* Entity或者DTO对象转换为QueryWrapper。
*
* @param 参数类型
* @param dto 参数对象
* @param fields 字段列表 指定参与转换的属性值
* @param myBatisPlusPagination 分页
* @return 结果
*/
public static QueryWrapper toQueryWrapper(DTO dto, Collection fields, MyBatisPlusPagination myBatisPlusPagination) {
return dtoToWrapper(dto, fields, myBatisPlusPagination);
}
/**
* Entity或者DTO对象转换为QueryWrapper。
*
* @param 参数类型
* @param dto 参数对象
* @return 结果
*/
public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto) {
return toDynamicJoinQueryWrapper(dto, null, null);
}
/**
* Entity或者DTO对象转换为QueryWrapper。
*
* @param 参数类型
* @param dto 参数对象
* @param myBatisPlusPagination 分页
* @return 结果
*/
public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto, MyBatisPlusPagination myBatisPlusPagination) {
return toDynamicJoinQueryWrapper(dto, null, myBatisPlusPagination);
}
/**
* Entity或者DTO对象转换为QueryWrapper。
*
* @param 参数类型
* @param dto 参数对象
* @param fields 字段列表 指定参与转换的属性值
* @return 结果
*/
public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto, Collection fields) {
return toDynamicJoinQueryWrapper(dto, fields, null);
}
/**
* Entity或者DTO对象转换为QueryWrapper。
*
* @param 参数类型
* @param dto 参数对象
* @param fields 字段列表 指定参与转换的属性值
* @param myBatisPlusPagination 分页对象
* @return 结果
*/
public static ExtQueryWrapper toDynamicJoinQueryWrapper(DTO dto, Collection fields,
MyBatisPlusPagination myBatisPlusPagination) {
QueryWrapper queryWrapper = dtoToWrapper(dto, fields, myBatisPlusPagination);
if (!(queryWrapper instanceof DynamicJoinQueryWrapper)) {
return (ExtQueryWrapper)queryWrapper;
}
return (DynamicJoinQueryWrapper)queryWrapper;
}
/**
* 检查是否包含列。
*
* @param segments 片段列表
* @param idCol id列
* @return 结果
*/
public static boolean checkHasColumn(NormalSegmentList segments, String idCol) {
if (segments.size() > 0) {
for (ISqlSegment segment : segments) {
if (segment.getSqlSegment().equalsIgnoreCase(idCol)) {
return true;
}
}
}
return false;
}
/**
* 转换具体实现。
*
* @param 参数类型
* @param dto 参数对象
* @param fields 字段列表
* @param myBatisPlusPagination 分页对象
* @return 结果
*/
private static QueryWrapper> dtoToWrapper(DTO dto, Collection fields, MyBatisPlusPagination myBatisPlusPagination) {
QueryWrapper> wrapper;
/*转换*/
LinkedHashMap fieldValuesMap = extractNotNullValues(dto, fields, myBatisPlusPagination);
if (Colls.emptyMap(fieldValuesMap)) {
return new QueryWrapper<>();
}
/*只解析有值的*/
fields = fieldValuesMap.keySet();
/*是否有join联表查询*/
boolean hasJoinTable = ParserCache.hasJoinTable(dto, fields);
if (hasJoinTable) {
wrapper = new DynamicJoinQueryWrapper<>(dto.getClass(), fields);
} else {
wrapper = new ExtQueryWrapper<>();
}
/*构建 ColumnName*/
List annoJoinerList = ParserCache.getBindQueryAnnos(dto.getClass());
BiFunction buildColumnName = (bindQuery, field) -> {
if (bindQuery != null) {
String key = field.getName() + bindQuery;
for (AnnoJoiner annoJoiner : annoJoinerList) {
if (key.equals(annoJoiner.getKey())) {
if (StrUtil.isNotBlank(annoJoiner.getJoin())) {
/*获取注解Table*/
return annoJoiner.getAlias() + "." + annoJoiner.getColumnName();
} else {
return (hasJoinTable ? "self." : "") + annoJoiner.getColumnName();
}
}
}
}
return (hasJoinTable ? "self." : "") + MyBatisPlusUtil.getColumnName(field);
};
/*忽略空字符串"",空集合等。*/
BiPredicate ignoreEmpty = (value,
bindQuery) -> bindQuery != null && (Strategy.IGNORE_EMPTY.equals(bindQuery.strategy())
/*忽略空字符串""。*/
&& value instanceof String && StrUtil.isBlank((String)value)
/*忽略空集合。*/
|| Comparison.IN.equals(bindQuery.comparison()) && ObjectUtil.isEmpty(value));
/*获取Class类型。*/
Function> getClass = bindQuery -> bindQuery == null || bindQuery.entity() == NullType.class
? dto.getClass() : bindQuery.entity();
/*获取属性名类型。*/
BiFunction getFieldName = (bindQuery,
defFieldName) -> bindQuery == null || StrUtil.isBlank(bindQuery.field()) ? defFieldName : bindQuery.field();
/*保护字段处理器。*/
ProtectFieldHandler protectFieldHandler = SpringContextHolder.getBean(ProtectFieldHandler.class);
/*构建QueryWrapper。*/
for (Map.Entry entry : fieldValuesMap.entrySet()) {
FieldAndValue fieldAndValue = entry.getValue();
Field field = fieldAndValue.getField();
/*忽略注解 @TableField(exist = false) 的字段*/
TableField tableField = field.getAnnotation(TableField.class);
if (tableField != null && !tableField.exist()) {
continue;
}
/*忽略字段*/
BindQuery query = field.getAnnotation(BindQuery.class);
if (query != null && query.ignore()) {
continue;
}
BindQuery.List queryList = field.getAnnotation(BindQuery.List.class);
Object value = fieldAndValue.getValue();
/*构建Query*/
if (queryList != null) {
List bindQueryList = Arrays.stream(queryList.value())
.filter(e -> !ignoreEmpty.test(value, e)).collect(Collectors.toList());
wrapper.and(Colls.notEmptyColl(bindQueryList), queryWrapper -> {
for (BindQuery bindQuery : bindQueryList) {
String columnName = buildColumnName.apply(bindQuery, field);
if (protectFieldHandler != null) {
Class> clazz = getClass.apply(query);
String fieldName = getFieldName.apply(query, entry.getKey());
if (ParserCache.getProtectFieldList(clazz).contains(fieldName)) {
buildQuery(queryWrapper.or(), bindQuery, columnName,
protectFieldHandler.encrypt(clazz, fieldName, value.toString()));
continue;
}
}
buildQuery(queryWrapper.or(), bindQuery, columnName, value);
}
});
} else {
if (query == null && ObjectUtil.isEmpty(value)) {
continue;
}
if (ignoreEmpty.test(value, query)) {
continue;
}
String columnName = buildColumnName.apply(query, field);
if (protectFieldHandler != null) {
Class> clazz = getClass.apply(query);
String fieldName = getFieldName.apply(query, entry.getKey());
if (ParserCache.getProtectFieldList(clazz).contains(fieldName)) {
buildQuery(wrapper, query, columnName,
protectFieldHandler.encrypt(clazz, fieldName, value.toString()));
continue;
}
}
buildQuery(wrapper, query, columnName, value);
}
}
return wrapper;
}
/**
* 建立条件。
*
* @param wrapper 条件包装器
* @param bindQuery 注解
* @param columnName 列名
* @param value 值
*/
private static void buildQuery(QueryWrapper> wrapper, BindQuery bindQuery, String columnName, Object value) {
Comparison comparison = bindQuery != null ? bindQuery.comparison() : Comparison.EQ;
if (value == null) {
if (bindQuery != null && bindQuery.strategy().equals(Strategy.INCLUDE_NULL)
&& comparison.equals(Comparison.EQ)) {
wrapper.isNull(columnName);
}
return;
}
switch (comparison) {
case EQ:
wrapper.eq(columnName, value);
break;
case IN:
if (value.getClass().isArray()) {
Object[] valueArray = (Object[])value;
if (valueArray.length == 1) {
wrapper.eq(columnName, valueArray[0]);
} else if (valueArray.length >= 2) {
wrapper.in(columnName, valueArray);
}
} else if (value instanceof Collection) {
wrapper.in(!((Collection)value).isEmpty(), columnName, (Collection>)value);
} else {
log.warn("字段类型错误:IN仅支持List及数组.");
}
break;
case NOT_IN:
if (value.getClass().isArray()) {
Object[] valueArray = (Object[])value;
if (valueArray.length == 1) {
wrapper.ne(columnName, valueArray[0]);
} else if (valueArray.length >= 2) {
wrapper.notIn(columnName, valueArray);
}
} else if (value instanceof Collection) {
wrapper.notIn(!((Collection)value).isEmpty(), columnName, (Collection>)value);
} else {
log.warn("字段类型错误:NOT_IN仅支持List及数组.");
}
break;
case CONTAINS:
case LIKE:
wrapper.like(columnName, value);
break;
case STARTSWITH:
wrapper.likeRight(columnName, value);
break;
case ENDSWITH:
wrapper.likeLeft(columnName, value);
break;
case GT:
wrapper.gt(columnName, value);
break;
case BETWEEN_BEGIN:
case GE:
wrapper.ge(columnName, value);
break;
case LT:
wrapper.lt(columnName, value);
break;
case BETWEEN_END:
case LE:
wrapper.le(columnName, value);
break;
case BETWEEN:
if (value.getClass().isArray()) {
Object[] valueArray = (Object[])value;
if (valueArray.length == 1) {
wrapper.ge(columnName, valueArray[0]);
} else if (valueArray.length >= 2) {
wrapper.between(columnName, valueArray[0], valueArray[1]);
}
} else if (value instanceof List) {
List> valueList = (List>)value;
if (valueList.size() == 1) {
wrapper.ge(columnName, valueList.get(0));
} else if (valueList.size() >= 2) {
wrapper.between(columnName, valueList.get(0), valueList.get(1));
}
} else if (value instanceof String && ((String)value).contains(Strings.COMMA)) {
/*支持逗号分隔的字符串*/
Object[] valueArray = ((String)value).split(Strings.COMMA);
wrapper.between(columnName, valueArray[0], valueArray[1]);
} else {
wrapper.ge(columnName, value);
}
break;
/*不等于*/
case NOT_EQ:
wrapper.ne(columnName, value);
break;
default:
break;
}
}
/**
* 提取非空字段及值。
*
* @param 参数类型
* @param dto 参数对象
* @param fields 字段列表
* @param myBatisPlusPagination 分页对象
* @return 结果
*/
private static LinkedHashMap extractNotNullValues(DTO dto, Collection fields,
MyBatisPlusPagination myBatisPlusPagination) {
Class> dtoClass = dto.getClass();
/*转换。*/
List declaredFields = BeanUtil.extractAllFields(dtoClass);
List extractOrderFieldNames = extractOrderFieldNames(myBatisPlusPagination);
/*结果map:<字段名,字段对象和值>。*/
LinkedHashMap resultMap = new LinkedHashMap<>(declaredFields.size());
for (Field field : declaredFields) {
String fieldName = field.getName();
/*非指定属性,非逻辑删除字段,跳过。;*/
if (Colls.notContains(fields, fieldName)) {
// // Date 属性放过
// if (!V.equals(field.getType(), Date.class)) {
// continue;
// }
/*Date 属性放过。*/
if (ObjUtil.notEqualsObject(field.getType(), Date.class)) {
continue;
}
}
/*忽略static,以及final,transient。*/
int modifiers = field.getModifiers();
boolean isStatic = Modifier.isStatic(modifiers);
boolean isFinal = Modifier.isFinal(modifiers);
boolean isTransient = Modifier.isTransient(modifiers);
if (isStatic || isFinal || isTransient) {
continue;
}
/*打开私有访问 获取值。*/
field.setAccessible(true);
Object value = null;
try {
value = field.get(dto);
if (ObjUtil.isEmptyObject(value)) {
String prefix = ObjUtil.equalsObject(boolean.class, field.getType()) ? "is" : "get";
Method method = dtoClass.getMethod(prefix + StrUtil.lowerCaseFirst1(fieldName));
value = method.invoke(dto);
}
} catch (IllegalAccessException e) {
log.error("通过反射获取属性值出错:{}", e.getMessage());
} catch (NoSuchMethodException e) {
log.debug("通过反射获取属性方法不存在:{}", e.getMessage());
} catch (InvocationTargetException e) {
log.warn("通过反射执行属性方法出错:{}", e.getMessage());
}
/*忽略逻辑删除字段,含有逻辑删除字段,并且值为false,则忽略。*/
if (field.isAnnotationPresent(TableLogic.class) && ObjUtil.equalsObject(false, value)) {
continue;
}
BindQuery bindQuery = field.getAnnotation(BindQuery.class);
Strategy strategy = bindQuery != null ? bindQuery.strategy() : Strategy.IGNORE_EMPTY;
boolean collectThisField = false;
/*INCLUDE_NULL策略,包含null也收集。*/
if (strategy.equals(Strategy.INCLUDE_NULL)) {
collectThisField = true;
} else if (strategy.equals(Strategy.IGNORE_EMPTY) && ObjUtil.isNotEmptyObject(value)) {
collectThisField = true;
} else if (strategy.equals(Strategy.INCLUDE_EMPTY) && value != null) {
collectThisField = true;
} else if (extractOrderFieldNames.contains(fieldName)) {
collectThisField = true;
}
if (collectThisField) {
resultMap.put(fieldName, new FieldAndValue(field, value));
}
}
return resultMap;
}
/**
* 是否为排序字段。
*
* @param myBatisPlusPagination 分页对象
* @return 结果
*/
private static List extractOrderFieldNames(MyBatisPlusPagination myBatisPlusPagination) {
if (myBatisPlusPagination == null || StrUtil.isBlank(myBatisPlusPagination.getOrderBy())) {
return Collections.emptyList();
}
/*解析排序 orderBy=shortName:DESC,age:ASC,birthdate*/
String[] orderByFields = StrUtil.splitToArray(myBatisPlusPagination.getOrderBy());
List orderFields = new ArrayList<>(orderByFields.length);
for (String field : orderByFields) {
if (field.contains(Strings.COLON)) {
field = StrUtil.subStrBefore(field, Strings.COLON);
}
orderFields.add(field);
}
return orderFields;
}
/**
* 保存字段Field对象和字段值。
*/
private static class FieldAndValue {
private final Field field;
private final Object value;
public FieldAndValue(Field field, Object value) {
this.field = field;
this.value = value;
}
public Field getField() {
return field;
}
public Object getValue() {
return value;
}
}
}