管理类软件通用高级查询组件(一)---升鲜宝生鲜配送供应链管理软件重构方案

管理类软件通用高级查询组件(一)---升鲜宝生鲜配送供应链管理软件重构方案

解决方案(Spring Boot + Vue3 + MyBatis-Plus 落地版)

|----------|------------------------------------------------------------|
| 适用系统 | 升鲜宝供应链管理系统 / 多门店收银系统 / WMS / OMS / PMS / 财务 / CRM |
| 适用对象 | 后端研发、前端研发、产品经理、测试、架构负责人 |
| 技术栈 | Spring Boot、MyBatis-Plus、MySQL 8.0、Redis、Vue3、Element Plus |
| 文档版本 | V1.0 |
| 生成日期 | 2025-03-24 |

文档摘要:

本文档将截图中类似"高级搜索"的查询框,抽象为升鲜宝系统级通用能力:前端通过字段配置动态渲染查询表单,后端通过字段白名单、操作符解析、排序白名单、数据权限和字段权限统一生成安全查询条件,并支持用户保存常用查询方案。方案可覆盖商品、订单、采购、库存、财务、CRM、供应商等多个业务域,避免每个页面重复开发查询条件。

目录

  1. 建设目标与设计原则

  2. 业务场景与组件定位

  3. 总体架构设计

  4. 前端高级查询组件设计

  5. 后端通用查询模型设计

  6. 数据库表结构与数据字典

  7. MyBatis-Plus 查询构建方案

  8. 权限、安全与防 SQL 注入设计

  9. 查询方案保存与默认条件

  10. 模块接入规范与示例

  11. 接口清单与请求响应示例

  12. 性能优化与缓存策略

  13. 测试验收清单

  14. 实施路线图

  15. 附录:DDL 与代码骨架

1. 建设目标与设计原则

升鲜宝系统中,商品、订单、库存、采购、销售、财务、CRM 等模块都存在复杂筛选需求。如果每个页面单独开发高级搜索弹窗,会产生字段重复、权限难统一、排序不可控、SQL 注入风险高、查询方案无法复用等问题。因此,本方案将高级查询抽象为平台级组件。

  • 前端统一:一个 AdvancedSearchDialog 组件支持 input、select、treeSelect、dateRange、numberRange、remoteSelect 等多种控件。
  • 后端统一:一个 QueryRequestDTO 接收查询条件、排序、分页和模块编码。
  • 安全统一:所有字段必须进入字段白名单,前端只传业务字段编码,不传数据库字段名。
  • 权限统一:查询条件与结果字段同时接入数据权限、字段权限、组织/门店权限。
  • 体验统一:支持用户保存"我的查询方案"、默认查询方案、一键重置和常用条件回显。

2. 业务场景与组件定位

|----------|----------------------------------|-----------------------------------|
| 业务模块 | 典型查询条件 | 接入价值 |
| 商品/PMS | 机构、门店、类别、品牌、SKU编码、SKU名称、条码、上下架状态 | 商品档案与 SKU 选择场景复用,减少订单、采购、库存页面重复开发 |
| 订单/OMS | 客户、业务员、订单状态、配送方式、下单日期、审核状态 | 统一订单列表、订单选择弹窗、出库生成订单查询 |
| 采购/PUR | 供应商、采购员、采购状态、到货日期、付款状态 | 采购订单、采购入库、供应商对账统一过滤 |
| 仓库/WMS | 仓库、库区、库位、批次、效期、库存状态 | 库存查询、拣货、盘点、批次追踪统一条件 |
| 门店/HWMS | 门店、门店库位、商品、批次、盘点状态 | 门店仓储式超市库存、POS 出库、线上核销复用 |
| 财务/FIN | 客户/供应商、账期、结算状态、金额区间、单据日期 | 客户对账、供应商对账、收付款流水统一筛选 |
| CRM | 客户等级、客户状态、业务人员、提醒日期、授信状态 | 客户池、跟进记录、账期提醒统一查询 |

3. 总体架构设计

通用高级查询组件由前端渲染层、查询配置中心、查询解析引擎、权限增强层、业务查询 Facade 五部分组成。

Vue3 页面

├─ 普通搜索区

