• 利用反射动态构造wrapper条件( 利用反射获取注解值以及实体类值)


    利用反射动态构造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;
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    QueryTypeEnum枚举类

    @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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65

    Query自定义注解

    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 ""; }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    QueryHelper 查询助手

    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 between = new ArrayList<>((List)fieldValue);
                    ValidationUtils.throwIf(between.size() != 2, "[{}] 必须是一个范围", fieldName);
                    queryWrapper.between(columnName, between.get(0), between.get(1));
                    break;
                case LEFT_LIKE:
                    queryWrapper.likeLeft(columnName, fieldValue);
                    break;
                case INNER_LIKE:
                    queryWrapper.like(columnName, fieldValue);
                    break;
                case RIGHT_LIKE:
                    queryWrapper.likeRight(columnName, fieldValue);
                    break;
                case IN:
                    ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName);
                    queryWrapper.in(columnName, (List)fieldValue);
                    break;
                case NOT_IN:
                    ValidationUtils.throwIfEmpty(fieldValue, "[{}] 不能为空", fieldName);
                    queryWrapper.notIn(columnName, (List)fieldValue);
                    break;
                case IS_NULL:
                    queryWrapper.isNull(columnName);
                    break;
                case IS_NOT_NULL:
                    queryWrapper.isNotNull(columnName);
                    break;
                default:
                    throw new IllegalArgumentException(String.format("暂不支持 [%s] 查询类型", queryType));
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176

    PageDataVO 结构封装

    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;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144

    service实现

       @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;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
  • 相关阅读:
    Go模板页面浏览器显示HTML源码问题
    servlet
    【Java基础】数据结构与算法
    动静分离和前后端分离
    从阿里出发看微服务发展!P8架构师手打800页微服务深度解析笔记
    nginx location / 区别
    SQL优化面试专题
    12 个强大的现代 CSS 技术
    人工智能:引领未来生活与工作的变革力量
    ajax(Springmvc实现和注册提示效果)
  • 原文地址:https://blog.csdn.net/weixin_43564627/article/details/134331269