MyBatisPlus查询对象转QueryWrapper工具类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MyBatisPlus查询对象转QueryWrapper工具类相关的知识,希望对你有一定的参考价值。

技术背景

在使用MyBatisPlus技术实际项目中,尤其是后台管理系统之类的项目中,经常会出现大量的需要将查询对象转换成QueryWrapper的应用场景,这时候就需要编写出现大量的转换代码,比如:

待转换的查询实体类

@Getter
@Setter
@ToString(callSuper = true)
public class MemberQuery  extends BaseQuery 

    /**
     * 昵称
     */
    private String nickname;

    /**
     * 性别:1女 2男 3未知
     */
    private Integer gender;

    /**
     * 生日:下限
     */
    private LocalDate start;
    /**
     * 生日:上限
     */
    private LocalDate end;

    /**
     * 电话
     */
    private String tel;

    /**
     * 外键:角色编号
     */
    private Long roleId;

    /**
     * 状态:1未激活 2激活
     */
    private Integer state;

    @Builder
    public MemberQuery(Integer pageNum, Integer pageSize, String nickname, Integer gender, LocalDate start, LocalDate end, String tel, Long roleId, Integer state) 
        super(pageNum, pageSize);
        this.nickname = nickname;
        this.gender = gender;
        this.start = start;
        this.end = end;
        this.tel = tel;
        this.roleId = roleId;
        this.state = state;
    

上面查询类引用的BaseQuery封装了分页信息,具体代码如下:

@Setter
@ToString
@AllArgsConstructor
public class BaseQuery 
    /**
     * 页码
     */
    private Integer pageNum;
    /**
     * 页面大小
     */
    private Integer pageSize;

    public Integer getPageNum() 
        return pageNum == null ? 1 : pageNum;
    

    public Integer getPageSize() 
        return pageSize == null ? GlobalConst.PAGE_SIZE : pageSize;
    

在Controller中进行转换

@PostMapping("/list")
public ResultBean list(@RequestBody MemberQuery memberQuery) 
    IPage<Member> page = new Page<>(memberQuery.getPageNum(), memberQuery.getPageSize());

    LambdaQueryWrapper<Member> queryWrapper = new LambdaQueryWrapper<>();

    if (memberQuery.getNickname() != null) 
        queryWrapper.like(Member::getNickname, memberQuery.getNickname());
    
    if (memberQuery.getTel() != null) 
        queryWrapper.like(Member::getTel, memberQuery.getTel());
    
    if (memberQuery.getGender() != null) 
        queryWrapper.eq(Member::getGender, memberQuery.getGender());
    
    if (memberQuery.getRoleId() != null) 
        queryWrapper.eq(Member::getRoleId, memberQuery.getRoleId());
    
    if (memberQuery.getState() != null) 
        queryWrapper.eq(Member::getState, memberQuery.getState());
    
    if (memberQuery.getStart() != null) 
        queryWrapper.ge(Member::getBirth,memberQuery.getStart());
    
    if(memberQuery.getEnd() != null)
        queryWrapper.le(Member::getBirth,memberQuery.getEnd());
    

    memberService.page(page, queryWrapper);

    PageBean<Member> pageBean = PageBean.init(page);

    return ResultBeanUtil.success().buildData("pageBean",pageBean);

上面大量的转换代码,不仅写起来烦琐,而且也不优雅。此时可以采用注解+反射技术编写一个工具类:将Query对象转换成Wrapper,具体代码如下:

优化方案

表示关系运算的接口

public interface Logic 
    String and = "AND";
    String or = "OR";

表示逻辑运算的枚举

  • Between
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Between 
    String logic() default Logic.and;

  • EQ
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface EQ 
    String logic() default Logic.and;

    String value() default "";

  • IN
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface IN 
    String logic() default Logic.and;

    String value() default "";

  • Like
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Like 
    String logic() default "AND";

    String value() default "";

  • NE
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface NE 
    String logic() default Logic.and;

    String value() default "";

封装区间的Bean

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class RangeBean<T> 
    /**
     * 下限
     */
    private T start;
    /**
     * 上限
     */
    private T end;

具体转换的工具类

public class QueryWrapperUtil<T> 

    /**
     * 将查询对象转换成MyBatisPlus中的QueryWrapper
     * @param query
     * @param <T>
     * @return
     */
    public static <T> QueryWrapper<T> build(Object query) 
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();

        //获取Query类中都有哪些属性
        final Field[] fields = query.getClass().getDeclaredFields();
        for (Field field : fields) 
            field.setAccessible(true);
            java.lang.Object fieldValue = null;
            try 
                fieldValue = field.get(query);
             catch (IllegalAccessException e) 
                e.printStackTrace();
            
            if (fieldValue != null) 
                //获取Query类属性上的注解
                final Annotation[] annotations = field.getAnnotations();
                for (Annotation annotation : annotations) 
                    //获取Query类属性的名称
                    final String fieldName = field.getName();
                    //获取Query类对应的表字段名
                    final String columnName = StringUtil.hump2underscore(fieldName);

                    //获取Query类属性上的注解类型的字节码
                    final Class<? extends Annotation> annotationType = annotation.annotationType();
                    if (EQ.class == annotationType) 
                        EQ eq = (EQ) annotation;
                        fun(eq.logic(), queryWrapper);
                        queryWrapper.eq(columnName, fieldValue);
                     else if (Like.class == annotationType) 
                        Like like = (Like) annotation;
                        fun(like.logic(), queryWrapper);
                        queryWrapper.like(columnName, fieldValue);
                     else if (IN.class == annotationType) 
                        IN in = (IN) annotation;
                        fun(in.logic(), queryWrapper);
                        queryWrapper.in(columnName, fieldValue);
                     else if (NE.class == annotationType) 
                        NE ne = (NE) annotation;
                        fun(ne.logic(), queryWrapper);
                        queryWrapper.ne(columnName, fieldValue);
                     else if (Between.class == annotationType) 
                        Between between = (Between) annotation;
                        fun(between.logic(), queryWrapper);
                        RangeBean rangeBean = (RangeBean) fieldValue;
                        queryWrapper.between(columnName, rangeBean.getStart(), rangeBean.getEnd());
                    
                
            
        
        return queryWrapper;
    

    /**
     * 添加or关系
     * @param logic
     * @param queryWrapper
     * @param <T>
     */
    private static <T> void fun(String logic, QueryWrapper<T> queryWrapper) 
        if ("or".equalsIgnoreCase(logic)) 
            queryWrapper.or();
        
    


优化方案:工具类应用

@PostMapping("/list")
public ResultBean list(@RequestBody MemberQuery memberQuery) 
    IPage<Member> page = new Page<>(memberQuery.getPageNum(), memberQuery.getPageSize());
    QueryWrapper<Member> queryWrapper = QueryWrapperUtil.build(memberQuery);
    memberService.page(page, queryWrapper);
    PageBean<Member> pageBean = PageBean.init(page);
    return ResultBeanUtil.success().addData("pageBean",pageBean);

以上是关于MyBatisPlus查询对象转QueryWrapper工具类的主要内容,如果未能解决你的问题,请参考以下文章

mybatisplus的分页关键字连表查询

mybatis-plus分页查询

SpringBoot 加 MybatisPlus高级查询

MybatisPlus resultMap标签collection的注解写法

Vue+SpringBoot 前后端分离实战(mybatisplus多表分页查询+博客显示)

MyBatisPlus