mybatis-plus 使用实体类传参 构造wrapper

本文介绍了一种利用注解简化MyBatis-Plus查询条件设置的方法,通过自定义工具类和注解,实现实体类属性直接转换为查询条件,提升开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.问题:现在mybatis-plus已经很多人用了,我们查询条件通常会很多,如果使用wrapper去一个个判空,再eq()。是不是很繁琐。比如:

是不是很low啊,现在让我们通过注解一行搞定所有查询条件

2.解决办法

  实现思路:

      1.在实体类中直接使用注解,表明需要什么查询

     2.写个工具类反射获取注解值和属性值,再进行包装wrapper

3.实现过程

1.工具类

/**
 * 牛逼的wrapper构造
 * 描述:实体类使用注解 WhereType
 * 默认 为等于,其他的使用枚举;参考InStorePageVo
 * @author: 张鹏
 * @Date: 2018/11/26
 */
@Data
public class WhereEntityTool {
    private static Map<WhereTypeEnum, WhereFun> typeFunc;

    static {
        if (typeFunc == null) {
            typeFunc = new HashMap<>();
            typeFunc.put(WhereTypeEnum.EQ, (w, k, v) -> {
                w.eq(k, v);
            });
            typeFunc.put(WhereTypeEnum.NEQ, (w, k, v) -> {
                w.ne(k, v);
            });
            typeFunc.put(WhereTypeEnum.IN, (w, k, v) -> {
                if (v instanceof Collection) {
                    w.in(k, (Collection<?>) v);
                } else if (v instanceof Object[]) {
                    w.in(k, (Object[]) v);
                } else {
                    w.in(k, v.toString());
                }
            });
            typeFunc.put(WhereTypeEnum.LIKE, (w, k, v) -> {
                w.like(k, v.toString());
            });
            typeFunc.put(WhereTypeEnum.LE, (w, k, v) -> {
                w.le(k, v);
            });
            typeFunc.put(WhereTypeEnum.LT, (w, k, v) -> {
                w.lt(k, v);
            });
            typeFunc.put(WhereTypeEnum.GE, (w, k, v) -> {
                w.ge(k, v);
            });
            typeFunc.put(WhereTypeEnum.GT, (w, k, v) -> {
                w.gt(k, v);
            });
        }

    }
    /**
     * 封装成需要的wrapper
     *
     * @param t 实体对象
     * @return
     */
    public static Wrapper invoke(Object t) {
        Wrapper<T> wrapper = new EntityWrapper();
        excute(t, wrapper);
        // 获取
        return wrapper;
    }

