在Java中实现多条件筛选功能_Java动态查询项目解析

Java多条件筛选应使用MyBatis-Plus的QueryWrapper实现动态查询,自动忽略空值,避免SQL注入;需封装ConditionBuilder解耦逻辑,建立联合索引优化性能。

Java中实现多条件筛选,核心在于构建灵活、可扩展的动态查询逻辑,避免硬编码SQL或大量if-else拼接。关键不是写死条件,而是让查询条件“可插拔”——用户选了哪些字段、填了哪些值,系统就自动加入对应WHERE子句。

用QueryWrapper(MyBatis-Plus)简化动态条件组装

MyBatis-Plus的QueryWrapper天然支持链式调用和空值跳过,是实现多条件筛选最常用且简洁的方式。它会自动忽略值为null、空字符串或集合为空的条件。

  • 对字符串字段:用likeeqne等方法,传入参数前无需手动判空
  • 对数值/日期字段:直接传参,若前端未提交该字段(即后端接收为null),对应条件不会进入SQL
  • 示例:用户输入用户名关键词+选择状态+指定创建时间范围,代码只需:

QueryWrapper wrapper = new QueryWrapper();
wrapper.like(StringUtils.isNotBlank(username), "username", username)
    .eq(status != null, "status", status)
    .between(startTime != null && endTime != null, "create_time", startTime, endTime);

封装通用条件处理器,解耦业务与查询逻辑

当筛选字段较多(如10+个)、规则较复杂(模糊+精确+范围+IN多选)时,建议将条件解析提取为独立组件,比如ConditionBuilder类。它接收DTO对象,按约定规则转换为QueryWrapper或Criteria对象。

  • 统一处理“空字符串视为忽略”、“-1表示全部”、“字符串trim后再判断”等细节
  • 支持自定义条件映射,例如DTO中userTypeList字段自动转为IN子句
  • 便于单元测试和后期新增筛选项,不侵入Service主流程

避免SQL注入与类型安全:别用字符串拼接,慎用apply()

绝对不要用wrapper.apply("age > " + age)这类方式拼接用户输入——存在SQL注入风险。所有用户输入必须走参数化占位符(?)。

  • 优先使用内置方法:gt("age", age)in("type"

    , types)
  • 必须用apply()时,只用于固定SQL片段(如函数、排序伪列),且参数仍需用{}占位并传参
  • 对枚举/状态码等受限值,入库前做白名单校验,防止恶意传入非法字符串

分页与性能兼顾:合理使用索引与延迟加载

多条件组合容易导致全表扫描。即使功能跑通,也要关注实际执行效率。

  • 在高频筛选字段(如status、create_time、tenant_id)上建立联合索引,顺序按区分度从高到低排列
  • 避免在WHERE中对字段做函数操作(如DATE(create_time) = '2025-01-01'),会失效索引
  • 大数据量下,考虑用SELECT COUNT(1)单独查总数,而非PageHelper.startPage().count(true)自动统计(可能慢)