升鲜宝通用自定义列导入导出功能的通用设计方案(一)---升鲜宝生鲜配送供应链管理系统源代码

** 升鲜宝通用自定义列导入导出功能的通用设计方案(一)---升鲜宝生鲜配送供应链管理系统源代码**

目的:

一份业务系统“自定义列导入导出功能”的通用设计方案。这套方案不是只针对某一个单据,而是按平台级能力来设计,适合订单、商品、客户、库存、财务、CRM、WMS、门店、商城等大多数业务模块复用。

一、这个功能到底要解决什么问题

很多业务系统都会遇到这些问题:

不同客户/部门需要的导出列不一样
有人要“客户名称 + 联系电话 + 地址”
有人要“客户编码 + 账期 + 业务员”
有人要“商品名称 + 规格 + 单位 + 库存”
导入模板不统一
A客户 Excel 列名叫“商品”
B客户列名叫“品名”
C客户列名叫“货品名称”
实际都对应系统里的 goods_name
字段校验复杂
必填
长度限制
数据类型
日期格式
枚举值
唯一性
引用合法性
业务规则校验
不同业务对象导入导出的规则不同
商品导入:可能允许自动新增品牌/单位/分类
订单导入:可能需要主从表拆分
库存导入:可能只允许初期数据导入
财务导入:可能要强校验借贷平衡

所以这个模块的本质不是“做一个 Excel 上传/下载按钮”,而是:

做一个可配置、可复用、可扩展、可审计的导入导出平台能力。

二、设计目标

建议按下面 8 个目标来设计:

1)统一

所有业务模块都走同一套导入导出框架,而不是每个模块单独写一套。

2)可配置

列是否显示、排序、标题、是否必填、默认值、字典映射、格式化规则都可配置。

3)支持自定义方案

同一个业务对象可以保存多个导出方案、多个导入模板。

4)支持“字段别名”

Excel 列名和系统字段名解耦。

5)支持主从结构

如订单主表 + 订单明细表。

6)支持大数据量

异步导出、分片导入、失败明细回写。

7)支持权限

字段权限、数据权限、角色权限要能融合。

8)支持审计

谁导入了什么、谁导出了什么、用了哪个模板、失败原因是什么,都要能查。

三、通用能力边界

这个平台建议覆盖以下四类能力:

1)导出
自定义列导出
固定模板导出
多语言列头导出
当前查询条件导出
导出方案保存
异步导出任务
2)导入
下载导入模板
Excel/CSV 导入
自定义列头映射
数据预检
导入执行
错误报告导出
3)配置
模块字段定义
列显示配置
导入模板配置
导出方案配置
字段转换规则配置
字典映射配置
4)治理
权限
审计日志
模板版本
幂等控制
任务管理
性能与限流
四、核心设计思想

我建议你采用下面这个核心模型:

1)业务模块(Module)

定义“哪个业务对象可以导入导出”

例如:

商品
客户
销售订单
采购订单
入库单
出库单
库存
对账单
2)字段元数据(Column Meta)

定义“这个模块有哪些可导入导出的字段”

例如:

字段编码:customer_name
字段标题:客户名称
字段路径:customer.name
数据类型:string
是否支持导入
是否支持导出
是否主键列
是否必填
是否允许自定义显示名
是否需要字典转换
3)方案(Scheme)

定义“这一次导出/导入要用哪些列”

例如:

商品导出方案A:名称、分类、品牌、售价
商品导出方案B:名称、规格、库存、成本价
销售订单导出方案A:订单号、客户、金额、状态
4)模板(Template)

定义“导入模板长什么样”

例如:

商品导入模板
客户导入模板
销售订单导入模板
订单明细导入模板
5)任务(Task)

定义“这一次导入/导出执行过程”

例如:

导出任务:待处理 / 处理中 / 成功 / 失败
导入任务:待校验 / 校验中 / 待执行 / 执行中 / 部分成功 / 成功 / 失败
五、总体架构设计

建议拆成 7 层能力:

1)前端配置层

给用户配置:

导出列
列顺序
列头名称
模板
默认方案
导入映射关系
2)元数据层

管理:

模块定义
字段定义
字典映射
校验规则
公式规则
3)任务层

管理:

导入任务
导出任务
任务状态
失败明细
文件地址
4)解析层

