本文记录一个真实的业务场景:列表页需要支持多状态组合筛选(如“进行中”合并两种关联状态),如何在不破坏现有API的前提下,优雅地实现前后端联调。

一、问题背景

1.1 原始需求

在前端应用的列表功能中,列表页需要按以下规则展示:

Tab分类

包含状态

说明

正在进行

状态1(2) + 状态2(3)

合并两种进行中的关联状态

历史数据

状态3(4)

仅展示已结束的相关数据

同时,列表项按钮展示逻辑如下:

  • 状态1:不显示操作按钮

  • 状态2 + 未操作:显示“去操作”按钮

  • 状态2 + 已操作:显示“查看详情”按钮

1.2 原有实现的问题

原有的API设计只支持单状态查询:

// 原查询参数
public class ListQueryForm {
private Integer status; // 只能传单个状态值
}

AND data.status = #{query.status}

这导致前端无法用一个请求获取“状态1+状态2”的合并列表,只能采用以下两种不合理方式:

  1. 发两次请求分别查询,前端合并 —— 分页逻辑复杂,易出现数据错乱

  2. 查询全部状态,前端过滤 —— 数据量大时性能差,浪费带宽

二、解决方案设计

2.1 核心思路

新增 statusList 参数支持多状态IN查询,同时保留原 status 参数确保向后兼容。

优先级:statusList > status

  • 如果传了 statusList,使用 IN 查询
  • 如果只传 status,保持原有逻辑
  • 两者都不传,不加状态筛选条件

2.2 方案优势

特性

说明

向后兼容

旧的调用方式继续生效,无需修改已有代码和相关依赖

灵活扩展

支持任意状态组合,适应未来业务需求变化

单次请求

避免多次请求的复杂性和性能损耗,提升接口响应效率

分页友好

数据库层面完成筛选,分页逻辑正确,无数据漏查、重复问题

三、后端实现

3.1 扩展查询参数

// ListQueryForm.java
public class ListQueryForm extends PageParam {

/** 单状态筛选(保留,向后兼容) */
private Integer status;

/** 多状态筛选(新增,优先级更高) */
private List<Integer> statusList;

// getter/setter...

}

3.2 MyBatis动态SQL

SELECT data.id, data.title, data.status, ... FROM t_list_data data data.deleted_flag = 0
    <!-- 多状态筛选(优先级高) -->
    <if test="query.statusList != null and query.statusList.size() > 0">
        AND data.status IN
        <foreach collection="query.statusList" item="s"
                 open="(" separator="," close=")">
            #{s}
        </foreach>
    </if>

    <!-- 单状态筛选(向后兼容,仅在statusList为空时生效) -->
    <if test="(query.statusList == null or query.statusList.size() == 0)
              and query.status != null">
        AND data.status = #{query.status}
    </if>

    <!-- 其他条件... -->
</where>
ORDER BY data.create_time DESC

关键点解析:

  1. 条件优先级:通过嵌套的 <if> 判断,确保 statusList 优先于 status,避免逻辑冲突

  2. 空集合处理:statusList.size() > 0 避免生成 IN () 的无效SQL,防止数据库报错

  3. foreach用法:open/separator/close 自动生成正确的 IN (2, 3) 语法,无需手动拼接

3.3 生成的SQL示例

– 前端传入 statusList = [2, 3]
SELECT … FROM t_list_data data
WHERE data.deleted_flag = 0
AND data.status IN (2, 3)
ORDER BY data.create_time DESC
LIMIT 0, 10;

– 旧接口传入 status = 4(向后兼容)
SELECT … FROM t_list_data data
WHERE data.deleted_flag = 0
AND data.status = 4
ORDER BY data.create_time DESC
LIMIT 0, 10;

四、前端适配

4.1 Tab与API参数映射

// list.vue
const TAB_CONFIG = {
ongoing: {
label: ‘正在进行’,
statusList: [2, 3] // 状态1 + 状态2
},
history: {
label: ‘历史数据’,
statusList: [4] // 状态3
}
}

const currentTab = ref(‘ongoing’)

// 获取列表数据
async function fetchListData(page = 1) {
const params = {
page,
pageSize: 10,
statusList: TAB_CONFIG[currentTab.value].statusList
}
const res = await api.getListData(params)
// …
}

4.2 按钮展示逻辑

{{ item.title }} {{ getStatusText(item.status) }}
<!-- 按钮区域:状态1不显示 -->
<view class="list-actions" v-if="item.status !== 2">
  <!-- 状态2:根据是否已操作显示不同按钮 -->
  <template v-if="item.status === 3">
    <button v-if="!item.hasOperated" type="primary" @click="goOperate(item)">
      去操作
    </button>
    <button v-else type="default" @click="viewDetail(item)">
      查看详情
    </button>
  </template>

  <!-- 状态3:只能查看 -->
  <button v-if="item.status === 4" type="default" @click="viewDetail(item)">
    查看结果
  </button>
</view>

4.3 状态与按钮对照表

状态

status值

hasOperated

显示按钮

状态1

2

无按钮

状态2

3

false

去操作

状态2

3

true

查看详情

状态3

4

查看结果

五、经验总结

5.1 API扩展的兼容性原则

✅ 新增参数,保留旧参数
✅ 新参数优先,旧参数兜底
✅ 不改变原有参数的语义
❌ 直接修改或删除旧参数
❌ 改变旧参数的默认行为

5.2 MyBatis多状态查询的通用模式

AND table.status IN #{item} AND table.status = #{query.status}

5.3 前端状态管理建议

  1. 配置化Tab映射:将Tab与状态的对应关系抽取为配置,集中管理,便于后续修改和维护

  2. 统一状态常量:前后端共用状态码定义,避免魔法数字,减少联调误差

  3. 按钮逻辑与列表解耦:按钮显示规则独立封装为方法或组件,提高可测试性和复用性

六、扩展思考

6.1 如果状态更多怎么办?

当状态组合变得复杂时,可以考虑通过枚举统一管理状态组:

// 定义状态组枚举
public enum DataStatusGroup {
ONGOING(Arrays.asList(2, 3)), // 正在进行
HISTORY(Arrays.asList(4)), // 历史
ALL(Arrays.asList(2, 3, 4)); // 全部

private final List<Integer> statusList;
// ...

}

前端只需传入 statusGroup: "ONGOING",后端自动展开为对应的状态列表,降低前后端联调成本。

6.2 性能优化

对于状态字段,建议做以下优化,提升查询效率:

  1. 添加数据库索引:CREATE INDEX idx_status ON t_list_data(status),加速状态筛选

  2. 如果状态值固定且数量较少,IN查询性能通常优于OR查询,更适合多状态组合场景


本文基于实际开发经验整理,聚焦多状态筛选的前后端联调技巧与兼容性设计,希望对遇到类似场景的开发者有所帮助。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