如何在MyBatis中使用注解实现条件Where子句?
MyBatis注解实现条件Where子句查询的参数绑定问题
现有代码及问题
Service层代码
public List<ApplicationConfig> find(@RequestBody String type){ List<WhereClauseParams> conditions = new ArrayList<>(); WhereClauseParams condition = new WhereClauseParams("type", type); conditions.add(condition); return applicationConfigRepository.find(conditions); } public List<ApplicationConfig> findById(@RequestBody String id){ List<WhereClauseParams> conditions = new ArrayList<>(); WhereClauseParams condition = new WhereClauseParams("id", id); conditions.add(condition); return applicationConfigRepository.find(conditions); }
自定义WhereClauseParams类
public class WhereClauseParams { private String column; private String sqlOperator = "="; private Object value; // 包含对应的getter、setter方法与构造方法 }
Mapper接口代码
@Repository @Mapper public interface ApplicationConfigRepository { @Select("<script>" + "select id, name, type, isActive, createdBy, createdOn, updatedBy, updatedOn " + "from application_config " + "where 1=1 " + "<if test=\"type!=null\"> " + " and type=#{type} " + " </if>" + "<if test=\"id!=null\"> " + " and id=#{id} " + " </if>" + "</script>") public List<ApplicationConfig> find(List<WhereClauseParams> params); }
首次报错信息
org.apache.ibatis.binding.BindingException: Parameter 'type' not found. Available parameters are [collection, list, params] ...(省略完整栈信息)
尝试将Mapper中的条件改为params.type!=null,问题未解决。
修改后的尝试
修改后的Service层
public List<ApplicationConfig> find(@RequestBody String type){ List<WhereClauseParams> conditions = new ArrayList<>(); WhereClauseParams condition = new WhereClauseParams("type", type); conditions.add(condition); return applicationConfigRepository.find(Map.of("type", type)); } public List<ApplicationConfig> findById(@RequestBody String id){ List<WhereClauseParams> conditions = new ArrayList<>(); WhereClauseParams condition = new WhereClauseParams("id", id); conditions.add(condition); return applicationConfigRepository.find(Map.of("id", id)); }
修改后的Mapper接口
@Select("<script>" + "select id, name, type, isActive, createdBy, createdOn, updatedBy, updatedOn " + "from application_config " + "where 1=1 " + "<if test=\"params.type!=null\"> " + " and type=#{params.type} " + " </if>" + "<if test=\"params.id!=null\"> " + " and id=#{params.id} " + " </if>" + "</script>") public List<ApplicationConfig> find(Map params);
新报错信息
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'params.type!=null'. Cause: org.apache.ibatis.ognl.OgnlException: source is null for getProperty(null, "type") ...(省略完整栈信息)
解决方案
方案1:简化Map参数传递
修改Mapper的SQL表达式,去掉多余的params.前缀,因为传递的Map直接包含type、id等键:
@Repository @Mapper public interface ApplicationConfigRepository { @Select("<script>" + "select id, name, type, isActive, createdBy, createdOn, updatedBy, updatedOn " + "from application_config " + "where 1=1 " + "<if test=\"type!=null\"> " + " and type=#{type} " + " </if>" + "<if test=\"id!=null\"> " + " and id=#{id} " + " </if>" + "</script>") public List<ApplicationConfig> find(Map<String, Object> params); }
Service层保持现有传递Map的逻辑即可,无需额外修改。
方案2:复用WhereClauseParams实现动态多条件
如果需要支持多条件组合查询,保留WhereClauseParams设计,用MyBatis的<foreach>遍历条件列表:
- 修改Mapper接口,用
@Param明确参数名:
@Repository @Mapper public interface ApplicationConfigRepository { @Select("<script>" + "select id, name, type, isActive, createdBy, createdOn, updatedBy, updatedOn " + "from application_config " + "where 1=1 " + "<foreach collection='conditions' item='condition' separator=' and '>" + " ${condition.column} ${condition.sqlOperator} #{condition.value} " + "</foreach>" + "</script>") public List<ApplicationConfig> find(@Param("conditions") List<WhereClauseParams> conditions); }
- 注意:
column和sqlOperator用${}(直接拼接SQL,需确保参数安全,避免注入),value用#{}(预编译,防止注入)。
- Service层恢复最初传递
conditions列表的逻辑即可。
方案3:单条件场景简化实现
如果只是单条件查询(按type或id),直接用@Param标注单个参数:
@Repository @Mapper public interface ApplicationConfigRepository { @Select("<script>" + "select id, name, type, isActive, createdBy, createdOn, updatedBy, updatedOn " + "from application_config " + "where 1=1 " + "<if test='type != null'> and type = #{type} </if>" + "<if test='id != null'> and id = #{id} </if>" + "</script>") List<ApplicationConfig> find(@Param("type") String type, @Param("id") String id); }
Service层调用时传递对应参数,比如find(type, null)或find(null, id)。
内容的提问来源于stack exchange,提问作者Abhishek Acharya
相关产品推荐
相关产品推荐

