本手册专注讲解 jquick-excel 导入(
IMPORT WITH)中最核心的三个配置项:MAPPING(字段映射)、TRANSFORM(数据转换)、VALIDATION(数据校验)。所有语法与参数均基于源码校验,示例统一采用 XML 声明式写法。
目录
总览与执行顺序 2.1 作用与语法 2.2 基础示例 2.3 使用规则 2.4 读取映射后的值 MAPPING — 字段映射 3.1 作用与语法 3.2 变量与字面量 3.3 内置转换函数 3.4 实战示例 3.5 TRANSFORM 与 MAPPING 的关系 TRANSFORM — 数据转换 4.4.1 通用规则 4.4.2 字符串类规则 4.4.3 数值类规则 4.4.4 日期类规则 4.4.5 其他规则 4.1 作用与语法 4.2 校验目标类型 4.3 规则通用结构 4.4 校验规则完整参考 4.5 多规则组合 4.6 实战示例 VALIDATION — 数据校验 三者协同使用 常见问题与避坑指南 扩展机制简介
1. 总览与执行顺序
三个配置项均写在 IMPORT WITH 语句中,以逗号分隔,书写顺序任意。但在实际执行导入时,框架有固定的处理顺序:
① VALIDATION → ② MAPPING → ③ TRANSFORM(校验原始值) (表头重命名) (值转换)
关键点: VALIDATION 校验的是原始值,TRANSFORM 转换的是校验通过后的值。若某字段需要先转换再校验,请使用 TRANSFORM 完成转换,并在程序中对转换结果做二次校验。
源码位置:JExcelImportHandler.java 的 importData 方法(位于 src/main/java/com/github/paohaijiao/handler/ 目录下)。
2. MAPPING — 字段映射
2.1 作用与语法
MAPPING 用于将 Excel 表头中的原始列名映射为目标字段名,只重命名,不改变值。
MAPPING = {”Excel原始列名”: ”目标字段名”,...}
左值:Excel 表头第 1 行中实际出现的列名(字符串,必须用引号包裹)。 右值:导入结果 JQuickRow中使用的字段名。未在 MAPPING 中出现的列:保留原始表头列名作为字段名。
2.2 基础示例
<![CDATA[IMPORT WITHHEADER=true,SHEET='Sheet1',MAPPING = {”学号”: ”no”,”姓名”: ”name”,”性别”: ”sex”,”年龄”: ”age”,”出生日期”: ”birthday”}]]>
2.3 使用规则
HEADER=false |
MAPPING 是 TRANSFORM 字段引用的桥梁:TRANSFORM 中的
${字段名}必须使用 MAPPING 映射后的目标字段名。
2.4 读取映射后的值
List rows = service.importExcel(”1”, ”2”);for (JQuickRow row : rows) {// 使用映射后的字段名取值String no = (String) row.get(”no”); // 来自”学号”列String name = (String) row.get(”name”); // 来自”姓名”列}
3. TRANSFORM — 数据转换
3.1 作用与语法
TRANSFORM 对读取到的单元格值执行转换函数,改变实际值。转换函数基于 jquick-transform-function 提供的 226+ 内置方法,并支持 SPI 自定义扩展。
TRANSFORM = {”字段名”: 函数名(参数1, 参数2, ...)}
左值:必须是 MAPPING 映射后的目标字段名。 右值:一个函数调用表达式。
3.2 变量与字面量
在转换函数的参数中,可使用以下几种写法:
${字段名} | ${sex} | |
${变量名} | JContext 中传入的外部变量 | ${dict} |
'字符串' | 'yyyy-MM-dd' | |
数字 | 1 | |
布尔 | true |
传入外部变量示例:
Map sexMap = new HashMap<>();sexMap.put(”男”, ”1”);sexMap.put(”女”, ”2”);JContext context = new JContext();context.put(”dict”, sexMap);JQuickParseHandler parser = new JQuickExcelImportXmlParseFactory(context, inputStream);
3.3 内置转换函数
jquick-excel 默认依赖 jquick-transform-function,无需额外引入。以下为常用函数分类概览(完整列表请参考 jquick-transform-function 官方仓库):
trans | trans(${dict},${sex}) |
dateFormat | dateFormat(${birthday},'yyyy-MM-dd') | |
now | now() | |
formatDate | formatDate(${date},'yyyy/MM/dd') | |
parseDate | parseDate(${str},'yyyy-MM-dd') | |
addDaysaddMonths / addYears | addDays(${date},7) | |
daysBetweenmonthsBetween / yearsBetween | daysBetween(${start},${end}) |
addsubtract / multiply / divide | add(${age},1) | |
absceil / floor / round | abs(${num}) | |
maxmin / avg | max(${a},${b}) | |
powsqrt | pow(${x},2) |
concat | concat(${first},${last}) | |
substringleft / right / mid | substring(${s},0,3) | |
replacereplaceAll | replace(${s},'a','b') | |
trimtoLower / toUpper | toUpper(${s}) | |
mask | mask(${idCard},6,14,'*') |
idCardAge | idCardAge(${idCard}) | |
idCardBirthday | idCardBirthday(${idCard},'yyyy-MM-dd') | |
idCardGender | idCardGender(${idCard}) | |
idCardValidate | idCardValidate(${idCard}) | |
phoneMask | phoneMask(${phone},3,4) | |
phoneValidate | phoneValidate(${phone}) | |
emailMask | emailMask(${email}) |
if | if(${age}>=18,'成年','未成年') | |
coalesce | coalesce(${a},${b},'默认') | |
defaultIfNull | defaultIfNull(${remark},'无') | |
eqne / gt / lt | eq(${status},1) |
toInttoLong / toDouble | toInt(${str}) | |
toStringtoBoolean | toString(${num}) |
3.4 实战示例
字典翻译 + 日期格式化 + 数值运算:
<![CDATA[IMPORT WITHHEADER=true,SHEET='Sheet1',MAPPING = {”学号”: ”no”,”姓名”: ”name”,”性别”: ”sex”,”年龄”: ”age”,”出生日期”: ”birthday”,”身份证号”: ”idCard”,”手机号”: ”phone”},TRANSFORM={”sex”:trans(${dict},${sex}),”birthday”:dateFormat(${birthday},'yyyy-MM-dd'),”age”:add(${age},1),”idCard”:mask(${idCard},6,14,'*'),”phone”:phoneMask(${phone},3,4)}]]>
调用端传入字典:
Map sexMap = new HashMap<>();sexMap.put(”男”, ”1”);sexMap.put(”女”, ”2”);JContext context = new JContext();context.put(”dict”, sexMap);JQuickParseHandler parser = new JQuickExcelImportXmlParseFactory(context, is);
3.5 TRANSFORM 与 MAPPING 的关系
TRANSFORM 的字段名引用必须是 MAPPING 映射后的目标字段名:
Excel 列 ”性别”↓ MAPPING字段名 ”sex”↓ TRANSFORMtrans(${dict},${sex}) ← 这里用 ${sex},不是 ${性别}
若 MAPPING 将 "性别" 映射为 "gender",则 TRANSFORM 应写
"gender":trans(${dict},${gender})。
4. VALIDATION — 数据校验
4.1 作用与语法
VALIDATION 在导入数据前对原始单元格值进行校验,校验失败立即抛出异常终止导入。
VALIDATION = {<目标区域>: {<规则名>{required: ,msg: '<错误消息>',map: { <参数键>: <参数值> }},<规则名>{ ... } // 同一区域可配多个规则,逗号分隔},<目标区域>: { ... }}
重要: VALIDATION 校验的是原始值(未经 TRANSFORM 转换的值)。例如性别列在 Excel 中是 "男"/"女",则校验时也按 "男"/"女" 校验,而不是转换后的 "1"/"2"。
4.2 校验目标类型
VALIDATION 支持四种目标区域,通过不同的语法指定:
ROW NROW N..M | ROW 5ROW 1..10 | ||
COL XCOL X..Y | COL ACOL A..D | ||
XN | C2 | ||
XN:YM | A1:B5 |
列也可省略
COL关键字,直接写A或A..D。
多目标校验示例:
<![CDATA[IMPORT WITH VALIDATION={ROW 2..10:{required{required:true,msg:'第2-10行不能为空'}},A..D:{max_length{required:true,msg:'列长度超限',map:{maxLength:50}}},C2:{regex{required:true,msg:'格式不对',map:{pattern:'^\\d+$'}}},A1:B5:{min_length{required:true,msg:'长度不足',map:{minLength:2}}}}]]>
4.3 规则通用结构
每条规则由三部分组成:
required | true;为 false 时跳过校验直接放行 | ||
msg | |||
map |
校验失败行为:当 required:true 且校验不通过时,框架抛出异常(包含 msg 或默认消息),终止整个导入流程。
4.4 校验规则完整参考
以下参数键均基于源码逐一校验,
map列标注"无"表示该规则不需要map参数。
required | required{required:true,msg:'不能为空'} |
regex | pattern | regex{required:true,msg:'只允许数字',map:{pattern:'^\\d+$'}} | ||
max_length | maxLength | max_length{required:true,msg:'过长',map:{maxLength:7}} | ||
min_length | minLength | min_length{required:true,msg:'过短',map:{minLength:1}} | ||
start_with | startWith | start_with{required:true,msg:'必须以SO开头',map:{startWith:'SO'}} | ||
not_start_with | notStartWith | not_start_with{required:true,msg:'非法前缀',map:{notStartWith:'test'}} | ||
end_with | endWith | end_with{required:true,msg:'必须以有限公司结尾',map:{endWith:'有限公司'}} | ||
not_end_with | notEndWith | not_end_with{required:true,msg:'非法后缀',map:{notEndWith:'@test.com'}} | ||
contain | contains | contain{required:true,msg:'必须包含关键字',map:{contains:'张三'}} | ||
not_contain | notContain | not_contain{required:true,msg:'含敏感词',map:{notContain:'敏感词'}} |
注意参数键命名差异: 规则名用下划线(
start_with),但参数键用驼峰(startWith)。contain的参数键是contains(带 s),not_contain的参数键是notContain(不带 s)。
integer | integer{required:true,msg:'必须是整数'} | |||
decimal | decimal{required:true,msg:'必须是小数'} | |||
max_value | maxValue | max_value{required:true,msg:'不能超过100',map:{maxValue:100}} | ||
min_value | minValue | min_value{required:true,msg:'不能小于0',map:{minValue:0}} |
date_format | format | date_format{required:true,msg:'格式错误',map:{format:'yyyy-MM-dd'}} | ||
max_date | formatmaxDate | max_date{required:true,msg:'超过最大日期',map:{format:'yyyy-MM-dd',maxDate:2025-01-01}} | ||
min_date | formatminDate | min_date{required:true,msg:'不能早于最小日期',map:{format:'yyyy-MM-dd',minDate:2022-01-01}} |
日期字面量使用
yyyy-MM-dd格式,不需要引号,如maxDate:2025-01-01。
email | email{required:true,msg:'邮箱格式错误'} | |||
mobile | ^1[3-9]\d{9}$) | mobile{required:true,msg:'手机号格式错误'} | ||
dict | dict{required:true,msg:'性别非法',map:{'1':'男','2':'女'}} | |||
boolean | boolean{required:true,msg:'布尔值非法',map:{'T':'true','F':'false'}} | |||
composite | composite{} |
dict与boolean的特殊行为: 二者都是校验"值是否在map的 values 中"。例如dict{map:{'1':'男','2':'女'}}表示 Excel 单元格的值必须是男或女(即 value),而不是1/2(即 key)。
4.5 多规则组合
同一目标区域可配置多条规则,以逗号分隔,所有规则都会执行,任一失败即抛异常:
<![CDATA[IMPORT WITH VALIDATION={D2:D100:{required{required:true,msg:'年龄不能为空'},integer{required:true,msg:'年龄必须是整数'},min_value{required:true,msg:'年龄>=0',map:{minValue:0}},max_value{required:true,msg:'年龄<=150',map:{maxValue:150}}}}]]>
4.6 实战示例
综合校验(字符串 + 数值 + 日期 + 字典 + 邮箱 + 手机):
<![CDATA[IMPORT WITHHEADER=true,SHEET='Sheet1',MAPPING = {”姓名”: ”name”,”性别”: ”sex”,”年龄”: ”age”,”出生日期”: ”birthday”,”手机号”: ”phone”,”邮箱”: ”email”,”订单号”: ”orderId”},VALIDATION={B2:B1000:{required{required:true,msg:'姓名不能为空'},min_length{required:true,msg:'姓名至少2位',map:{minLength:2}},max_length{required:true,msg:'姓名最长10位',map:{maxLength:10}}},C2:C1000:{dict{required:true,msg:'性别非法',map:{'1':'男','2':'女'}}},D2:D1000:{integer{required:true,msg:'年龄必须是整数'},min_value{required:true,msg:'年龄>=6',map:{minValue:6}},max_value{required:true,msg:'年龄<=60',map:{maxValue:60}}},E2:E1000:{date_format{required:true,msg:'日期格式错误',map:{format:'yyyy-MM-dd'}},min_date{required:true,msg:'不能早于2000年',map:{format:'yyyy-MM-dd',minDate:2000-01-01}},max_date{required:true,msg:'不能晚于2025年',map:{format:'yyyy-MM-dd',maxDate:2025-12-31}}},F2:F1000:{mobile{required:true,msg:'手机号格式错误'}},G2:G1000:{email{required:true,msg:'邮箱格式错误'}},A2:A1000:{start_with{required:true,msg:'订单号必须以SO开头',map:{startWith:'SO'}}}}]]>
5. 三者协同使用
一个完整的导入配置通常同时使用三者:
<![CDATA[IMPORT WITHHEADER=true,SHEET='学生表',MAPPING = {”学号”: ”no”,”姓名”: ”name”,”性别”: ”sex”,”年龄”: ”age”,”出生日期”: ”birthday”},TRANSFORM={”sex”:trans(${dict},${sex}),”birthday”:dateFormat(${birthday},'yyyy-MM-dd'),”age”:add(${age},1)},VALIDATION={C2:C1000:{dict{required:true,msg:'性别非法',map:{'1':'男','2':'女'}}},D2:D1000:{integer{required:true,msg:'年龄必须是整数'},min_value{required:true,msg:'年龄>=0',map:{minValue:0}}},E2:E1000:{date_format{required:true,msg:'日期格式错误',map:{format:'yyyy-MM-dd'}}}}]]>
完整处理流程示例(以"性别"列为例):
Excel 单元格值: ”男”↓ ① VALIDATION(校验原始值 ”男”)dict{map:{'1':'男','2':'女'}} → ”男” 在 values 中 → ✅ 通过↓ ② MAPPING(表头重命名)”性别” → ”sex”↓ ③ TRANSFORM(值转换)trans(${dict},${sex}) → 查字典 ${dict}[”男”] = ”1”↓ 最终结果JQuickRow.get(”sex”) = ”1”
6. 常见问题与避坑指南
6.1 VALIDATION 校验的是原始值还是转换后的值?
原始值。VALIDATION 在 TRANSFORM 之前执行,校验的是 Excel 中的原始单元格值。若 Excel 中性别列是 "男"/"女",校验时按 "男"/"女" 校验,而非转换后的 "1"/"2"。
6.2 TRANSFORM 中的字段名该写哪个?
写MAPPING 映射后的目标字段名。若 MAPPING 将 "性别" 映射为 "sex",则 TRANSFORM 应写 "sex":trans(${dict},${sex}),而非 "性别":...。
6.3 dict / boolean 规则的 map 是按 key 还是 value 校验?
按value校验。dict{map:{'1':'男','2':'女'}} 表示单元格值必须是 男 或 女。
6.4 日期字面量需要加引号吗?
不需要。maxDate:2025-01-01 直接写日期字面量,不要写成 '2025-01-01'。
6.5 required 配置项有什么作用?
required:true—— 启用该校验规则。 required:false—— 跳过校验,直接放行(即使值为空或不符合规则)。
注意:这并非"字段是否必填"的语义。要校验字段非空,请使用
required规则(required{required:true,msg:'不能为空'}),而非把别的规则的required设为 true。
6.6 规则名与参数键的命名风格为什么不一致?
规则名使用下划线(如 start_with、max_length),参数键使用驼峰(如 startWith、maxLength)。这是框架的既定约定,配置时请严格对照本手册的参数表。
6.7 校验失败后会怎样?
校验失败会抛出异常(包含 msg 自定义消息或规则默认消息),终止整个导入流程,已读取的数据不会返回。若希望容错,请在调用端 try-catch 处理。
7. 扩展机制简介
7.1 自定义转换函数(TRANSFORM)
TRANSFORM 的函数基于 SPI 机制扩展,详见 jquick-transform-function 仓库。核心步骤:
实现 JQuickMethodFunctionProvider接口(或继承JQuickBaseFunctionFunctionProvider)。在 META-INF/services/com.github.paohaijiao.function.core.JQuickMethodFunctionProvider注册实现类。在 XML 的 TRANSFORM 中按 getMethodName()调用。
也支持运行时动态注册:
JQuickMethodInvocationManager manager = JQuickMethodInvocationManager.getInstance();manager.registerInvoker(”myFunc”, (args) -> {// 自定义逻辑return result;}, ”自定义函数说明”);
7.2 自定义校验规则(VALIDATION)
VALIDATION 支持自定义规则扩展:
继承 JAbstractValidationRule,实现doValidate(String value)和getDefaultMsg()。在 JMethodValidationRuleType枚举中注册:MY_RULE("my_rule", JMyRule.class)。在 JExcelValidationRuleFactory增加工厂方法。在 XML 中使用: my_rule{required:true,msg:'校验失败'}。
完整的 SPI 扩展说明请参考 useage-import.md 第 4 章。
更多用法可参考:
README.md 使用示例章节 useage-import.md 完整导入使用手册 测试用例:src/test/java/com/github/paohaijiao/importFile/validate/
夜雨聆风