Springboot+Mybatis实现条件查询可以这样实现
@Data
@NoArgsConstructor
@ApiModel("查询DTO")
public class QueryDTO {
@ApiModelProperty("名称")
private String name;
@ApiModelProperty("类型")
private String type;
@ApiModelProperty("描述")
private String description;
}
Controller代码如下
@GetMapping("/list")
@ApiOperation(value = "列表查询")
public Result list(@ApiParam QueryDTO request){
QueryWrapper<QueryDTO> queryWrapper = new QueryWrapper<>();
if(request.getName()!=null){
queryWrapper.like("name",request.getName());
}
if(request.getType()!=null){
queryWrapper.eq("type",request.getType());
}
if(request.getDescription()!=null){
queryWrapper.eq("descrption",request.getDescription());
}
List<QueryDTO> list = service.list(queryWrapper);
return Result.success(list);
}
可见,每多一个条件,就要多写一段 queryWrapper.eq...这样类似的代码
使用自定义注解可以更优雅的实现条件查询
添加一个自定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Query {
/**
* 对应数据库字段,为空取实体属性名 驼峰转下划线
*/
String column() default "";
/**
* 另一个类中的属性名称,支持多级获取,以小数点隔开
*/
String targetAttr() default "";
/**
* 查询类型
*/
Type type() default Type.EQUAL;
enum Type {
/**
* 相等
*/
EQUAL((queryWrapper, filedColumn, val) -> {
queryWrapper.eq(filedColumn, val);
}),
/**
* 大于等于
*/
GREATER_THAN((queryWrapper, filedColumn, val) -> {
queryWrapper.ge(filedColumn, val);
}),
/**
* 大于
*/
GREATER_THAN_NQ((queryWrapper, filedColumn, val) -> {
queryWrapper.gt(filedColumn, val);
}),
/**
* 小于等于
*/
LESS_THAN((queryWrapper, filedColumn, val) -> {
queryWrapper.le(filedColumn, val);
}),
/**
* 小于
*/
LESS_THAN_NQ((queryWrapper, filedColumn, val) -> {
queryWrapper.lt(filedColumn, val);
}),
/**
* 不等于
*/
NOT_EQUAL((queryWrapper, filedColumn, val) -> {
queryWrapper.ne(filedColumn, val);
}),
/**
* 不为空
*/
NOT_NULL((queryWrapper, filedColumn, val) -> {
queryWrapper.isNotNull(filedColumn);
}),
/**
* 中模糊查询<br/>
* like %str%
*/
LIKE((queryWrapper, filedColumn, val) -> {
queryWrapper.like(filedColumn, val);
}),
/**
* 左模糊查询
*/
LEFT_LIKE((queryWrapper, filedColumn, val) -> {
queryWrapper.likeLeft(filedColumn, val);
}),
/**
* 右模糊查询
*/
RIGHT_LIKE((queryWrapper, filedColumn, val) -> {
queryWrapper.likeRight(filedColumn, val);
}),
/**
* 包含
*/
IN((queryWrapper, filedColumn, val) -> {
queryWrapper.in(filedColumn, (Collection) val);
}),
/**
* JSON数组中是否包含
*/
JSON_ARRAY_CONTAINS((queryWrapper, filedColumn, val) -> {
queryWrapper.apply("JSON_CONTAINS(" + filedColumn + ",json_array({0}) )", val);
}),
;
private TriConsumer consumer;
Type(TriConsumer<QueryWrapper, String, Object> consumer) {
this.consumer = consumer;
}
public void buildQuery(QueryWrapper t, String field, Object val) {
consumer.accept(t, field, val);
}
}
}
如果字段名与属性名相同或相匹配(驼峰转下划线 如:createTime-> create_time 表示字段匹配),不用标注column字段 如果字段名与属性名不同且不匹配,如属性名为 searchValue,需要查询的字段是name,则需要增加column字段,@Query(column="name") 默认使用=查询,如果要使用like或其它查询类型,则需要标注type字段,选择相应的type即可,如: @Query(type=Query.Type.LIKE) 每个type会生成什么样的QueryWrapper语句,可以参考Type枚举类的方法
再添加一个处理注解的工具类
@Slf4j
public class QueryUtil {
public static <T> QueryWrapper setQueryWrapper(T bean) {
QueryWrapper<T> queryWrapper = new QueryWrapper<>();
if (bean == null) {
return queryWrapper;
}
try {
List<Object[]> fields = getFields(bean.getClass());
for (Object[] os : fields) {
Field field = (Field) os[0];
Query q = (Query) os[1];
Object val = getTargetValue(bean, field, q);
if (val == null) {
continue;
}
String filedColumn = StringUtils.isBlank(q.column()) ? StringUtils.toUnderScoreCase(field.getName()) : q.column();
q.type().buildQuery(queryWrapper,filedColumn,val);
}
} catch (Exception e) {
log.error("设置查询条件失败{}", e);
}
return queryWrapper;
}
/**
* 获取bean值
*
* @param vo
* @param field
* @return
* @throws Exception
*/
public static Object getObjectValue(Object vo, Field field) throws Exception {
Object o = field.get(vo);
if (o == null) {
return null;
}
//空字符串转换为null对象
if (field.getGenericType().toString().equals("class java.lang.String")) {
String val = (String) o;
if (StringUtils.isBlank(val)) {
o = null;
}
}
return o;
}
/**
* 获取bean中的属性值
*
* @param vo 实体对象
* @param field 字段
* @param query 注解
* @return 最终的属性值
* @throws Exception
*/
private static Object getTargetValue(Object vo, Field field, Query query) throws Exception {
Object o = getObjectValue(vo, field);
if (o == null) {
return o;
}
if (StringUtils.isNotEmpty(query.targetAttr())) {
String target = query.targetAttr();
if (target.contains(".")) {
String[] targets = target.split("[.]");
for (String name : targets) {
o = getValue(o, name);
}
} else {
o = getValue(o, target);
}
}
return o;
}
/**
* 以类的属性的get方法方法形式获取值
*
* @param o
* @param name
* @return value
* @throws Exception
*/
private static Object getValue(Object o, String name) throws Exception {
if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) {
if (o instanceof Map) {
Map<String, Object> objectMap = BeanUtils.beanToMap(o);
if (objectMap.containsKey(name)) {
return objectMap.get(name);
}
return null;
} else {
Class<?> clazz = o.getClass();
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
o = getObjectValue(o, field);
}
}
return o;
}
/**
* 获取字段注解信息
*/
public static List<Object[]> getFields(Class clazz) {
List<Object[]> fields = new ArrayList<Object[]>();
List<Field> tempFields = new ArrayList<>();
tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
for (Field field : tempFields) {
// 单注解
if (field.isAnnotationPresent(Query.class)) {
Query attr = field.getAnnotation(Query.class);
if (attr != null) {
field.setAccessible(true);
fields.add(new Object[]{field, attr});
}
}
// 多注解
if (field.isAnnotationPresent(Queries.class)) {
Queries attrs = field.getAnnotation(Queries.class);
Query[] queries = attrs.value();
for (Query attr : queries) {
if (attr != null) {
field.setAccessible(true);
fields.add(new Object[]{field, attr});
}
}
}
}
return fields;
}
}
在查询的DTO类中使用注解
@Data
@NoArgsConstructor
@ApiModel("查询DTO")
public class QueryDTO {
/**
* 名称
*/
@ApiModelProperty("名称")
@Query(type = Query.Type.LIKE) //不是用等于查找条件,需要指定type
private String name;
/**
* 类型
*/
@ApiModelProperty("类型")
@Query //表字段与属性名相匹配,且是用等于查找的,只需要这样的简单注解即可
private String type;
/**
* 描述
*/
@ApiModelProperty("描述")
@Query(column="description") //如果字段名与属性名不匹配,则添加column字段值指定表字段
private String description;
}
Controller类中使用如下:
@GetMapping("/list")
@ApiOperation(value = "列表查询")
public Result list(@ApiParam QueryDTO request){
QueryWrapper<QueryDTO> queryWrapper = QueryUtil.setQueryWrapper(request);
List<QueryDTO> list = service.list(queryWrapper);
return Result.success(list);
}
Controller中的代码更简洁了,如果需要增加一个条件,只需要在QueryDTO中增加一处属性和注解即可,不用再复制一段雷同的代码