基于 主表 + JSON 自定义字段 的条件查询完整设计(若依 SpringBoot 最佳实践)
你现在的核心问题:
自定义字段存在 JSON 里,如何像普通字段一样支持:等于、大于、小于、区间、模糊、下拉筛选?
生产可用、高性能、兼容若依分页、支持多厂家、无侵入 的完整方案。
一、核心方案:MySQL JSON 函数查询(官方标准)
MySQL 5.7+/8.0+ 原生支持 JSON 字段条件查询,性能极高,支持索引,不用改表。
通用 JSON 查询语法(直接用)
假设 JSON 字段:custom_field_json
json
{"supplier":"A厂","checkResult":"合格","inspectTime":"2025-12-25","qty":100}
1. 等值查询
sql
AND custom_field_json->>'$.supplier' = 'A厂'
2. 数字大于/小于/区间
sql
AND custom_field_json->>'$.qty' > 100
AND custom_field_json->>'$.qty' BETWEEN 50 AND 200
3. 日期区间
sql
AND custom_field_json->>'$.inspectTime' >= '2025-01-01'
AND custom_field_json->>'$.inspectTime' <= '2025-12-31'
4. 模糊查询
sql
AND custom_field_json->>'$.supplier' LIKE '%A厂%'
5. 不为空
sql
AND custom_field_json->>'$.supplier' IS NOT NULL
二、后端架构设计(若依风格)
目标
前端传入:
js
customParams: {
supplier: "A厂",
qtyMin: 50,
qtyMax: 200,
inspectTimeStart: "2025-01-01",
inspectTimeEnd: "2025-12-31"
}
后端自动拼接 JSON 查询条件 ,兼容若依 startPage() 分页。
三、完整实现代码(直接复制可用)
1. 给 DTO / 实体增加查询字段
MesProductionOrder.java 增加查询专用字段:
java
// 自定义字段查询条件(非数据库字段)
@TableField(exist = false)
private Map<String, Object> customParams;
2. 构造 XML 动态 SQL(核心!)
MesProductionOrderMapper.xml
xml
<select id="selectCustomOrderList" resultType="com.ruoyi.mes.domain.MesProductionOrder">
SELECT * FROM mes_production_order
WHERE del_flag = '0'
<if test="orderNo != null and orderNo != ''">
AND order_no = #{orderNo}
</if>
<!-- ====================== JSON 自定义字段查询 ====================== -->
<if test="customParams != null">
<!-- 文本类型 = -->
<if test="customParams.supplier != null and customParams.supplier != ''">
AND custom_field_json->>'$.supplier' = #{customParams.supplier}
</if>
<!-- 数字区间 -->
<if test="customParams.qtyMin != null">
AND custom_field_json->>'$.qty' >= #{customParams.qtyMin}
</if>
<if test="customParams.qtyMax != null">
AND custom_field_json->>'$.qty' <= #{customParams.qtyMax}
</if>
<!-- 日期区间 -->
<if test="customParams.inspectTimeStart != null">
AND custom_field_json->>'$.inspectTime' >= #{customParams.inspectTimeStart}
</if>
<if test="customParams.inspectTimeEnd != null">
AND custom_field_json->>'$.inspectTime' <= #{customParams.inspectTimeEnd}
</if>
<!-- 模糊查询 -->
<if test="customParams.likeSupplier != null and customParams.likeSupplier != ''">
AND custom_field_json->>'$.supplier' LIKE concat('%', #{customParams.likeSupplier}, '%')
</if>
</if>
</select>
3. Mapper
java
List<MesProductionOrder> selectCustomOrderList(MesProductionOrder order);
4. Service
java
public List<MesProductionOrder> selectList(MesProductionOrder order) {
return baseMapper.selectCustomOrderList(order);
}
5. Controller(若依标准写法)
java
@GetMapping("/list")
public TableDataInfo list(MesProductionOrder order) {
startPage();
List<MesProductionOrder> list = service.selectList(order);
return getDataTable(list);
}
四、动态字段查询(真正的自定义字段任意筛选)
上面是固定字段,但你要的是:用户配置什么字段,就能按什么字段查。
终极方案:动态拼接 JSON SQL(生产级)
后端工具类:生成自定义查询条件
java
public class CustomFieldSqlBuilder {
/**
* 动态构建自定义字段查询SQL
*/
public static String buildJsonSql(Map<String, Object> params) {
if (params == null || params.isEmpty()) return "";
StringBuilder sql = new StringBuilder();
for (Map.Entry<String, Object> entry : params.entrySet()) {
String key = entry.getKey();
Object val = entry.getValue();
if (val == null || StringUtils.isEmpty(val.toString())) continue;
// 规则:
// xxx -> 等值
// xxx_min -> 大于等于
// xxx_max -> 小于等于
// xxx_like -> 模糊
if (key.endsWith("_min")) {
String field = key.replace("_min", "");
sql.append(" AND custom_field_json->>'$.").append(field).append("' >= #{customParams.").append(key).append("}");
} else if (key.endsWith("_max")) {
String field = key.replace("_max", "");
sql.append(" AND custom_field_json->>'$.").append(field).append("' <= #{customParams.").append(key).append("}");
} else if (key.endsWith("_like")) {
String field = key.replace("_like", "");
sql.append(" AND custom_field_json->>'$.").append(field).append("' LIKE concat('%', #{customParams.").append(key).append("}, '%')");
} else {
sql.append(" AND custom_field_json->>'$.").append(key).append("' = #{customParams.").append(key).append("}");
}
}
return sql.toString();
}
}
XML 使用动态 SQL
xml
<select id="selectList" resultType="MesProductionOrder">
SELECT * FROM mes_production_order
WHERE del_flag = '0'
${customSql}
</select>
Service 传入
java
String sql = CustomFieldSqlBuilder.buildJsonSql(order.getCustomParams());
order.setCustomSql(sql);
return mapper.selectList(order);
✅ 效果:前端传任意自定义字段,后端自动生成查询条件
五、性能优化(千万级不卡顿)
给 JSON 字段建索引
sql
-- 等值查询索引
CREATE INDEX idx_json_supplier ON mes_production_order ((custom_field_json->>'$.supplier'));
-- 数字/日期索引
CREATE INDEX idx_json_qty ON mes_production_order ((custom_field_json->>'$.qty'));
CREATE INDEX idx_json_time ON mes_production_order ((custom_field_json->>'$.inspectTime'));
加索引后,JSON 查询速度 = 普通字段速度
六、前端对接格式
js
queryParams: {
orderNo: "MO2025001",
// 自定义字段查询
customParams: {
supplier: "A厂",
qtyMin: 50,
qtyMax: 200,
inspectTimeStart: "2025-01-01",
inspectTimeEnd: "2025-12-31",
supplierLike: "A厂"
}
}
七、总结(最精简核心)
自定义字段条件查询 = 3 步
- 前端 传入
customParams动态条件 - 后端 自动拼接
JSON->>'$.字段'查询语句 - MySQL执行,支持索引、分页、排序、联表、权限
无大表、无联表、高性能、可动态扩展、适配多厂家