负责:

读取 Excel/CSV
识别列头
映射系统字段
类型转换
5)校验层

负责:

基础校验
引用校验
唯一性校验
业务校验
跨行校验
6)执行层

负责:

数据落库
主从分组
幂等处理
事务控制
批量处理
7)文件层

负责:

模板生成
文件上传
文件下载
OSS/MinIO 存储
大文件异步读写
六、通用数据模型设计

下面给你一套比较通用的表结构设计思路。

  1. 导入导出模块定义表
    sys_ie_module
    CREATE TABLE sys_ie_module (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    module_code VARCHAR(64) NOT NULL COMMENT '模块编码,如 sales_order、goods、customer',
    module_name VARCHAR(128) NOT NULL COMMENT '模块名称',
    biz_type VARCHAR(64) DEFAULT NULL COMMENT '业务类型',
    import_enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否支持导入:0否1是',
    export_enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否支持导出:0否1是',
    template_enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否支持模板',
    async_enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否支持异步任务',
    service_name VARCHAR(128) DEFAULT NULL COMMENT '处理服务Bean名称',
    remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
    sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:0禁用1启用',
    create_time BIGINT NOT NULL,
    update_time BIGINT NOT NULL,
    UNIQUE KEY uk_module_code (module_code)
    ) COMMENT='导入导出模块定义表';
  2. 字段元数据表
    sys_ie_column
    CREATE TABLE sys_ie_column (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    module_code VARCHAR(64) NOT NULL COMMENT '模块编码',
    column_code VARCHAR(64) NOT NULL COMMENT '字段编码',
    column_name VARCHAR(128) NOT NULL COMMENT '默认列名',
    field_path VARCHAR(256) NOT NULL COMMENT '字段路径,如 customer.name、goods.spec',
    db_field VARCHAR(128) DEFAULT NULL COMMENT '数据库字段',
    data_type VARCHAR(32) NOT NULL COMMENT 'string、int、decimal、date、datetime、boolean、enum',
    scope_type VARCHAR(32) NOT NULL DEFAULT 'main' COMMENT 'main主表/detail明细/virtual虚拟字段',
    parent_code VARCHAR(64) DEFAULT NULL COMMENT '父字段编码,主从结构时可用',
    import_enabled TINYINT NOT NULL DEFAULT 1 COMMENT '支持导入',
    export_enabled TINYINT NOT NULL DEFAULT 1 COMMENT '支持导出',
    required_flag TINYINT NOT NULL DEFAULT 0 COMMENT '默认是否必填',
    unique_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否唯一值校验',
    query_enabled TINYINT NOT NULL DEFAULT 0 COMMENT '是否支持作为查询条件',
    dict_type VARCHAR(64) DEFAULT NULL COMMENT '字典类型',
    enum_code VARCHAR(64) DEFAULT NULL COMMENT '枚举编码',
    format_pattern VARCHAR(64) DEFAULT NULL COMMENT '格式化模式',
    default_value VARCHAR(256) DEFAULT NULL COMMENT '默认值',
    sample_value VARCHAR(256) DEFAULT NULL COMMENT '模板示例值',
    width INT DEFAULT NULL COMMENT '导出列宽',
    precision_num INT DEFAULT NULL COMMENT '小数位',
    sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
    system_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否系统字段',
    permission_code VARCHAR(128) DEFAULT NULL COMMENT '字段权限编码',
    validate_rule_json TEXT DEFAULT NULL COMMENT '校验规则JSON',
    convert_rule_json TEXT DEFAULT NULL COMMENT '转换规则JSON',
    description VARCHAR(500) DEFAULT NULL COMMENT '说明',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
    create_time BIGINT NOT NULL,
    update_time BIGINT NOT NULL,
    UNIQUE KEY uk_module_column (module_code, column_code),
    KEY idx_module_code (module_code)
    ) COMMENT='导入导出字段元数据表';
  3. 导出方案/导入方案主表
    sys_ie_scheme
    CREATE TABLE sys_ie_scheme (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    module_code VARCHAR(64) NOT NULL COMMENT '模块编码',
    scheme_code VARCHAR(64) NOT NULL COMMENT '方案编码',
    scheme_name VARCHAR(128) NOT NULL COMMENT '方案名称',
    scheme_type VARCHAR(32) NOT NULL COMMENT 'EXPORT/IMPORT',
    owner_type VARCHAR(32) NOT NULL DEFAULT 'USER' COMMENT 'SYSTEM/USER/ROLE/ORG',
    owner_id BIGINT DEFAULT NULL COMMENT '所属人/角色/组织ID',
    public_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否公共方案',
    default_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认方案',
    version_no INT NOT NULL DEFAULT 1 COMMENT '版本号',
    remark VARCHAR(500) DEFAULT NULL COMMENT '备注',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
    create_time BIGINT NOT NULL,
    update_time BIGINT NOT NULL,
    UNIQUE KEY uk_scheme_code (module_code, scheme_code)
    ) COMMENT='导入导出方案主表';
  4. 方案列配置表
    sys_ie_scheme_column
    CREATE TABLE sys_ie_scheme_column (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    scheme_id BIGINT NOT NULL COMMENT '方案ID',
    module_code VARCHAR(64) NOT NULL COMMENT '模块编码',
    column_code VARCHAR(64) NOT NULL COMMENT '字段编码',
    display_name VARCHAR(128) DEFAULT NULL COMMENT '显示名称,可覆盖默认列名',
    sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
    checked_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否勾选',
    required_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否导入必填',
    visible_flag TINYINT NOT NULL DEFAULT 1 COMMENT '是否显示',
    width INT DEFAULT NULL COMMENT '导出列宽',
    format_pattern VARCHAR(64) DEFAULT NULL COMMENT '当前方案格式',
    default_value VARCHAR(256) DEFAULT NULL COMMENT '默认值',
    example_value VARCHAR(256) DEFAULT NULL COMMENT '示例值',
    rule_json TEXT DEFAULT NULL COMMENT '方案级规则覆盖',
    create_time BIGINT NOT NULL,
    update_time BIGINT NOT NULL,
    KEY idx_scheme_id (scheme_id),
    KEY idx_module_code (module_code)
    ) COMMENT='导入导出方案列配置表';
  5. 列头别名映射表
    sys_ie_column_alias
    CREATE TABLE sys_ie_column_alias (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    module_code VARCHAR(64) NOT NULL COMMENT '模块编码',
    column_code VARCHAR(64) NOT NULL COMMENT '字段编码',
    alias_name VARCHAR(128) NOT NULL COMMENT '别名,如 商品、品名、货品名称',
    lang_code VARCHAR(32) DEFAULT NULL COMMENT '语言编码',
    system_flag TINYINT NOT NULL DEFAULT 1 COMMENT '系统内置/用户新增',
    create_time BIGINT NOT NULL,
    update_time BIGINT NOT NULL,
    KEY idx_module_column (module_code, column_code),
    KEY idx_alias_name (alias_name)
    ) COMMENT='字段列头别名表';

