Files
workpod/dev-envs/flux/docs/Redkale使用易错点.md
T

383 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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<PartnerFormRecord> 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<Sheet<PartnerFormRecord>> 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<PartnerFormRecord> sheet = dataSource.querySheet(PartnerFormRecord.class, flipper, node);
return render(sheet);
}
```
### PartnerCustomerService.java
```java
@RestMapping(name = "list", comment = "分页查询客户列表")
public RetResult<Sheet<PartnerCustomer>> 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<PartnerCustomer> 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<User> users = JsonConvert.root().convertFrom(
new TypeToken<List<User>>() {}.getType(),
json
);
// Map(用于解析不确定结构的JSON)
Map<String, Object> 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
// 速贷请求BeanJava驼峰,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` 简化转换