├─ 高级搜索按钮

└─ AdvancedSearchDialog.vue

↓ 提交 QueryRequestDTO

Spring Boot API

├─ QueryFieldController 查询字段配置

├─ QuerySchemeController 查询方案保存

├─ QueryFacade 业务查询门面

├─ QueryConditionParser 条件解析

├─ QueryFieldWhitelist 字段白名单

├─ QueryOperatorHandler 操作符处理

├─ FieldPermissionEngine 字段权限过滤

└─ DataScopeEngine 数据权限增强

MyBatis-Plus / Custom SQL / Mapper

MySQL 8.0

|--------|-------------------------------------------|----------------------------|
| 层级 | 组件 | 职责 |
| 前端组件层 | AdvancedSearchDialog / QueryFieldRenderer | 根据配置渲染高级查询弹窗,收集查询条件并回显 |
| 配置中心层 | sys_query_field / sys_query_scheme | 维护模块字段、组件类型、操作符、排序、用户方案 |
| 解析引擎层 | QueryConditionParser / OperatorHandler | 把前端字段编码转换成安全 SQL 条件 |
| 权限增强层 | DataScopeEngine / FieldPermissionEngine | 补充组织、门店、角色、字段级权限 |
| 业务查询层 | 各模块 QueryFacade | 承接业务列表接口,组合分页、排序、统计与 VO 转换 |

4. 前端高级查询组件设计

4.1 组件组成

|--------------------------|----------|---------------------------------------------------------|
| 组件 | 用途 | 说明 |
| AdvancedSearchDialog.vue | 高级搜索弹窗容器 | 控制弹窗标题、宽度、列布局、确定/取消/重置按钮 |
| QueryFieldRenderer.vue | 字段渲染器 | 根据 componentType 渲染 Input、Select、TreeSelect、DateRange 等 |
| QuerySchemeManager.vue | 查询方案管理 | 保存、加载、删除、设为默认查询方案 |
| useAdvancedSearch.ts | 组合式状态管理 | 处理表单数据、条件转换、字段显隐、默认值 |
| queryFieldApi.ts | 字段配置 API | 拉取 moduleCode 对应字段配置 |

4.2 字段配置模型

export interface QueryFieldConfig {

fieldCode: string

fieldName: string

componentType: 'input' | 'select' | 'treeSelect' | 'dateRange' | 'numberRange' | 'remoteSelect'

dictType?: string

defaultOperator: 'eq' | 'like' | 'likeRight' | 'between' | 'in'

requiredFlag: boolean

visibleFlag: boolean

span: number

placeholder?: string

remoteApi?: string

defaultValue?: any

}

4.3 商品 SKU 高级查询示例

const skuAdvancedFields = [

{ fieldCode: 'orgId', fieldName: '机构', componentType: 'remoteSelect', defaultOperator: 'eq', span: 12 },

{ fieldCode: 'shopId', fieldName: '门店', componentType: 'remoteSelect', defaultOperator: 'eq', span: 12 },

{ fieldCode: 'deptCode', fieldName: '部门编码', componentType: 'remoteSelect', defaultOperator: 'eq', span: 12 },

{ fieldCode: 'categoryId', fieldName: '类别编码', componentType: 'treeSelect', defaultOperator: 'eq', span: 12 },

{ fieldCode: 'skuCode', fieldName: 'SKU编码', componentType: 'input', defaultOperator: 'likeRight', span: 12 },

{ fieldCode: 'skuName', fieldName: 'SKU名称', componentType: 'input', defaultOperator: 'like', span: 12 },

{ fieldCode: 'barcode', fieldName: '国际条码', componentType: 'input', defaultOperator: 'eq', span: 12 },

{ fieldCode: 'processStatus', fieldName: '处理状态', componentType: 'select', dictType: 'process_status', defaultOperator: 'eq', span: 12 },

{ fieldCode: 'deliveryMode', fieldName: '配送方式', componentType: 'select', dictType: 'delivery_mode', defaultOperator: 'eq', span: 12 }

]

5. 后端通用查询模型设计

5.1 请求 DTO

@Data