这个表很重要,导入识别列头时非常有用。

  1. 导入导出任务表
    sys_ie_task
    CREATE TABLE sys_ie_task (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    task_no VARCHAR(64) NOT NULL COMMENT '任务编号',
    module_code VARCHAR(64) NOT NULL COMMENT '模块编码',
    scheme_id BIGINT DEFAULT NULL COMMENT '方案ID',
    task_type VARCHAR(32) NOT NULL COMMENT 'IMPORT/EXPORT',
    biz_mode VARCHAR(32) DEFAULT NULL COMMENT 'SYNC/ASYNC',
    file_name VARCHAR(256) DEFAULT NULL COMMENT '文件名',
    file_url VARCHAR(512) DEFAULT NULL COMMENT '文件地址',
    template_name VARCHAR(128) DEFAULT NULL COMMENT '模板名',
    request_param_json LONGTEXT DEFAULT NULL COMMENT '请求参数',
    mapping_json LONGTEXT DEFAULT NULL COMMENT '列映射JSON',
    total_count INT NOT NULL DEFAULT 0 COMMENT '总记录数',
    success_count INT NOT NULL DEFAULT 0 COMMENT '成功数',
    fail_count INT NOT NULL DEFAULT 0 COMMENT '失败数',
    status VARCHAR(32) NOT NULL COMMENT 'PENDING/RUNNING/SUCCESS/PART_SUCCESS/FAILED/CANCELED',
    error_msg VARCHAR(1000) DEFAULT NULL COMMENT '错误信息',
    result_file_url VARCHAR(512) DEFAULT NULL COMMENT '结果文件URL',
    operator_id BIGINT DEFAULT NULL COMMENT '操作人ID',
    operator_name VARCHAR(128) DEFAULT NULL COMMENT '操作人',
    start_time BIGINT DEFAULT NULL COMMENT '开始时间',
    finish_time BIGINT DEFAULT NULL COMMENT '结束时间',
    create_time BIGINT NOT NULL,
    update_time BIGINT NOT NULL,
    UNIQUE KEY uk_task_no (task_no),
    KEY idx_module_type (module_code, task_type),
    KEY idx_operator_id (operator_id)
    ) COMMENT='导入导出任务表';
  2. 导入失败明细表
    sys_ie_task_detail
    CREATE TABLE sys_ie_task_detail (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    task_id BIGINT NOT NULL COMMENT '任务ID',
    row_no INT NOT NULL COMMENT 'Excel行号',
    column_code VARCHAR(64) DEFAULT NULL COMMENT '字段编码',
    column_name VARCHAR(128) DEFAULT NULL COMMENT '列名称',
    raw_value VARCHAR(2000) DEFAULT NULL COMMENT '原始值',
    parsed_value VARCHAR(2000) DEFAULT NULL COMMENT '解析值',
    error_code VARCHAR(64) DEFAULT NULL COMMENT '错误编码',
    error_msg VARCHAR(1000) DEFAULT NULL COMMENT '错误信息',
    status VARCHAR(32) NOT NULL DEFAULT 'FAIL' COMMENT 'SUCCESS/FAIL/WARN',
    create_time BIGINT NOT NULL,
    KEY idx_task_id (task_id),
    KEY idx_task_row (task_id, row_no)
    ) COMMENT='导入任务明细表';
  3. 模板版本表
    sys_ie_template
    CREATE TABLE sys_ie_template (
    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键',
    module_code VARCHAR(64) NOT NULL COMMENT '模块编码',
    template_code VARCHAR(64) NOT NULL COMMENT '模板编码',
    template_name VARCHAR(128) NOT NULL COMMENT '模板名称',
    template_type VARCHAR(32) NOT NULL COMMENT 'IMPORT/EXPORT',
    scheme_id BIGINT DEFAULT NULL COMMENT '关联方案ID',
    version_no INT NOT NULL DEFAULT 1 COMMENT '版本',
    file_url VARCHAR(512) DEFAULT NULL COMMENT '模板文件地址',
    sample_file_url VARCHAR(512) DEFAULT NULL COMMENT '示例文件地址',
    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态',
    create_time BIGINT NOT NULL,
    update_time BIGINT NOT NULL,
    UNIQUE KEY uk_template_code (module_code, template_code, version_no)
    ) COMMENT='导入导出模板表';
    七、字段元数据要定义哪些内容

