前言

自定义查询注解是为实体类中某些实体属性作为查询条件定义的,在实体属性上引入注解可以实现自动生成查询条件QueryWrapper的功能。


一、为什么引入自定义查询注解

一个实体作为查询条件,但实体里面的属性很多,如果写在mapper.xml里面要写很多的判断,如果用mybatis-plus 的LambdaQueryWrapper会显得很臃肿如下:

    /**
     * 公共查询条件
     * @param bean
     * @return
     */
    private LambdaQueryWrapper<Bean> getCommonCondition(Bean bean) {
        LambdaQueryWrapper<Bean> lqw = new LambdaQueryWrapper<Bean>()
                .like(StringUtils.isNotNull(bean.getLName()), Bean::getLeadName, bean.getSName())
                .like(StringUtils.isNotNull(bean.getTName()), Bean::getTeamName, bean.getTName())
                .eq(StringUtils.isNotNull(bean.getActId()), Bean::getActId, bean.getActId())
                .eq(StringUtils.isNotNull(bean.getIdCard()), Bean::getLeadIdCard, bean.getIdCard())
                .like(StringUtils.isNotNull(bean.getPhone()), Bean::getLeadPhone, bean.getPhone())
                .gt(StringUtils.isNotNull(bean.getStartTime()), Bean::getCreateTime, bean.getStartTime())
                .lt(StringUtils.isNotNull(bean.getEndTime()), Bean::getCreateTime, bean.getEndTime())
                .eq(StringUtils.isNotNull(bean.getStatus()), Bean::getCheckStatus, bean.getStatus());
        return lqw;
    }

二、自定义查询注解定义

1.Query 注解

代码如下:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义导出Excel数据注解
 *
 * @author lys
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Query {
    /**
     * 对应数据库字段,为空取实体属性名 驼峰转下划线
     */
    public String filedColumn() default "";
    /**
     * 分隔符,读取字符串组内容
     */
    public String separator() default ",";
    /**
     * 另一个类中的属性名称,支持多级获取,以小数点隔开
     */
    public String targetAttr() default "";
    /**
     * 字段类型
     */
    Type type() default Type.EQUAL;

    enum Type {
        EQUAL //相等
        , GREATER_THAN// 大于等于
        , GREATER_THAN_NQ  //大于
        , LESS_THAN //小于等于
        , LESS_THAN_NQ //小于
        , NOT_EQUAL  //不等于
        , NOT_NULL  //不为空
        , INNER_LIKE //中模糊查询
        , LEFT_LIKE // 左模糊查询
        , RIGHT_LIKE //右模糊查询
        , IN  //包含
        , BETWEEN  //between
        , UNIX_TIMESTAMP //查询时间
    }
}

2.Querys 注解(用于属性多个条件情况)

代码如下:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Excel注解集
 * @author lys
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Querys {
    Query[] value();
}

3.Query注解处理工具类

代码如下:


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.core.annotation.Query;
import com.core.annotation.Querys;
import com.core.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Query相关处理
 * @author lys
 */
public class QueryUtil {
    private static final Logger log = LoggerFactory.getLogger(QueryUtil.class);

    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.filedColumn()) ? StrUtil.toUnderlineCase(field.getName()) :q.filedColumn();
                switch (q.type()) {
//                    case EQUAL:
//                        queryWrapper.eq(ReflectUtil.getFieldName(field),val);
//                        break;
                    case GREATER_THAN: // 大于等于
                        queryWrapper.ge(filedColumn, val);
                        break;
                    case GREATER_THAN_NQ: //大于
                        queryWrapper.gt(filedColumn, val);
                        break;
                    case LESS_THAN: //小于等于
                        queryWrapper.le(filedColumn, val);
                        break;
                    case LESS_THAN_NQ: //小于
                        queryWrapper.lt(filedColumn, val);
                        break;
                    case INNER_LIKE: //中模糊查询
                        queryWrapper.like(filedColumn, val);
                        break;
                    case LEFT_LIKE: //左模糊查询
                        queryWrapper.likeLeft(filedColumn, val);
                        break;
                    case RIGHT_LIKE: //右模糊查询
                        queryWrapper.likeRight(filedColumn, val);
                        break;
                    case IN: //包含
                        if (field.getGenericType().toString().equals("class java.lang.String")) {
                            queryWrapper.in(filedColumn, ((String)val).split(q.separator()));
                        } else if (CollUtil.isNotEmpty((Collection) val)) {
                            queryWrapper.in(filedColumn, (Collection) val);
                        }
                        break; //不等于
                    case NOT_EQUAL:
                        queryWrapper.ne(filedColumn, val);
                        break;
                    case NOT_NULL: //不为空
                        queryWrapper.isNotNull(filedColumn);
                        break;
                    case BETWEEN:  //between
                        List between = new ArrayList<>((List) val);
                        queryWrapper.between(filedColumn, between.get(0), between.get(1));
                        break;
                    case UNIX_TIMESTAMP: //查询时间
                        List UNIX_TIMESTAMP = new ArrayList<>((List) val);
                        if (!UNIX_TIMESTAMP.isEmpty()) {
                            SimpleDateFormat fm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            Date time1 = fm.parse(UNIX_TIMESTAMP.get(0).toString());
                            Date time2 = fm.parse(UNIX_TIMESTAMP.get(1).toString());
                            queryWrapper.between(filedColumn, time1, time2);
                        }
                        break;
                    default: //默认等于
                        queryWrapper.eq(filedColumn,val);
                        break;
                }
            }
        } 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;}
        if (field.getGenericType().toString().equals("class java.lang.String")) {
            String val = (String) o;
            if (StringUtils.isBlank(val)) {
                o = null;
            }
        } else
            // 如果类型是Integer
            if (field.getGenericType().toString().equals("class java.lang.int")) {
                int val = Integer.parseInt((String) o);
                if (val == 0) {
                    o = null;
                }
            } else {
                // 如果类型是Double
                if (field.getGenericType().toString().equals("class java.lang.long")) {
                    long val = Long.parseLong((String) o);
                    if (val == 0) {
                        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 = BeanUtil.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(Querys.class)) {
                Querys attrs = field.getAnnotation(Querys.class);
                Query[] querys = attrs.value();
                for (Query attr : querys) {
                    if (attr != null) {
                        field.setAccessible(true);
                        fields.add(new Object[]{field, attr});
                    }
                }
            }
        }
        return fields;
    }
}