public class QueryRequestDTO {

private String moduleCode;

private Integer pageNo = 1;

private Integer pageSize = 20;

private List<QueryConditionDTO> conditions;

private List<QueryOrderDTO> orders;

private Boolean includeSummary = false;

}

@Data

public class QueryConditionDTO {

private String field;

private String operator;

private Object value;

private Object valueEnd;

}

@Data

public class QueryOrderDTO {

private String field;

private String direction;

}

5.2 操作符枚举

|----------------|-----------|---------------------------------|-------------------------------|
| 操作符 | 含义 | SQL 语义 | 适用控件 |
| eq | 等于 | column = ? | select / input / remoteSelect |
| ne | 不等于 | column <> ? | select / input |
| like | 包含 | column LIKE concat('%', ?, '%') | input |
| likeLeft | 左模糊 | column LIKE concat('%', ?) | input |
| likeRight | 右模糊 | column LIKE concat(?, '%') | input |
| gt / ge | 大于 / 大于等于 | column > ? / column >= ? | number / date |
| lt / le | 小于 / 小于等于 | column < ? / column <= ? | number / date |
| between | 区间 | column BETWEEN ? AND ? | dateRange / numberRange |
| in | 包含任一 | column IN (...) | multiSelect |
| null / notNull | 为空 / 不为空 | IS NULL / IS NOT NULL | checkbox / special |

6. 数据库表结构与数据字典

数据库层采用"字段配置表 + 查询方案表 + 查询日志表"的三表模型。字段配置表解决不同模块可查询字段、字段映射、控件类型、操作符和排序白名单;查询方案表解决用户自定义常用条件;查询日志表用于审计与慢查询分析。

6.1 sys_query_field:通用查询字段配置表

|-------------------|--------------|--------|------------------------------------------------------|
| 字段名 | 类型 | 必填 | 说明 |
| id | BIGINT | 是 | 主键 ID |
| module_code | VARCHAR(64) | 是 | 模块编码,如 pms_sku、oms_order |
| field_code | VARCHAR(64) | 是 | 前端字段编码,如 skuName |
| field_name | VARCHAR(100) | 是 | 字段显示名称 |
| table_alias | VARCHAR(32) | 否 | SQL 表别名,如 g、o、c |
| column_name | VARCHAR(64) | 是 | 真实数据库字段名,如 sku_name |
| java_type | VARCHAR(32) | 是 | Java 类型 String、Long、Integer、BigDecimal、LocalDateTime |
| component_type | VARCHAR(32) | 是 | 控件类型 input、select、treeSelect、dateRange |
| dict_type | VARCHAR(64) | 否 | 字典类型 |
| support_operators | VARCHAR(255) | 是 | 支持操作符列表 |
| default_operator | VARCHAR(32) | 是 | 默认操作符 |
| sortable_flag | TINYINT | 是 | 是否允许排序 |
| display_order | INT | 是 | 显示顺序 |
| required_flag | TINYINT | 是 | 是否必填 |
| visible_flag | TINYINT | 是 | 是否显示 |
| enabled_flag | TINYINT | 是 | 是否启用 |
| remark | VARCHAR(500) | 否 | 备注 |
| create_time | DATETIME | 是 | 创建时间 |
| update_time | DATETIME | 是 | 更新时间 |