字段元数据是整套系统最核心的地方。建议每个字段至少具备下面这些能力:

1)基础属性
字段编码
字段名称
字段路径
数据类型
主表/明细/虚拟字段
排序号
2)导入属性
是否支持导入
是否必填
是否允许空值
默认值
别名匹配
示例值
3)导出属性
是否支持导出
默认显示
默认排序
列宽
格式化规则
4)校验属性
最大长度
最小长度
数值范围
日期格式
枚举范围
唯一校验
引用校验
正则校验
5)转换属性
字典编码
枚举转换
布尔值转换
单位换算
数据脱敏
自定义表达式
6)权限属性
字段权限编码
是否敏感字段
是否可导出
是否可导入
八、导出功能通用设计

  1. 导出模式

建议支持四种:

模式A:默认导出

系统预设列,点一下直接导出。

模式B:自定义列导出

用户勾选自己要的列,再导出。

模式C:保存方案导出

用户保存一套常用方案,下次直接选。

模式D:模板导出

按固定模板导出,适合对接外部系统。

  1. 导出流程
    标准流程
    用户进入列表页
    点击导出
    选择“全部字段”或“自定义列”
    系统读取字段元数据
    根据权限过滤不可见字段
    组装查询条件
    按选择列构建导出 DTO
    格式化数据
    写入 Excel/CSV
    记录导出任务
    返回下载地址
  2. 导出字段处理规则