    public static void invoke(Object t, Wrapper wrapper) {
        excute(t, wrapper);
    }
    /**
     * 执行
     *
     * @param t       obj
     * @param wrapper
     */
    public static void excute(Object t, Wrapper wrapper) {
        //反射获取属性
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field field : fields) {
            try {
                field.setAccessible(true);
                Object val = field.get(t);
                String colum = "";
                if (val != null && !"".equals(val.toString())) {
                    WhereType whereType = field.getAnnotation(WhereType.class);
                    //没有注解,取默认为下划线拼接
                    if (whereType == null) {
                        colum = camelToUnderline(field.getName());
                        // 执行方法
                        typeFunc.get(WhereTypeEnum.EQ).whereFunc(wrapper, colum, val);
                    } else {
                        if (whereType.ignore()) {
                            continue;
                        } else {
                            //没有定义查询属性,取默认
                            if (!StringUtils.isBlank(whereType.filed())) {
                                colum = whereType.filed();
                            } else {
                                colum = camelToUnderline(field.getName());
                            }
                            // 是否另取一个where
                            if (whereType.andNew()) {
                                wrapper.andNew();
                            }
                            // 执行方法
                            typeFunc.get(whereType.type()).whereFunc(wrapper, colum, val);
                        }
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 驼峰转下划线
     * @param param
     * @return
     * @Author 张鹏
     * @Date 2018/11/27 11:52
     */
    public static String camelToUnderline(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append("_");
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static void main(String[] args) {
        InStorePageVo inStorePageVo = new InStorePageVo();
        inStorePageVo.setBusinessCompany("测试了");
        inStorePageVo.setBusinessNo("1112312");
        inStorePageVo.setBusinessType("adaaa");
        inStorePageVo.setCustomerName("zpzp");

        Wrapper<InstoreView> wrapper = WhereEntityTool.invoke(inStorePageVo);
        System.out.println(wrapper.toString());
    }
}

2.注解、枚举类和接口

public enum WhereTypeEnum {
    EQ,NEQ,IN,LIKE,LT,GT,LE,GE;
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface WhereType {

    /**
     * <p>
     * 查询类型
     * </p>
     */
    WhereTypeEnum type() default WhereTypeEnum.EQ;

    /**
     * 判定字段名
     * @return
     */
    String filed() default "";
    /**
     * 是否忽略
     */
    boolean ignore() default false;

    boolean andNew() default  false;

}

/**
 * 说明:
 * @author 张鹏
 * @create
 */
public interface WhereFun {
    void whereFunc(Wrapper wrapper,String field, Object vaule);
}

3.使用效果

    @ApiModelProperty(value="分公司")
    @WhereType(filed = "businessCompany",type=WhereTypeEnum.LIKE)
    private String businessCompany;

    @ApiModelProperty(value="仓库")
    private String wareHouseNo;
    @ApiModelProperty(value="业务状态")
    private String intoStatus;
    @ApiModelProperty(value="入库日期")
    @WhereType(filed = "into_time",type=WhereTypeEnum.GE)
    private String intoTimeStart;
    @WhereType(filed = "into_time",type=WhereTypeEnum.GT)
    private String intoTimeEnd;


/// 调用
        WhereEntityTool.invoke(inStorePageVo,wrapper);

感谢大家的支持!谢谢

<think>嗯,用户想详细了解MyBatis-Plus的条件构造器QueryWrapper的用法。让我先回顾一下之前的对话和提供的引用内容。用户之前的问题是关于mapper-locations配置的,现在转到了条件构造器,特别是QueryWrapper。我需要确保回答的结构清晰,涵盖基本用法、链式调用、条件组合、排序分页、Lambda表达式对比,以及常见问题。首先,引用[1]、[2]、[3]都提到了Wrapper的三种类型,其中QueryWrapper用于查询条件。引用[4]和[5]给出了具体的代码示例,尤其是QueryWrapper和LambdaQueryWrapper的区别。用户可能需要知道如何构建各种查询条件,比如eq、like、between等,以及如何组合条件。接下来,我需要分步骤解释QueryWrapper的用法。从创建实例开始,然后逐个添加条件方法,比如eq、like、in等。链式调用是关键点,需要强调其可读性和维护性。同时,要提到条件优先级,比如and和or的使用,引用[4]中的例子展示了嵌套的and方法,需要详细说明。 然后,排序和分页也是常用功能,需要包括orderBy和last方法的应用。不过要注意last方法可能带来的SQL注入风险,提醒用户谨慎使用。比较QueryWrapper和LambdaQueryWrapper的区别也很重要,引用[5]提到列名的不同处理方式,需要指出Lambda的类型安全优势,但QueryWrapper在动态场景下的灵活性。 可能还需要提到多条件组合时的逻辑,比如and和or的嵌套,以及如何处理复杂的查询结构。例如,用户可能需要同时满足多个条件,或者其中一个条件满足即可,这时候需要正确使用括号来组合条件。 另外,用户可能在实际使用中遇到条件不生效的问题,这时候需要检查是否错误地使用了链式调用,或者条件字段名是否正确。例如,数据库字段名是否与实体类属性对应,尤其是在使用下划线命名的情况下。最后,生成相关问题,比如如何解决条件优先级问题,或者动态条件构建的方法,帮助用户进一步学习。确保引用标记正确,比如链式调用的部分引用[2],条件构造器的类型引用[3],Lambda的对比引用[5]等。总结下来,回答的结构应该包括基本用法、常用方法、链式调用、条件组合、排序分页、与Lambda的对比、注意事项,以及相关问题。需要确保每个部分都有代码示例,并正确引用提供的资料。</think>### MyBatis-Plus 条件构造器 QueryWrapper 详解 #### 1. **基本概念与核心作用** QueryWrapperMyBatis-Plus 提供的查询条件封装类,用于**动态构建 SQL 查询条件**,避免手动编写 XML 或注解中的复杂条件逻辑[^1]。其核心优势在于: - **链式调用**:通过方法链式组合条件,提升代码可读性[^2]; - **类型安全**:支持 Lambda 表达式(LambdaQueryWrapper),减少字段名硬编码错误; - **防 SQL 注入**:内部自动处理参数化查询,提升安全性[^2]。 #### 2. **核心方法与使用场景** ##### 2.1 基础条件构建 ```java QueryWrapper<User> wrapper = new QueryWrapper<>(); // 等于条件 wrapper.eq("age", 25); // WHERE age = 25 // 模糊查询 wrapper.like("name", "张"); // WHERE name LIKE '%张%' // 范围查询 wrapper.between("create_time", startDate, endDate); // WHERE create_time BETWEEN ? AND ? // IN 查询 wrapper.in("status", Arrays.asList(1, 3, 5)); // WHERE status IN (1,3,5) ``` [^4] ##### 2.2 链式调用与条件组合 ```java // 组合 AND/OR 条件 wrapper.gt("age", 18) .and(w -> w.like("email", "@example.com").or().isNotNull("phone")) .orderByDesc("create_time"); // 对应 SQL: // WHERE age > 18 AND (email LIKE '%@example.com%' OR phone IS NOT NULL) ORDER BY create_time DESC ``` [^4] ##### 2.3 动态条件(空值过滤) ```java User user = new User(); user.setName("李四"); user.setStatus(null); // 状态为 null 时自动忽略该条件 QueryWrapper<User> wrapper = new QueryWrapper<>(user) .eq(StringUtils.isNotBlank(user.getName()), "name", user.getName()) .eq(user.getStatus() != null, "status", user.getStatus()); // 若 user.name 非空且 status 为 null,生成 SQL: WHERE name = '李四' ``` [^5] #### 3. **复杂条件与嵌套逻辑** ##### 3.1 嵌套 AND/OR 条件 ```java wrapper.likeRight("name", "王") .and(w -> w.eq("gender", 1).or().gt("age", 30)); // SQL: WHERE name LIKE '王%' AND (gender = 1 OR age > 30) ``` [^4] ##### 3.2 子查询支持 ```java wrapper.inSql("department_id", "SELECT id FROM department WHERE name = '研发部'"); // SQL: WHERE department_id IN (SELECT id FROM department WHERE name = '研发部') ``` #### 4. **排序与分页** ```java // 排序 wrapper.orderByAsc("age", "create_time"); // ORDER BY age ASC, create_time ASC // 分页(需配合 Page 对象) Page<User> page = new Page<>(1, 10); userMapper.selectPage(page, wrapper); ``` [^4] #### 5. **QueryWrapper 与 LambdaQueryWrapper 对比** | **特性** | **QueryWrapper** | **LambdaQueryWrapper** | |----------------|---------------------------|----------------------------------| | 字段引用方式 | 字符串(易错) | 方法引用(类型安全) | | 动态条件 | 灵活但需手动判空 | 支持链式动态过滤 | | 适用场景 | 简单查询或动态字段名场景 | 复杂条件且需类型安全的场景 | ```java // LambdaQueryWrapper 示例 LambdaQueryWrapper<User> lambdaWrapper = new LambdaQueryWrapper<>(); lambdaWrapper.eq(User::getAge, 25).like(User::getName, "张"); ``` [^5] #### 6. **常见问题与解决** - **条件未生效**:检查字段名是否与数据库列名一致(区分大小写和下划线规则)[^5]; - **动态条件失效**:确保使用 `.eq(condition, column, value)` 格式,且 `condition` 为布尔值; - **性能问题**:避免在循环中频繁创建 QueryWrapper 对象。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值