# Redkale FilterNode 使用易错点 > 创建时间:2026-02-03 > 基于:flux-api 项目实际代码 --- ## ❌ 常见错误 ### 1. LIKE 查询错误 **错误写法**: ```java // ❌ 错误:使用静态方法 node.and(PartnerFormRecord::getRealname, FilterNode.like(keyword)); ``` **正确写法**: ```java // ✅ 正确:使用实例方法 node.like(PartnerFormRecord::getRealname, keyword); ``` --- ### 2. 比较查询错误 **错误写法**: ```java // ❌ 错误:方法名拼写错误 node.and(PartnerFormRecord::getCreatedtime, FilterNode.greateEqual(starttime)); node.and(PartnerFormRecord::getCreatedtime, FilterNode.lessEqual(endtime)); ``` **正确写法**: ```java // ✅ 正确:使用简短的方法名 node.ge(PartnerFormRecord::getCreatedtime, starttime); node.le(PartnerFormRecord::getCreatedtime, endtime); ``` **参考方法**: - `ge()` - Greater or Equal(>=) - `le()` - Less or Equal(<=) - `gt()` - Greater Than(>) - `lt()` - Less Than(<) --- ### 3. OR 条件错误 **错误写法**: ```java // ❌ 错误:在 and() 中混用 FilterNode 静态方法 node.and( FilterNode.or( PartnerFormRecord::getRealname, FilterNode.like(keyword), PartnerFormRecord::getMobile, FilterNode.like(keyword) ) ); ``` **正确写法**: ```java // ✅ 正确:创建独立 OR 节点,链式调用 FilterNode orNode = new FilterNode(); orNode.or(PartnerFormRecord::getRealname, FilterNode.like(keyword)) .or(PartnerFormRecord::getMobile, FilterNode.like(keyword)) .or(PartnerFormRecord::getIdcard, FilterNode.like(keyword)); node.and(orNode); ``` --- ### 4. 等值条件冗余 **错误写法**: ```java // ❌ 冗余:等值条件不需要特殊方法 node.and(PartnerFormRecord::getStatus, FilterNode.eq(1)); ``` **正确写法**: ```java // ✅ 简洁:直接传值 node.and(PartnerFormRecord::getStatus, 1); ``` --- ### 5. NOT 条件错误 **错误写法**: ```java // ❌ 错误:使用不存在的 notLike 方法 node.notLike(PartnerFormRecord::getStatus, 3); ``` **正确写法**: ```java // ✅ 正确:使用 notEq node.notEq(PartnerFormRecord::getStatus, 3); ``` --- ## ✅ 正确的模式 ### 基础查询条件 ```java FilterNode node = new FilterNode(); // 固定条件 node.and(PartnerFormRecord::getDraftstatus, (short) 0); // 可选条件 if (bean.getKeyword() != null && !bean.getKeyword().isEmpty()) { node.like(PartnerFormRecord::getRealname, bean.getKeyword()); } // 范围查询 if (bean.getStarttime() > 0) { node.ge(PartnerFormRecord::getCreatedtime, bean.getStarttime()); } if (bean.getEndtime() > 0) { node.le(PartnerFormRecord::getCreatedtime, bean.getEndtime()); } // 不等于 node.notEq(PartnerFormRecord::getStatus, (short) 3); ``` ### OR 条件组合 ```java // 关键词:姓名 OR 电话 OR 身份证 if (bean.getKeyword() != null && !bean.getKeyword().isEmpty()) { FilterNode orNode = new FilterNode(); orNode.or(PartnerFormRecord::getRealname, FilterNode.like(bean.getKeyword())) .or(PartnerFormRecord::getMobile, FilterNode.like(bean.getKeyword())) .or(PartnerFormRecord::getIdcard, FilterNode.like(bean.getKeyword())); node.and(orNode); } ``` ### IN 条件 ```java // IN 查询 FilterNode node = new FilterNode(); node.in(PartnerFormRecord::getFormdataid, formIds.toArray()); List list = dataSource.queryList(PartnerFormRecord.class, node); ``` --- ## 📋 FilterNode 方法速查表 | 方法 | 说明 | 示例 | |------|------|------| | `and()` | AND 等值条件 | `node.and(Entity::getField, value)` | | `like()` | LIKE 模糊查询 | `node.like(Entity::getField, "%keyword%")` | | `ge()` | >= 大于等于 | `node.ge(Entity::getTime, timestamp)` | | `le()` | <= 小于等于 | `node.le(Entity::getTime, timestamp)` | | `gt()` | > 大于 | `node.gt(Entity::getField, value)` | | `lt()` | < 小于 | `node.lt(Entity::getField, value)` | | `notEq()` | != 不等于 | `node.notEq(Entity::getStatus, 3)` | | `in()` | IN 查询 | `node.in(Entity::getId, ids.toArray())` | | `or()` | OR 条件 | 需创建独立 FilterNode | --- ## 🔍 完整示例参考 ### PartnerFormService.java ```java @RestMapping(name = "list", comment = "分页查询表单记录") public RetResult> list(FormRecordFilterBean bean, Flipper flipper) { FilterNode node = new FilterNode(); node.notEq(PartnerFormRecord::getStatus, STATUS_DELETED); if (!Utils.isEmpty(bean.getRealname())) { node.like(PartnerFormRecord::getRealname, bean.getRealname()); } if (bean.getDraftstatus() >= 0) { node.and(PartnerFormRecord::getDraftstatus, bean.getDraftstatus()); } if (bean.getStarttime() > 0) { node.ge(PartnerFormRecord::getCreatedtime, bean.getStarttime()); } if (bean.getEndtime() > 0) { node.le(PartnerFormRecord::getCreatedtime, bean.getEndtime()); } Sheet sheet = dataSource.querySheet(PartnerFormRecord.class, flipper, node); return render(sheet); } ``` ### PartnerCustomerService.java ```java @RestMapping(name = "list", comment = "分页查询客户列表") public RetResult> list(PartnerCustomerFilterBean bean, Flipper flipper) { FilterNode node = new FilterNode(); node.notEq(PartnerCustomer::getStatus, (short) 3); if (!Utils.isEmpty(bean.getMobile())) { node.and(PartnerCustomer::getMobile, bean.getMobile()); } if (bean.getStatus() > 0) { node.and(PartnerCustomer::getStatus, bean.getStatus()); } if (bean.getStarttime() > 0) { node.ge(PartnerCustomer::getCreatedtime, bean.getStarttime()); } if (bean.getEndtime() > 0) { node.le(PartnerCustomer::getCreatedtime, bean.getEndtime()); } Sheet sheet = dataSource.querySheet(PartnerCustomer.class, flipper, node); return render(sheet); } ``` --- ## ⚠️ 注意事项 1. **方法调用方式**:所有条件方法都是 `FilterNode` 实例的方法,不是静态方法 2. **方法命名**:`ge`/`le` 而非 `greateEqual`/`lessEqual` 3. **OR 条件**:必须创建独立的 `FilterNode` 对象进行链式调用 4. **值比较**:等值条件直接传值,不需要 `FilterNode.eq()` 5. **LIKE 参数**:通常需要在参数中自行添加 `%` 通配符 --- ## 📚 参考代码位置 - `flux-api/src/main/java/cn/casehub/partner/PartnerFormService.java` - `flux-api/src/main/java/cn/casehub/partner/PartnerCustomerService.java` - `flux-api/src/main/java/cn/casehub/partner/PartnerVisitService.java` --- # Redkale JSON 使用要点 > 更新时间:2026-03-03 > 背景:速贷接口接入时错误使用 `@JsonProperty`(Jackson 注解),Redkale 不支持 --- ## ❌ 常见错误 ### 1. 使用 Jackson 注解 **错误写法**: ```java // ❌ 错误:Redkale 不支持 Jackson 注解 import com.fasterxml.jackson.annotation.JsonProperty; @JsonProperty("mobile_md5") private String mobileMd5; ``` **正确方案**:使用 Redkale 的 `@ConvertColumn(name = "xxx")` 进行字段重命名: ```java // ✅ 正确:使用 @ConvertColumn 重命名 import org.redkale.convert.ConvertColumn; @ConvertColumn(name = "mobile_md5") private String mobileMd5; // Java驼峰,JSON下划线 ``` --- ## ✅ JsonConvert 使用方式 ### 序列化(对象 → JSON) ```java // 方式1:实例方法 JsonConvert convert = JsonConvert.root(); String json = convert.convertTo(object); // 方式2:静态调用 String json = JsonConvert.root().convertTo(object); ``` ### 反序列化(JSON → 对象) ```java // 单个对象 User user = JsonConvert.root().convertFrom(User.class, json); // 泛型集合 List users = JsonConvert.root().convertFrom( new TypeToken>() {}.getType(), json ); // Map(用于解析不确定结构的JSON) Map map = JsonConvert.root().convertFrom(Map.class, json); ``` --- ## 📋 字段映射规则 | Java 字段名 | JSON 字段名 | 说明 | |------------|------------|------| | `mobileMd5` | `mobileMd5` | 默认:驼峰 → 驼峰 | | `mobile_md5` | `mobile_md5` | 默认:下划线 → 下划线 | | `mobileMd5` + `@ConvertColumn(name="mobile_md5")` | `mobile_md5` | ✅ 重命名 | | `mobileMd5` + `@ConvertColumn(ignore=true)` | - | 忽略字段 | **结论**:使用 `@ConvertColumn(name = "xxx")` 可实现字段重命名。 --- ## 🔧 跨命名风格转换方案 当第三方接口使用下划线,内部使用驼峰时: ### 方案1:@ConvertColumn + Utils.copy(推荐) ```java // 速贷请求Bean(Java驼峰,JSON下划线) public class SuDaiRequest { @ConvertColumn(name = "mobile_md5") private String mobileMd5; @ConvertColumn(name = "city_id") private String cityId; } // 内部Bean(驼峰) public class CollideBean { private String mobileMd5; private String cityId; } // 转换器 - 使用 Utils.copy public class Converter { public static CollideBean toBean(SuDaiRequest req) { return Utils.copy(new CollideBean(), req); // 一行搞定 } } ``` ### 方案2:手动映射(不推荐) ```java // 速贷请求Bean(下划线) public class SuDaiRequest { private String mobile_md5; private String city_id; } // 转换器 - 手动映射 public class Converter { public static CollideBean toBean(SuDaiRequest req) { CollideBean bean = new CollideBean(); bean.setMobileMd5(req.getMobile_md5()); // 手动映射 bean.setCityId(req.getCity_id()); return bean; } } ``` --- ## ⚠️ 注意事项 1. **使用 @ConvertColumn**:Redkale 的字段重命名注解,不是 Jackson 的 @JsonProperty 2. **@ConvertColumn 用法**: - `@ConvertColumn(name = "xxx")` - 重命名JSON字段 - `@ConvertColumn(ignore = true)` - 忽略字段 3. **配合 Utils.copy**:重命名后,Java字段名一致,可用 `Utils.copy` 简化转换