导出时每个字段应支持:

字段显示名替换
字典值翻译
枚举文本化
日期格式化
小数位处理
脱敏处理
空值默认显示
多语言列头

例如:

系统字段 原始值 导出值
order_status 1 已审核
create_time 1712000000000 2026-04-15 10:00:00
mobile 13812345678 138****5678
4. 导出方案保存

用户勾选列后,可以保存:

方案名称
是否默认
是否公开
列顺序
显示名
格式规则

这就能实现“每个人有自己的导出习惯”。

九、导入功能通用设计

  1. 导入模式

建议支持三种:

模式A:标准模板导入

系统下载模板,用户按模板填数据上传。

模式B:智能列头映射导入

即使列头不完全一致,只要能识别别名,也能导入。

模式C:手动映射导入

系统识别不到时,用户自己把 Excel 列映射到系统字段。

  1. 导入流程建议拆成两阶段
    第一阶段:预校验

只做检查,不落库。

校验内容:

列头是否识别
必填是否为空
类型是否正确
字典值是否合法
日期格式是否正确
关联数据是否存在
唯一键是否重复
文件内是否重复
第二阶段:正式导入

通过后再执行落库。

这样用户体验会好很多。

  1. 导入流程图逻辑
    单表导入
    上传文件
    创建任务
    解析表头
    列头匹配
    行数据读取
    字段转换
    基础校验
    业务校验
    批量入库
    输出结果报告
    主从表导入

以订单为例:

读取每一行
按“订单号”分组
组装订单主表
组装订单明细
先校验主表
再校验明细
最后主从一起保存
十、主从结构导入如何通用化

这部分非常关键,因为很多业务不是单表。

比如销售订单 Excel 可能是这样:

订单号 客户名称 收货地址 商品名称 规格 数量 单价

其实一行是“订单明细”,但其中:

订单号、客户名称、收货地址 属于主表
商品名称、规格、数量、单价 属于明细表

所以系统必须支持:

1)字段归属

字段元数据要标记:

scope_type = main
scope_type = detail
2)主键分组

定义主记录分组键:

订单号
或导入时生成临时主键
3)主从组装器

导入引擎统一做:

相同订单号行聚合成一个订单
订单下挂多个明细
4)业务处理接口

每个业务模块只实现自己的组装和保存逻辑即可。

例如统一接口:

public interface ImportBizHandler {

String moduleCode();

ImportParseResult parse(List<Map<String, Object>> rows);

ImportValidateResult validate(List dataList);

ImportExecuteResult execute(List dataList);
}

这样平台层负责通用流程,业务层只负责业务规则。

十一、导入字段映射设计

Excel 列名和系统字段一定要解耦。

建议支持三种匹配方式:

1)精确匹配

Excel 列头 = 字段名称

2)别名匹配

如:

商品
品名
货品名称

都映射到 goods_name

3)用户手动映射

系统弹出映射页面,用户选择:

Excel列A -> 系统字段X
Excel列B -> 系统字段Y
十二、校验规则通用设计

建议把校验拆成 5 层:

1)文件级校验
文件类型
文件大小
Sheet 数量
表头完整性
2)字段级校验
必填
类型
长度
范围
格式
3)引用级校验
客户是否存在
商品是否存在
单位是否存在
仓库是否存在
4)行级业务校验
数量不能小于0
金额必须大于0
状态是否允许导入
5)跨行校验
同一订单号是否重复冲突
同一客户编码是否重复
同一商品+规格+单位是否重复
校验失败输出建议

不要只提示“导入失败”,而是要精确到:

第几行
哪一列
原始值是什么
错误原因是什么
建议怎么修改

例如:

行号 列名 值 错误原因
5 客户名称 测试客户A 客户不存在
8 数量 abc 不是数字
12 单价 -5 单价不能小于0
十三、导入执行策略设计

建议支持这几种策略:

1)全有全无

一条失败,全批回滚。

适合:

财务凭证
库存期初
结算数据
2)部分成功

正确的保存,错误的跳过。

适合:

客户资料导入
商品资料导入
联系人导入
3)覆盖更新

导入时如果已存在就更新。

4)仅新增

已存在则报错。

5)不存在自动创建引用数据

例如:

单位不存在自动新增单位
品牌不存在自动新增品牌
客户不存在自动新增客户

这个能力非常适合你常见的业务导入场景。

十四、权限设计

导入导出绝不能只看“有没有按钮权限”,至少要看四层:

1)模块权限

是否可以导入/导出某模块。

2)字段权限

例如:

成本价可看不可导出
手机号可导出但要脱敏
身份证不可导出
3)数据权限

例如只能导出:

自己的数据
本部门数据
某个门店数据
某个租户数据
4)方案权限

公共方案谁都能用
个人方案只能本人用
角色方案按角色共享

十五、前端页面设计建议

建议做 5 个页面:

1)模块字段管理页

运营或管理员配置模块有哪些字段。

2)导出列选择弹窗

用户勾选、排序、重命名、保存方案。

3)导入模板下载页

下载标准模板、示例模板。

4)导入映射页

上传文件后自动识别列头,不匹配的手动映射。

5)任务中心页

查看导入导出任务状态、下载结果文件、查看失败原因。

十六、后端接口设计建议
1)元数据接口
获取模块字段

GET /ie/module/{moduleCode}/columns

获取方案列表

GET /ie/module/{moduleCode}/schemes?type=EXPORT

保存方案

POST /ie/scheme/save

删除方案

POST /ie/scheme/delete

2)模板接口
下载导入模板

GET /ie/template/download?moduleCode=goods

下载示例模板

GET /ie/template/sample?moduleCode=goods

3)导入接口
上传文件

POST /ie/import/upload

预校验

POST /ie/import/precheck

执行导入

POST /ie/import/execute

查询任务

GET /ie/task/{taskId}

下载失败报告

GET /ie/task/{taskId}/fail-report

4)导出接口
同步导出

POST /ie/export/sync

异步导出

POST /ie/export/async

查询导出任务

GET /ie/task/{taskId}

下载导出文件

GET /ie/task/{taskId}/download

十七、Java 架构建议

你现在常用的是 Spring Boot + MyBatis-Plus + EasyExcel,这套很适合。

建议核心代码结构如下:

com.sxb.common.ie
├── controller
│ ├── ImportExportController
├── service
│ ├── ImportService
│ ├── ExportService
│ ├── SchemeService
│ ├── TemplateService
│ ├── TaskService
├── engine
│ ├── ImportEngine
│ ├── ExportEngine
│ ├── ColumnMappingEngine
│ ├── ValidateEngine
│ ├── ConvertEngine
├── handler
│ ├── ImportBizHandler
│ ├── ExportBizHandler
│ ├── abstract
│ │ ├── AbstractImportBizHandler
│ │ ├── AbstractExportBizHandler
├── model
│ ├── dto
│ ├── vo
│ ├── entity
├── enums
│ ├── IeTaskStatusEnum
│ ├── IeDataTypeEnum
│ ├── IeSchemeTypeEnum
├── dao
├── util
│ ├── ExcelUtil
│ ├── TemplateUtil
│ ├── RuleUtil
十八、建议的核心接口
导入处理器
public interface ImportBizHandler {

String moduleCode();

void validateTemplate(List mappings);

ImportPreviewResult preview(ImportContext context);

ImportValidateResult validate(ImportContext context);

ImportExecuteResult execute(ImportContext context);
}
导出处理器
public interface ExportBizHandler {

String moduleCode();

List<?> queryExportData(ExportContext context);

List buildRows(ExportContext context, List<?> dataList);
}
字段值转换器
public interface ColumnValueConverter {

boolean supports(String dataType);

Object parse(Object rawValue, ColumnMetaDTO columnMeta);

Object format(Object value, ColumnMetaDTO columnMeta);
}
校验器
public interface ColumnValidator {

boolean supports(String ruleType);

ValidateResult validate(Object value, ColumnMetaDTO meta, Map<String, Object> rowData);
}
十九、推荐的导入导出执行模式
小数据量

直接同步处理。

适合:

1千行以内
列较少
校验简单
大数据量

异步任务处理。

适合:

1万行以上
主从结构
复杂引用校验
复杂业务写入
大文件导入建议
1)分批读取

一次 500 或 1000 行处理。

2)分批校验

避免一次性占用大量内存。

3)分批写库

使用批量 insert/update。

4)引用缓存

例如客户、商品、单位、仓库等预加载到内存 Map。

