利用反射动态构造wrapper条件
/**
* api 列表查询实体类
*
* @author wys
*/
@Data
public class SysApiQuery {
private Long id;
/**
* api名称
*/
@Query(type = QueryTypeEnum.EQUAL)
private String apiName;
/**
* api路径
*/
@Query(type = QueryTypeEnum.EQUAL)
private String apiUrl;
/** 开始时间 */
@JsonIgnore
private String beginTime;
/** 结束时间 */
@JsonIgnore
private String endTime;
}
@Getter
@RequiredArgsConstructor
public enum QueryTypeEnum {
/**
* 等值查询,例如:WHERE `age` = 18
*/
EQUAL(1, "="),
/**
* 非等值查询,例如:WHERE `age` != 18
*/
NOT_EQUAL(2, "!="),
/**
* 大于查询,例如:WHERE `age` > 18
*/
GREATER_THAN(3, ">"),
/**
* 小于查询,例如:WHERE `age` < 18
*/
LESS_THAN(4, "<"),
/**
* 大于等于查询,例如:WHERE `age` >= 18
*/
GREATER_THAN_OR_EQUAL(5, ">="),
/**
* 小于等于查询,例如:WHERE `age` <= 18
*/
LESS_THAN_OR_EQUAL(6, "<="),
/**
* 范围查询,例如:WHERE `age` BETWEEN 10 AND 18
*/
BETWEEN(7, "BETWEEN"),
/**
* 左模糊查询,例如:WHERE `nickname` LIKE '%s'
*/
LEFT_LIKE(8, "LIKE '%s'"),
/**
* 中模糊查询,例如:WHERE `nickname` LIKE '%s%'
*/
INNER_LIKE(9, "LIKE '%s%'"),
/**
* 右模糊查询,例如:WHERE `nickname` LIKE 's%'
*/
RIGHT_LIKE(10, "LIKE 's%'"),
/**
* 包含查询,例如:WHERE `age` IN (10, 20, 30)
*/
IN(11, "IN"),
/**
* 不包含查询,例如:WHERE `age` NOT IN (20, 30)
*/
NOT_IN(12, "NOT IN"),
/**
* 空查询,例如:WHERE `email` IS NULL
*/
IS_NULL(13, "IS NULL"),
/**
* 非空查询,例如:WHERE `email` IS NOT NULL
*/
IS_NOT_NULL(14, "IS NOT NULL"),;
private final Integer value;
private final String description;
}
import com.chinaunicom.common.enums.QueryTypeEnum;
import java.lang.annotation.*;
/**
* 查询注解
*
* @author Zheng Jie(ELADMIN)
* @author Charles7c
* @since 2023/1/15 18:01
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Query {
/**
* 属性名(默认和使用该注解的属性的名称一致)
*/
String property() default "";
/**
* 查询类型(等值查询、模糊查询、范围查询等)
*/
QueryTypeEnum type() default QueryTypeEnum.EQUAL;
/**
* 多属性模糊查询,仅支持 String 类型属性,多个属性之间用逗号分隔
*
* 例如:@Query(blurry = "username,email") 表示根据用户名和邮箱模糊查询
*
*/
String blurry() default "";
}
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.chinaunicom.common.annotation.Query;
import com.chinaunicom.common.enums.QueryTypeEnum;
import com.chinaunicom.common.utils.reflect.ReflectUtils;
import com.chinaunicom.common.validate.ValidationUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* 查询助手
*
* @author Zheng Jie(ELADMIN)
* @author Charles7c
* @since 2023/1/15 18:17
*/
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class QueryHelper {
/**
* 根据查询条件构建 MyBatis Plus 查询条件封装对象
*
* @param query
* 查询条件
* @param
* 查询条件数据类型
* @param
* 查询数据类型
* @return MyBatis Plus 查询条件封装对象
*/
public static QueryWrapper build(Q query) {
QueryWrapper queryWrapper = new QueryWrapper<>();
// 没有查询条件,直接返回
if (null == query) {
return queryWrapper;
}
// 获取查询条件中所有的字段
List fieldList = ReflectUtils.getNonStaticFields(query.getClass());
fieldList.forEach(field -> buildQuery(query, field, queryWrapper));
return queryWrapper;
}
/**
* 构建 MyBatis Plus 查询条件封装对象
*
* @param query
* 查询条件
* @param field
* 字段
* @param queryWrapper
* MyBatis Plus 查询条件封装对象
* @param
* 查询条件数据类型
* @param
* 查询数据类型
*/
private static void buildQuery(Q query, Field field, QueryWrapper queryWrapper) {
boolean accessible = field.isAccessible();
try {
field.setAccessible(true);
// 没有 @Query,直接返回
Query queryAnnotation = field.getAnnotation(Query.class);
if (null == queryAnnotation) {
return;
}
// 如果字段值为空,直接返回
Object fieldValue = field.get(query);
if (ObjectUtil.isEmpty(fieldValue)) {
return;
}
// 解析查询条件
parse(queryAnnotation, field.getName(), fieldValue, queryWrapper);
} catch (Exception e) {
log.error("Build query occurred an error: {}. Query: {}, Field: {}.", e.getMessage(), query, field, e);
} finally {
field.setAccessible(accessible);
}
}
/**
* 解析查询条件
*
* @param queryAnnotation
* 查询注解
* @param fieldName
* 字段名
* @param fieldValue
* 字段值
* @param queryWrapper
* MyBatis Plus 查询条件封装对象
* @param
* 查询数据类型
*/
private static void parse(Query queryAnnotation, String fieldName, Object fieldValue,
QueryWrapper queryWrapper) {
// 解析多属性模糊查询
// 如果设置了多属性模糊查询,分割属性进行条件拼接
String blurry = queryAnnotation.blurry();
if (StrUtil.isNotBlank(blurry)) {
String[] propertyArr = blurry.split(",");
queryWrapper.and(wrapper -> {
for (String property : propertyArr) {
wrapper.or().like(StrUtil.toUnderlineCase(property), fieldValue);
}
});
return;
}
// 解析单个属性查询
// 如果没有单独指定属性名,就和使用该注解的属性的名称一致
// 注意:数据库规范中列采用下划线连接法命名,程序规范中变量采用驼峰法命名
String property = queryAnnotation.property();
String columnName = StrUtil.toUnderlineCase(StrUtil.blankToDefault(property, fieldName));
QueryTypeEnum queryType = queryAnnotation.type();
switch (queryType) {
case EQUAL:
queryWrapper.eq(columnName, fieldValue);
break;
case NOT_EQUAL:
queryWrapper.ne(columnName, fieldValue);
break;
case GREATER_THAN:
queryWrapper.gt(columnName, fieldValue);
break;
case LESS_THAN:
queryWrapper.lt(columnName, fieldValue);
break;
case GREATER_THAN_OR_EQUAL:
queryWrapper.ge(columnName, fieldValue);
break;
case LESS_THAN_OR_EQUAL:
queryWrapper.le(columnName, fieldValue);
break;
case BETWEEN:
List
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.Data;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
/**
* 分页信息
*
* @param
* 列表数据类型
* @author Charles7c
* @since 2023/1/14 23:40
*/
@Data
public class PageDataVO implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 列表数据
*/
private List list;
/**
* 总记录数
*/
private long total;
/**
* 基于 MyBatis Plus 分页数据构建分页信息,并将源数据转换为指定类型数据
*
* @param page
* MyBatis Plus 分页数据
* @param targetClass
* 目标类型 Class 对象
* @param
* 源列表数据类型
* @param
* 目标列表数据类型
* @return 分页信息
*/
public static PageDataVO build(IPage page, Class targetClass) {
if (null == page) {
return empty();
}
PageDataVO pageDataVO = new PageDataVO<>();
pageDataVO.setList(BeanUtil.copyToList(page.getRecords(), targetClass));
pageDataVO.setTotal(page.getTotal());
return pageDataVO;
}
/**
* 基于 MyBatis Plus 并将源数据转换为指定类型数据
*
* @param
*
* @param targetClass
* 目标类型 Class 对象
* @param
* 源列表数据类型
* @param
* 目标列表数据类型
* @return 分页信息
*/
public static List build(List list, Class targetClass) {
if (null == list) {
return new ArrayList<>();
}
List toList = BeanUtil.copyToList(list, targetClass);
return toList;
}
/**
* 基于 MyBatis Plus 分页数据构建分页信息
*
* @param page
* MyBatis Plus 分页数据
* @param
* 列表数据类型
* @return 分页信息
*/
public static PageDataVO build(IPage page) {
if (null == page) {
return empty();
}
PageDataVO pageDataVO = new PageDataVO<>();
pageDataVO.setList(page.getRecords());
pageDataVO.setTotal(page.getTotal());
return pageDataVO;
}
/**
* 基于列表数据构建分页信息
*
* @param page
* 页码
* @param size
* 每页条数
* @param list
* 列表数据
* @param
* 列表数据类型
* @return 分页信息
*/
public static PageDataVO build(int page, int size, List list) {
if (CollUtil.isEmpty(list)) {
return empty();
}
PageDataVO pageDataVO = new PageDataVO<>();
pageDataVO.setTotal(list.size());
// 对列表数据进行分页
int fromIndex = (page - 1) * size;
int toIndex = page * size + size;
if (fromIndex > list.size()) {
pageDataVO.setList(new ArrayList<>(0));
} else if (toIndex >= list.size()) {
pageDataVO.setList(list.subList(fromIndex, list.size()));
} else {
pageDataVO.setList(list.subList(fromIndex, toIndex));
}
return pageDataVO;
}
/**
* 空分页信息
*
* @param
* 列表数据类型
* @return 分页信息
*/
private static PageDataVO empty() {
PageDataVO pageDataVO = new PageDataVO<>();
pageDataVO.setList(new ArrayList<>(0));
return pageDataVO;
}
}
@Override
public List pageList(SysApiQuery apiQuery) {
// 根据查询条件构建 MyBatis Plus 查询条件封装对象
QueryWrapper queryWrapper = QueryHelper.build(apiQuery);
List apiList = baseMapper.selectList(queryWrapper);
// 基于 MyBatis Plus 并将源数据转换为指定类型数据
List list = PageDataVO.build(apiList, SysApiVo.class);
return list;
}