4.示例

1.单注解方式

    /**
     * 创建者
     */
    @ApiModelProperty(value = "创建者")
    @TableField(fill = FieldFill.INSERT)
    @Query
    private String createBy;

2.多注解方式

     /**
     * 请求参数
     */
    @ApiModelProperty(value = "请求参数")
    @TableField(exist = false)
    @JsonIgnore
    @Querys({
        @Query(filedColumn = "create_time", targetAttr = "params.beginTime",type = Query.Type.GREATER_THAN),
        @Query(filedColumn = "create_time", targetAttr = "params.endTime",type = Query.Type.LESS_THAN)
    })
    private Map<String, Object> params = new HashMap<>();

3.应用示例


import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.common.core.annotation.Query;
import com.common.core.annotation.Querys;
import io.swagger.annotations.ApiModelProperty;

/**
 * (Demo)请求实体类
 * @author lys
 */
@Data
@EqualsAndHashCode(callSuper = true)
@NoArgsConstructor
public class ReqDemo {

    @ApiModelProperty(value = "唯一标识")
    @Query
    private Long id;

    @ApiModelProperty(value = "名称")
    @Query(type = Query.Type.INNER_LIKE)
    private String name;
    
    @ApiModelProperty(value = "身份证号")
    @Query(type = Query.Type.INNER_LIKE)
    private String idcard;
    
    @ApiModelProperty(value = "创建者")
    @Query
    private String createBy;

	//多注解方式
    @ApiModelProperty(value = "请求参数")
    @Querys({
        @Query(filedColumn = "create_time", targetAttr = "params.beginTime",type = Query.Type.GREATER_THAN),
        @Query(filedColumn = "create_time", targetAttr = "params.endTime",type = Query.Type.LESS_THAN)
    })
    private Map<String, Object> params = new HashMap<>();
    
}
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.common.mybatis.core.page.PageQuery;
import com.common.mybatis.core.page.TableDataInfo;
import com.common.mybatis.util.QueryUtil;
import com.demo.domain.Demo;
import com.demo.domain.req.ReqDemo;
import com.demo.mapper.DemoMapper;
import com.demo.service.DemoService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;
/**
 * (Demo)表服务实现类
 * @author lys
 */
@RequiredArgsConstructor
@Service
public class DemoServiceImpl extends ServiceImpl<DemoMapper, Demo> implements DemoService {

    @Override
    public TableDataInfo<Demo> selectPageList(ReqDemo bean, PageQuery pageQuery) {
        QueryWrapper<Demo> queryWrapper = QueryUtil.setQueryWrapper(bean);
        //xml方式
        Page<Demo> page = this.getBaseMapper().selectPageList(pageQuery.build(), queryWrapper);
        return TableDataInfo.build(page);
    }

    @Override
    public List<Demo> selectList(ReqDemo bean) {
        QueryWrapper<Demo> queryWrapper = QueryUtil.setQueryWrapper(bean);
        //直接调用 mybatis-plus baseMapper方式
        return this.getBaseMapper().selectList(queryWrapper);
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.demo.mapper.DemoMapper">
    <resultMap type="com.demo.domain.Demo" id="DemoMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="idcard" column="idcard" jdbcType="VARCHAR"/>
        <result property="age" column="age" jdbcType="INTEGER"/>
        <result property="createTime" column="create_time" jdbcType="TIMESTAMP"/>
        <result property="updateTime" column="update_time" jdbcType="TIMESTAMP"/>
        <result property="createBy" column="create_by" jdbcType="VARCHAR"/>
        <result property="updateBy" column="update_by" jdbcType="VARCHAR"/>
    </resultMap>
    <select id="selectPageList" resultType="com.demo.domain.Demo">
        select id,name,idcard,age,create_time,update_time,create_by,update_by
        from demo as q ${ew.customSqlSegment}
    </select>
</mapper>

总结

本文仅用于学习记录,如有不合理地方欢迎指出。
参考来源:https://blog.csdn.net/ly1316221439/article/details/123555418

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