5)异步任务

避免前端请求超时。

二十、Excel 模板怎么设计更合理

建议模板至少包含:

1)数据 Sheet

真正填写数据的地方。

2)说明 Sheet

说明:

哪些字段必填
格式要求
示例值
注意事项
3)字典 Sheet(可选)

例如:

状态值
单位
仓库
枚举项
模板列头建议格式

可以支持两行表头:

第一行

用户可见名称
例如:客户名称

第二行

系统编码
例如:customer_name

这样能显著提升导入识别准确率。

二十一、一个典型业务例子:销售订单导入

例如用户上传:

订单号 客户名称 联系电话 商品名称 规格 单位 数量 单价

系统处理:

第一步:列头匹配
订单号 -> order_no
客户名称 -> customer_name
联系电话 -> contact_mobile
商品名称 -> goods_name
第二步:字段转换
数量 -> decimal
单价 -> decimal
第三步:引用校验
客户名称是否存在
商品名称+规格+单位是否存在
第四步:主从分组

按订单号分组

第五步:业务校验
同一订单号下客户必须一致
数量必须大于0
单价不能小于0
第六步:落库

生成:

销售订单主表
销售订单明细表
二十二、通用设计中的几个关键难点
1)字段不是数据库字段怎么办

很多导出列其实是:

计算字段
关联字段
虚拟字段
翻译字段

例如:

可用库存
未出数量
最近采购价
审核状态名称

解决办法:
字段元数据里增加:

scope_type = virtual
field_path
convert_rule_json
由业务 Handler 提供取值逻辑
2)同一个字段在不同方案中格式不同怎么办

例如金额:

财务导出保留 2 位
BI 导出保留 4 位

解决办法:
系统默认规则在 sys_ie_column
方案覆盖规则在 sys_ie_scheme_column

3)字段权限和导出列冲突怎么办

例如用户保存的方案里有“成本价”,但当前用户没权限。

解决办法:
实际执行时再次做权限裁剪,不要直接按保存方案原样输出。

4)导入时外部列名五花八门怎么办

解决办法:

别名表
模糊匹配
手工映射
模板下载规范化
二十三、推荐的状态设计
导入任务状态
INIT
UPLOADED
MAPPING
PRECHECKING
PRECHECK_FAIL
WAIT_EXECUTE
RUNNING
PART_SUCCESS
SUCCESS
FAILED
CANCELED
导出任务状态
INIT
WAITING
RUNNING
SUCCESS
FAILED
EXPIRED
二十四、审计与日志设计

建议导入导出都记录完整日志:

导出日志
谁导出了
导出哪个模块
用了什么条件
用了哪些列
共导出多少条
是否包含敏感字段
文件地址
导入日志
谁导入了
上传了什么文件
使用了什么模板
识别了哪些列
成功多少条
失败多少条
失败原因文件地址
是否自动创建了引用数据
二十五、平台化落地建议

如果你想把它做成“升鲜宝整个平台都能复用”的能力,我建议你按下面方式落地:

第一阶段:先做基础通用版

支持:

单表导出
自定义列
方案保存
标准模板导入
失败报告
第二阶段:做增强版

支持:

列头别名
手动映射
主从导入
字典转换
异步任务
第三阶段:做平台版

支持:

权限集成
多语言列头
模板版本
字段级脱敏
审计中心
OSS 文件中心
导入导出中心
二十六、我给你的最终推荐方案

如果你要做真正可复用、可上线、可扩展的版本,我建议采用下面这个结论:

核心原则

字段元数据 + 方案配置 + 模板配置 + 任务中心 + 业务处理器
这是最稳的通用设计模型。

最佳实践结构
平台层负责
列定义
模板生成
文件解析
列映射
基础校验
任务管理
结果文件生成
业务层负责
业务字段补充
引用校验
主从聚合
事务保存
特殊规则处理
最终效果

你后续无论是:

商品导入导出
客户导入导出
订单导入导出
库存导入导出
财务数据导入导出
CRM 数据导入导出

都只需要:

注册模块
配置字段
配置模板/方案
实现一个业务 Handler

就能复用整套平台能力。

posted @ 2026-04-16 11:07  升鲜宝生鲜供应链系统  阅读(48)  评论(0)    收藏  举报