CREATE TABLE sys_query_field (

id BIGINT NOT NULL PRIMARY KEY COMMENT '主键ID',

module_code VARCHAR(64) NOT NULL COMMENT '模块编码',

field_code VARCHAR(64) NOT NULL COMMENT '前端字段编码',

field_name VARCHAR(100) NOT NULL COMMENT '字段名称',

table_alias VARCHAR(32) DEFAULT NULL COMMENT 'SQL表别名',

column_name VARCHAR(64) NOT NULL COMMENT '数据库字段名',

java_type VARCHAR(32) NOT NULL COMMENT 'Java类型',

component_type VARCHAR(32) NOT NULL COMMENT '组件类型',

dict_type VARCHAR(64) DEFAULT NULL COMMENT '字典类型',

support_operators VARCHAR(255) NOT NULL COMMENT '支持操作符',

default_operator VARCHAR(32) NOT NULL COMMENT '默认操作符',

sortable_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否允许排序:0否,1是',

display_order INT NOT NULL DEFAULT 0 COMMENT '显示顺序',

required_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否必填:0否,1是',

visible_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否显示:0否,1是',

enabled_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用:0否,1是',

remark VARCHAR(500) DEFAULT NULL COMMENT '备注',

create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

UNIQUE KEY uk_module_field (module_code, field_code),

KEY idx_module_enabled (module_code, enabled_flag, display_order)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通用查询字段配置表';

6.2 sys_query_scheme:用户查询方案表

CREATE TABLE sys_query_scheme (

id BIGINT NOT NULL PRIMARY KEY COMMENT '主键ID',

user_id BIGINT NOT NULL COMMENT '用户ID',

module_code VARCHAR(64) NOT NULL COMMENT '模块编码',

scheme_name VARCHAR(100) NOT NULL COMMENT '查询方案名称',

condition_json JSON NOT NULL COMMENT '查询条件JSON',

default_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认:0否,1是',

enabled_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用:0否,1是',

create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

UNIQUE KEY uk_user_module_name (user_id, module_code, scheme_name),

KEY idx_user_module_default (user_id, module_code, default_flag)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户查询方案表';

6.3 sys_query_log:查询审计日志表

CREATE TABLE sys_query_log (

id BIGINT NOT NULL PRIMARY KEY COMMENT '主键ID',

module_code VARCHAR(64) NOT NULL COMMENT '模块编码',

user_id BIGINT NOT NULL COMMENT '用户ID',

request_json JSON NOT NULL COMMENT '请求条件JSON',

cost_ms INT NOT NULL DEFAULT 0 COMMENT '耗时毫秒',

result_count INT NOT NULL DEFAULT 0 COMMENT '结果数量',

success_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否成功:0否,1是',

error_message VARCHAR(1000) DEFAULT NULL COMMENT '异常信息',

trace_id VARCHAR(64) DEFAULT NULL COMMENT '链路ID',

create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

KEY idx_module_time (module_code, create_time),

KEY idx_user_time (user_id, create_time),

KEY idx_trace_id (trace_id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='通用查询日志表';

7. MyBatis-Plus 查询构建方案

7.1 核心流程

  1. 校验 moduleCode 是否存在并启用。

  2. 加载 sys_query_field 字段白名单,按 fieldCode 建立 Map。

  3. 过滤空值条件,校验字段是否可查询。

  4. 校验 operator 是否在 support_operators 中。

  5. 将 fieldCode 映射为 tableAlias.columnName。

  6. 按 javaType 做值类型转换。

  7. 通过 OperatorHandler 写入 LambdaQueryWrapper 或 Custom SQL 参数。

  8. 追加数据权限条件、组织/门店条件。

  9. 校验排序字段白名单,追加 order by。

  10. 执行分页查询并记录 sys_query_log。

7.2 查询解析器代码骨架

@Service

public class QueryConditionParser {

@Resource

private QueryFieldService queryFieldService;

@Resource

private DataScopeEngine dataScopeEngine;

public QueryBuildResult parse(QueryRequestDTO request, LoginUser loginUser) {

Map<String, QueryFieldConfig> fieldMap = queryFieldService.getFieldMap(request.getModuleCode());

QueryBuildResult result = new QueryBuildResult();

for (QueryConditionDTO condition : request.getConditions()) {

QueryFieldConfig field = fieldMap.get(condition.getField());

if (field == null) {

throw new SxbException("非法查询字段:" + condition.getField());

}

if (!field.supportOperator(condition.getOperator())) {

throw new SxbException("字段不支持该查询操作符");

}

OperatorHandler handler = OperatorHandlerFactory.get(condition.getOperator());

handler.apply(result, field, condition);

}

dataScopeEngine.apply(request.getModuleCode(), result, loginUser);

return result;

}

}

8. 权限、安全与防 SQL 注入设计

|---------|-----------------------------|----------------------------------------------|
| 风险点 | 错误做法 | 正确做法 |
| 字段注入 | 前端直接传 sku_name 或 g.sku_name | 前端只传 skuName,后端白名单映射 |
| 操作符注入 | 前端传自定义 SQL 片段 | operator 必须是系统枚举,并且字段支持该操作符 |
| 排序注入 | orderBy 直接拼接请求值 | 排序字段必须 sortableFlag=1,direction 只允许 asc/desc |
| 越权查询 | 前端传 orgId/shopId 任意查 | 后端 DataScopeEngine 强制追加当前用户可访问组织/门店 |
| 字段越权 | 返回所有字段 | FieldPermissionEngine 对 VO 字段做脱敏或移除 |
| 慢查询 | 复杂 like + 大分页 | 限制 pageSize、建立索引、记录查询日志、启用缓存 |

8.1 字段白名单规则

  • 禁止前端传数据库列名。
  • 禁止前端传 SQL 片段。
  • 禁止未配置字段参与查询或排序。
  • 禁止未启用字段被展示或参与查询。
  • 跨表字段必须配置 table_alias,避免 SQL 歧义。

8.2 数据权限接入

通用查询组件必须与升鲜宝数据权限体系打通。对于有组织、门店、仓库、客户、供应商归属的数据,业务查询 Facade 不应该依赖前端传入权限条件,而应由后端按当前登录用户自动追加。

public interface DataScopeEngine {

void apply(String moduleCode, QueryBuildResult result, LoginUser loginUser);

}

// 示例:商品 SKU 查询自动追加组织和门店权限

// g.org_id IN (当前用户可访问机构)

// g.shop_id IN (当前用户可访问门店)

9. 查询方案保存与默认条件

查询方案用于解决用户经常重复设置同一组高级查询条件的问题。每个用户、每个模块可以保存多个查询方案,并允许设置一个默认方案。

|--------|----------------------------------------------------|
| 功能 | 说明 |
| 保存当前条件 | 将当前 conditions、orders、pageSize 等保存为 condition_json |
| 设为默认 | 用户进入模块页面时自动加载默认查询方案 |
| 共享方案 | 后续可扩展为角色级或公司级共享查询方案 |
| 重置条件 | 恢复系统默认条件,不影响已保存方案 |
| 删除方案 | 删除个人方案,不影响模块字段配置 |

{

"pageNo": 1,

"pageSize": 20,

"conditions": [

{ "field": "shopId", "operator": "eq", "value": 10001 },

{ "field": "skuName", "operator": "like", "value": "龙虾" },

{ "field": "processStatus", "operator": "eq", "value": 0 }

],

"orders": [

{ "field": "createTime", "direction": "desc" }

]

}

10. 模块接入规范与示例

|--------|------------------------|------------------------|
| 模块 | moduleCode | 建议接入页面 |
| 商品档案 | pms_goods | 商品列表、商品选择弹窗、商品导入校验 |
| SKU 档案 | pms_sku | SKU 列表、订单选品、采购选品、出入库选品 |
| 销售订单 | oms_order | 订单列表、订单审核、销售出库生成 |
| 采购订单 | pur_order | 采购列表、采购入库、供应商对账 |
| 库存查询 | wms_inventory | 实时库存、批次库存、效期预警 |
| 门店库存 | hwms_inventory | 门店库存、POS 出库、线上核销 |
| 客户档案 | crm_customer | 客户列表、账期提醒、授信查询 |
| 供应商档案 | sup_supplier | 供应商列表、采购对账、结算状态 |
| 客户对账 | fin_customer_statement | 客户账单、应收、收款流水 |
| 供应商对账 | fin_supplier_statement | 供应商账单、应付、付款流水 |

10.1 pms_sku 字段初始化 SQL 示例

INSERT INTO sys_query_field

(id, module_code, field_code, field_name, table_alias, column_name, java_type, component_type, dict_type, support_operators, default_operator, sortable_flag, display_order)

VALUES

(1001, 'pms_sku', 'orgId', '机构', 'g', 'org_id', 'Long', 'remoteSelect', NULL, 'eq,in', 'eq', 0, 10),

(1002, 'pms_sku', 'shopId', '门店', 'g', 'shop_id', 'Long', 'remoteSelect', NULL, 'eq,in', 'eq', 0, 20),

(1003, 'pms_sku', 'categoryId', '类别编码', 'g', 'category_id', 'Long', 'treeSelect', NULL, 'eq,in', 'eq', 0, 30),

(1004, 'pms_sku', 'skuCode', 'SKU编码', 's', 'sku_code', 'String', 'input', NULL, 'eq,likeRight,in', 'likeRight', 1, 40),

(1005, 'pms_sku', 'skuName', 'SKU名称', 's', 'sku_name', 'String', 'input', NULL, 'eq,like,likeRight', 'like', 1, 50),

(1006, 'pms_sku', 'barcode', '国际条码', 's', 'barcode', 'String', 'input', NULL, 'eq,likeRight', 'eq', 1, 60),

(1007, 'pms_sku', 'processStatus', '处理状态', 's', 'process_status', 'Integer', 'select', 'process_status', 'eq,in', 'eq', 0, 70),

(1008, 'pms_sku', 'deliveryMode', '配送方式', 's', 'delivery_mode', 'Integer', 'select', 'delivery_mode', 'eq,in', 'eq', 0, 80),

(1009, 'pms_sku', 'createTime', '创建时间', 's', 'create_time', 'LocalDateTime', 'dateRange', NULL, 'between,ge,le', 'between', 1, 90);

11. 接口清单与请求响应示例

|---------------------------------|--------|-----------------------------|
| 接口 | 方法 | 说明 |
| /api/query/fields/{moduleCode} | GET | 获取指定模块的高级查询字段配置 |
| /api/query/schemes/{moduleCode} | GET | 获取当前用户在指定模块下的查询方案 |
| /api/query/schemes | POST | 保存查询方案 |
| /api/query/schemes/{id} | PUT | 修改查询方案 |
| /api/query/schemes/{id} | DELETE | 删除查询方案 |
| /api/pms/sku/page | POST | 业务模块分页查询,接收 QueryRequestDTO |

11.1 获取查询字段响应示例

{

"code": 0,

"message": "success",

"data": [

{ "fieldCode": "orgId", "fieldName": "机构", "componentType": "remoteSelect", "defaultOperator": "eq", "span": 12 },

{ "fieldCode": "shopId", "fieldName": "门店", "componentType": "remoteSelect", "defaultOperator": "eq", "span": 12 },

{ "fieldCode": "skuName", "fieldName": "SKU名称", "componentType": "input", "defaultOperator": "like", "span": 12 }

]

}

11.2 分页查询请求示例

{

"moduleCode": "pms_sku",

"pageNo": 1,

"pageSize": 20,

"conditions": [

{ "field": "shopId", "operator": "eq", "value": 2001 },

{ "field": "skuName", "operator": "like", "value": "波士顿龙虾" },

{ "field": "processStatus", "operator": "eq", "value": 0 }

],

"orders": [

{ "field": "createTime", "direction": "desc" }

]

}

12. 性能优化与缓存策略

|---------|-----------------------------------------------------------------|
| 优化点 | 方案 |
| 字段配置缓存 | 按 moduleCode 缓存 sys_query_field,可使用 Caffeine 本地缓存 + Redis 分布式缓存 |
| 字典缓存 | DictSelect 所需字典按 dictType + langCode 缓存,避免每次打开弹窗查询数据库 |
| 远程选择器 | 机构、门店、客户、供应商等 remoteSelect 支持关键字搜索和分页 |
| 索引设计 | 高频条件字段建立组合索引,如 shop_id + sku_code、customer_id + bill_date |
| 分页限制 | pageSize 默认 20,最大建议 200;大数据导出走异步导出任务 |
| 慢查询日志 | sys_query_log 记录 costMs,超过阈值写入告警或运维日志 |
| 条件裁剪 | 空值、空数组、空字符串不进入 SQL 条件 |

13. 测试验收清单

|----------|------------------------------------------------------|
| 测试类别 | 验收点 |
| 功能测试 | 字段能正确展示、回显、重置、提交,查询结果符合预期 |
| 权限测试 | 无权限组织、门店、仓库、客户数据不可被查询 |
| 字段安全测试 | 传入未配置字段、数据库字段名、非法 operator 必须报错 |
| 排序安全测试 | 未配置 sortableFlag 的字段不允许排序 |
| 兼容测试 | input、select、treeSelect、dateRange、numberRange 均可正常工作 |
| 性能测试 | 常用查询 1 秒内返回;复杂查询有慢查询记录 |
| 回归测试 | 接入通用组件后,原有列表查询和分页行为不被破坏 |
| 审计测试 | 查询失败、慢查询、越权尝试有日志记录 |

14. 实施路线图

|-----------|--------|-----------------------------------------------------|
| 阶段 | 周期 | 交付内容 |
| 第一阶段:基础组件 | 1 周 | AdvancedSearchDialog、字段配置接口、QueryRequestDTO、字段白名单校验 |
| 第二阶段:业务试点 | 1 周 | 先接入 pms_sku、oms_order、wms_inventory 三个高频模块 |
| 第三阶段:查询方案 | 1 周 | 实现用户查询方案保存、默认方案、删除、回显 |
| 第四阶段:权限增强 | 1-2 周 | 接入 DataScopeEngine、FieldPermissionEngine、查询审计日志 |
| 第五阶段:全域推广 | 2-4 周 | 推广到采购、供应商、CRM、财务、门店库存等模块 |
| 第六阶段:高级能力 | 持续迭代 | 共享查询方案、复杂条件组 OR/AND、异步导出联动、查询分析报表 |

15. 附录:Controller / Service 代码骨架

@RestController

@RequestMapping("/api/query/fields")

public class QueryFieldController {

@Resource

private QueryFieldService queryFieldService;

@GetMapping("/{moduleCode}")

public List<QueryFieldVO> listByModule(@PathVariable String moduleCode) {

return queryFieldService.listEnabledFields(moduleCode);

}

}

@RestController

@RequestMapping("/api/query/schemes")

public class QuerySchemeController {

@Resource

private QuerySchemeService querySchemeService;

@GetMapping("/{moduleCode}")

public List<QuerySchemeVO> list(@PathVariable String moduleCode) {

return querySchemeService.listMySchemes(moduleCode);

}

@PostMapping

public Long save(@RequestBody QuerySchemeSaveDTO dto) {

return querySchemeService.saveScheme(dto);

}

}

@RestController

@RequestMapping("/api/pms/sku")

public class PmsSkuController {

@Resource

private PmsSkuQueryFacade pmsSkuQueryFacade;

@PostMapping("/page")

public PageResult<PmsSkuVO> page(@RequestBody QueryRequestDTO request) {

request.setModuleCode("pms_sku");

return pmsSkuQueryFacade.page(request);

}

}

16. 最终落地建议

  • 不要把高级查询只做成单个页面功能,应作为升鲜宝平台级基础组件建设。
  • 第一批建议接入 pms_sku、oms_order、wms_inventory,因为这三个模块最能验证商品、订单、库存三类典型场景。
  • 后端必须坚持"字段白名单 + 操作符枚举 + 排序白名单",禁止任何前端 SQL 片段进入后端。
  • 查询组件应与数据权限、字段权限、操作日志统一接入,避免后续补权限成本过高。
  • 后续可继续扩展为"通用列表中心":查询条件、列表列配置、导入导出方案、打印模板一起配置化。
相关推荐
工业甲酰苯胺3 小时前
Tomcat的事件监听机制:观察者模式
java·观察者模式·tomcat
QC班长10 小时前
Maven公司私库配置踩坑点
java·服务器·maven·intellij-idea
Makoto_Kimur10 小时前
java开发面试-AI Coding速成
java·开发语言
wuqingshun31415910 小时前
说说mybatis的缓存机制
java·缓存·mybatis
空中海11 小时前
Kubernetes 生产实践、可观测性与扩展入门
java·贪心算法·kubernetes
Devin~Y11 小时前
大厂Java面试实录:Spring Boot/Cloud、Kafka、Redis、K8s 与 Spring AI(RAG/Agent)三轮连环问
java·spring boot·redis·mysql·spring cloud·kafka·kubernetes
bLEd RING11 小时前
SpringBoot3.3.0集成Knife4j4.5.0实战
java
小松加哲12 小时前
Spring MVC 核心原理全解析
java·spring·mvc
Ulyanov12 小时前
《PySide6 GUI开发指南:QML核心与实践》 第二篇:QML语法精要——构建声明式UI的基础
java·开发语言·javascript·python·ui·gui·雷达电子对抗系统仿真