# QueryBuilder 通用查询工具类使用指南 ## 一、功能特点 - ✅ **自动构建查询条件**:根据对象非空字段自动生成查询条件 - ✅ **支持分页查询**:内置分页功能 - ✅ **支持模糊查询**:可指定字段或全局设置String字段模糊查询 - ✅ **支持批量查询**:集合类型字段自动使用IN查询 - ✅ **支持范围查询**:识别Start/End后缀字段 - ✅ **链式调用**:流畅的API设计 - ✅ **类型安全**:自动处理序列化问题,避免类型转换错误 - ✅ **字段过滤**:自动跳过静态字段、transient字段、不存在字段 ## 二、基本使用 ### 1. 简单查询 ```java // Controller中 @GetMapping("/getList") public R> getList(@ModelAttribute LawyerUser query) { List list = QueryBuilder.of(query) .build() .list(lawyerUserService); return R.data(list); } ``` **请求示例:** ``` GET /lawyer/user/getList?name=张三&status=1 ``` **说明:** - 所有非空字段都会作为等值查询条件(`=`) - String类型字段默认使用等值查询 ### 2. 分页查询 ```java @GetMapping("/getPage") public R> getPage( @ModelAttribute LawyerUser query, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) { IPage page = QueryBuilder.of(query) .page(pageNum, pageSize) // 设置分页 .build() .page(lawyerUserService); // 执行分页查询 return R.data(page); } ``` ### 3. 模糊查询 #### 方式一:指定字段模糊查询(推荐) ```java @GetMapping("/search") public R> search(@ModelAttribute LawyerUser query) { List list = QueryBuilder.of(query) .likeFields("name", "phone") // 指定 name 和 phone 字段使用模糊查询 .build() .list(lawyerUserService); return R.data(list); } ``` **请求示例:** ``` GET /lawyer/user/search?name=张&phone=138 ``` **生成的SQL:** ```sql WHERE name LIKE '%张%' AND phone LIKE '%138%' ``` #### 方式二:全局String字段模糊查询 ```java @GetMapping("/search") public R> search(@ModelAttribute LawyerUser query) { List list = QueryBuilder.of(query) .stringFieldLike(true) // 所有String类型字段都使用模糊查询 .build() .list(lawyerUserService); return R.data(list); } ``` #### 方式三:使用_Like后缀字段(自动识别) 在实体类中添加_Like后缀字段(仅用于查询,不需要对应数据库字段): ```java // 查询实体类(继承基础实体类) public class LawyerUserQuery extends LawyerUser { private String name_Like; // 模糊查询姓名 private String phone_Like; // 模糊查询手机号 } ``` ```java // Controller中 @GetMapping("/search") public R> search(@ModelAttribute LawyerUserQuery query) { List list = QueryBuilder.of(query) .build() .list(lawyerUserService); return R.data(list); } ``` **请求示例:** ``` GET /lawyer/user/search?name_Like=张&phone_Like=138 ``` ### 4. 批量查询(IN查询) 在实体类中添加_List后缀字段: ```java // 查询实体类(继承基础实体类) public class LawyerUserQuery extends LawyerUser { private List id_List; // 批量查询ID private List status_List; // 批量查询状态 } ``` ```java // Controller中 @GetMapping("/getByIds") public R> getByIds(@ModelAttribute LawyerUserQuery query) { List list = QueryBuilder.of(query) .build() .list(lawyerUserService); return R.data(list); } ``` **请求示例:** ``` GET /lawyer/user/getByIds?id_List=1&id_List=2&id_List=3 ``` **生成的SQL:** ```sql WHERE id IN (1, 2, 3) ``` ### 5. 范围查询 在实体类中添加_Start/_End后缀字段: ```java // 查询实体类(继承基础实体类) public class LawyerUserQuery extends LawyerUser { private Date createdTime_Start; // 创建时间开始 private Date createdTime_End; // 创建时间结束 private Integer serviceCount_Start; // 服务次数范围开始 private Integer serviceCount_End; // 服务次数范围结束 } ``` ```java // Controller中 @GetMapping("/getByTimeRange") public R> getByTimeRange(@ModelAttribute LawyerUserQuery query) { List list = QueryBuilder.of(query) .build() .list(lawyerUserService); return R.data(list); } ``` **请求示例:** ``` GET /lawyer/user/getByTimeRange?createdTime_Start=2025-01-01&createdTime_End=2025-01-31 ``` **生成的SQL:** ```sql WHERE created_time >= '2025-01-01' AND created_time <= '2025-01-31' ``` ## 三、组合查询示例 ### 复杂查询场景 ```java @GetMapping("/complexQuery") public R> complexQuery( @ModelAttribute LawyerUserQuery query, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) { IPage page = QueryBuilder.of(query) .page(pageNum, pageSize) // 分页 .likeFields("name", "phone") // 指定字段模糊查询 .ignoreEmptyStr(true) // 忽略空字符串(默认true) .build() .page(lawyerUserService); return R.data(page); } ``` **请求示例:** ``` GET /lawyer/user/complexQuery?name=张&phone=138&status=1&createdTime_Start=2025-01-01&createdTime_End=2025-01-31&pageNum=1&pageSize=10 ``` **生成的SQL:** ```sql WHERE name LIKE '%张%' AND phone LIKE '%138%' AND status = 1 AND created_time >= '2025-01-01' AND created_time <= '2025-01-31' LIMIT 10 OFFSET 0 ``` ## 四、API方法说明 ### QueryBuilder 方法 #### 1. `of(T queryEntity)` - 创建查询构建器 ```java QueryBuilder.of(queryEntity) ``` #### 2. `ignoreEmptyStr(boolean ignore)` - 设置是否忽略空字符串 ```java QueryBuilder.of(query) .ignoreEmptyStr(true) // 默认true,忽略空字符串 .build() .list(service); QueryBuilder.of(query) .ignoreEmptyStr(false) // 保留空字符串作为查询条件 .build() .list(service); ``` #### 3. `stringFieldLike(boolean like)` - 设置String字段是否默认模糊查询 ```java QueryBuilder.of(query) .stringFieldLike(true) // 所有String字段使用模糊查询 .build() .list(service); QueryBuilder.of(query) .stringFieldLike(false) // 所有String字段使用等值查询(默认) .build() .list(service); ``` #### 4. `likeFields(String... fieldNames)` - 指定字段使用模糊查询 ```java QueryBuilder.of(query) .likeFields("name") // 单个字段 .build() .list(service); QueryBuilder.of(query) .likeFields("name", "phone") // 多个字段 .build() .list(service); ``` #### 5. `page(int pageNum, int pageSize)` - 设置分页参数 ```java QueryBuilder.of(query) .page(1, 10) // 第1页,每页10条 .build() .page(service); ``` #### 6. `page(Page page)` - 设置分页对象 ```java Page pageObj = new Page<>(1, 10); QueryBuilder.of(query) .page(pageObj) .build() .page(service); ``` #### 7. `build()` - 构建查询条件 ```java QueryResult result = QueryBuilder.of(query) .build(); // 返回 QueryResult 对象 ``` ### QueryResult 方法 #### 1. `list(IService service)` - 列表查询 ```java List list = builder.build().list(lawyerUserService); ``` #### 2. `page(IService service)` - 分页查询 ```java IPage page = builder.page(1, 10).build().page(lawyerUserService); ``` #### 3. `one(IService service)` - 单条查询 ```java LawyerUser user = builder.build().one(lawyerUserService); ``` #### 4. `count(IService service)` - 计数查询 ```java long count = builder.build().count(lawyerUserService); ``` #### 5. `getWrapper()` - 获取查询条件(用于调试) ```java QueryWrapper wrapper = builder.build().getWrapper(); System.out.println(wrapper.getTargetSql()); // 打印SQL ``` ## 五、命名规则 ### 1. 模糊查询字段 **方式一:使用 likeFields 方法指定** ```java .likeFields("name", "phone") // 在代码中指定 ``` **方式二:字段名以 `_Like` 结尾** - 字段名以 `_Like` 结尾 - 示例:`name_Like` → 查询 `name` 字段,使用 `LIKE '%value%'` ### 2. 批量查询字段 - 字段类型为 `Collection`(List、Set等) - 字段名以 `_List` 结尾(推荐) - 示例:`id_List` → 查询 `id` 字段,使用 `IN (1,2,3)` ### 3. 范围查询字段 - 字段名以 `_Start` 或 `_End` 结尾 - 成对出现:`xxx_Start` 和 `xxx_End` - 示例: - `createdTime_Start` → `createdTime >= value` - `createdTime_End` → `createdTime <= value` ## 六、查询优先级 ### 模糊查询优先级 1. **最高优先级**:`likeFields()` 方法指定的字段 2. **次优先级**:字段名以 `_Like` 结尾的字段 3. **全局设置**:`stringFieldLike(true)` 时,所有String字段使用模糊查询 4. **默认**:等值查询(`=`) ### 示例 ```java QueryBuilder.of(query) .stringFieldLike(true) // 全局:所有String字段模糊查询 .likeFields("name") // 指定:name字段模糊查询(优先级更高) .build() .list(service); ``` **结果:** - `name` 字段:使用模糊查询(`likeFields` 优先级更高) - 其他String字段:使用模糊查询(`stringFieldLike` 生效) - 非String字段:使用等值查询 ## 七、完整示例 ### 实体类定义 ```java import java.util.Date; import java.util.List; import lombok.Data; @Data public class LawyerUserQuery extends LawyerUser { // 模糊查询字段(方式一:在代码中指定,不需要在实体类中定义) // 方式二:使用_Like后缀字段 private String name_Like; private String phone_Like; // 批量查询字段 private List id_List; private List status_List; // 范围查询字段 private Date createdTime_Start; private Date createdTime_End; private Integer serviceCount_Start; private Integer serviceCount_End; } ``` ### Controller 完整示例 ```java import org.springframework.web.bind.annotation.*; import lombok.RequiredArgsConstructor; import com.baomidou.mybatisplus.core.metadata.IPage; @RestController @RequestMapping("/lawyer/user") @RequiredArgsConstructor public class LawyerUserController { private final LawyerUserService lawyerUserService; /** * 通用查询接口(支持所有查询方式) */ @GetMapping("/query") public R> query( @ModelAttribute LawyerUserQuery query, @RequestParam(defaultValue = "1") int pageNum, @RequestParam(defaultValue = "10") int pageSize) { IPage page = QueryBuilder.of(query) .page(pageNum, pageSize) .likeFields("name", "phone") // 指定字段模糊查询 .build() .page(lawyerUserService); return R.data(page); } /** * 简单查询(只使用等值查询) */ @GetMapping("/simple") public R> simple(@ModelAttribute LawyerUser query) { List list = QueryBuilder.of(query) .build() .list(lawyerUserService); return R.data(list); } /** * 全局模糊查询(所有String字段都模糊查询) */ @GetMapping("/search") public R> search(@ModelAttribute LawyerUser query) { List list = QueryBuilder.of(query) .stringFieldLike(true) // 所有String字段模糊查询 .build() .list(lawyerUserService); return R.data(list); } } ``` ## 八、注意事项 ### 1. 字段过滤规则 - **自动跳过**:静态字段(`static`)、transient字段(`transient`) - **自动跳过**:`@TableField(exist = false)` 标记的字段 - **自动跳过**:空值(`null`)、空字符串(如果启用 `ignoreEmptyStr`) - **自动跳过**:空集合 ### 2. 字段名映射 - **优先使用**:`@TableField` 注解的 `value` 属性 - **默认规则**:驼峰命名转下划线命名(`userName` → `user_name`) ### 3. 序列化安全 - 自动过滤不可序列化的对象 - 只支持基本类型:Number、String、Boolean、Date等 - 集合元素会自动过滤不可序列化的项 ### 4. 性能考虑 - 批量查询(IN)建议限制集合大小,避免SQL过长 - 模糊查询(LIKE)在大数据量时可能较慢,建议添加索引 ### 5. 日期处理 - 日期字段会自动处理空字符串绑定问题 - 支持 `java.util.Date`、`java.sql.Date`、`LocalDate`、`LocalDateTime` ## 九、常见问题 ### Q1: 如何让某个String字段使用等值查询,其他字段使用模糊查询? ```java // 方式一:使用全局模糊查询,然后排除特定字段 QueryBuilder.of(query) .stringFieldLike(true) // 全局模糊查询 .build() .list(service); // 注意:没有单独排除的方法,可以使用Like后缀字段的方式 // 方式二:只指定需要模糊查询的字段 QueryBuilder.of(query) .likeFields("name", "phone") // 只指定这些字段模糊查询 .build() .list(service); ``` ### Q2: 如何同时使用等值查询和模糊查询? ```java // 在实体类中定义两个字段 // 查询实体类(继承基础实体类) public class LawyerUserQuery extends LawyerUser { private String name; // 等值查询 private String name_Like; // 模糊查询 } // 使用时 QueryBuilder.of(query) .build() // name使用等值查询,name_Like使用模糊查询 .list(service); ``` ### Q3: 如何查询空值? ```java QueryBuilder.of(query) .ignoreEmptyStr(false) // 不忽略空字符串 .build() .list(service); ``` ### Q4: 如何调试生成的SQL? ```java QueryResult result = QueryBuilder.of(query).build(); QueryWrapper wrapper = result.getWrapper(); System.out.println(wrapper.getTargetSql()); // 打印SQL语句 ``` ## 十、最佳实践 ### 1. 推荐使用方式 ```java // ✅ 推荐:指定字段模糊查询 QueryBuilder.of(query) .likeFields("name", "phone") .build() .list(service); // ✅ 推荐:使用_Like后缀字段(更灵活) // 在实体类中定义 name_Like 字段 QueryBuilder.of(query) .build() .list(service); ``` ### 2. 不推荐使用方式 ```java // ❌ 不推荐:全局String字段模糊查询(可能影响不需要模糊的字段) QueryBuilder.of(query) .stringFieldLike(true) // 除非你真的需要所有String字段都模糊 .build() .list(service); ``` ### 3. 性能优化建议 - 模糊查询字段建议添加数据库索引 - 批量查询(IN)建议限制集合大小(如:最多1000个) - 复杂查询建议使用分页,避免一次性查询大量数据 --- **总结**:`QueryBuilder` 提供了强大而灵活的查询能力,只需要传入对象,就能自动构建各种查询条件,大大简化了开发工作。通过合理使用 `likeFields()` 和 `stringFieldLike()` 方法,可以灵活控制模糊查询行为。