一、Excel框架简介
1.1 简介
本Excel框架是嵌入式的代码中间件,用于屏蔽Excel对上层业务的复杂性,将Excel转换为对程序员更友好的Bean列表,并提供多版本、不定表头、全局异常捕获、举例行过滤、springmvc注解等实用功能特性,除此之外还针对07版本的Excel做了特定的优化,降低其巨大的内存占用,解决了excel将内存撑满的问题。
1.2 目录结构
全文总共有三大部分:
Excel框架简介以及框架的设计思路以及常见类介绍
实用特性的介绍以及原理解析
07版Excel内存优化方案
1.3 源码地址
https://github.com/MAKEOnesDestiny/excel
球球了,请star一下
二、框架解析
2.1 类结构图
2.2 ExcelFactoryConfig配置项
此配置项只提供了是否将空白单元格解析成空字符串,如果为true,则对应字段为null。接口形式的配置已经过期并推荐使用ExcelFactoryConfigInner成员配置类。
/**
* @see ExcelFactoryConfigInner
*/
@Deprecated
public interface ExcelFactoryConfig {
/**
* 是否忽略空白单元格,例如单元格格式设置为"文本"的空单元格
* @return true->忽略 false->不忽略
*/
@Deprecated
boolean skipBlank();
}复制
2.3 ExcelFactoryConfigInner
excel解析的配置项,可以用于控制excel解析的关键行为。
public class ExcelFactoryConfigInner implements ExcelFactoryConfig {
/**
* 是否忽略空白单元格,例如单元格格式设置为"文本"的空单元格
* @return true->忽略 false->不忽略
*/
private boolean skipBlank = false;
/**
* 是否捕获所有异常
*/
private boolean catchAllException = true;
/**
* 是否过滤举例行
*/
private boolean filterExample = true;
/**
* 是否使用1904时间格式
*/
private boolean use1904 = false;
}复制
2.4 ExcelFactory主体流程图
三、源码解析
3.1 核心类说明
3.1.1 Column注解
Column注解的参数名意义如下
参数名 | 说明 | 默认值 |
---|---|---|
version | 多版本控制 | -1 |
position | 字段在excel中对应的位置(暂未使用) | -1 |
headerName | 对应列表头的名称 | 无 |
setter | 自定义的setter方法 | “”,代表将自动使用setXxx()的方法 |
getter | 自定义的getter方法 | “”,代表将自动使用getXxx()的方法 |
required | 此表头是否必须存在 | true |
converter | 自定义的转换器,如果没有设置将使用Spring框架提供的ConversionService尝试进行转换 | EmptyConverter |
valid | 校验器,支持多个校验器同时校验,校验的顺序即为从左到右,如果不设置则不进行校验 | {NopValidator} |
argsValid(新增) | 新增带参数的校验器,与valid同时使用时会使得valid失效 | [] |
format | 格式化类,在generateExcel方法中使用,对bean进行format,在文件上传时不起作用 | DefaultFormatter |
3.1.2 Excel注解
Excel注解的参数名意义如下
参数名 | 说明 | 默认值 |
---|---|---|
offset | 表头的偏移量 | 0 |
sheet | excel表格的sheet编号 | 0 |
sheetName | sheet名称,优先级高于sheet | “” |
3.1.3 ColumnWrap类
ColumnWrap类有3个成员变量,分别是Column 、Field、ValidPipeline
public class ColumnWrap {
private Column column;
private Field field;
private DefaultExcelFactory.ValidPipeLine pipeLine;
}复制
一个ColumnWrap实例代表了excel中某一列于目标bean中的某一个field的对应关系,pipeline代表根据Column中valid属性中的校验器数组,为了后期使用的方便,预先解析出来,其内部结构为链表。
public static final class ValidPipeLine {
public static final ValidPipeLine EMPTY_VALID_PIPELINE;
static {
EMPTY_VALID_PIPELINE = new ValidPipeLine(null);
EMPTY_VALID_PIPELINE.setNext(null);
EMPTY_VALID_PIPELINE.setPrev(null);
}
volatile ValidPipeLine next;
volatile ValidPipeLine prev;
Validator validator;
}复制
根据传入的excel解析出来的多个ColumnWrap组成数组作为ExcelBeanMetaData的成员属性,用于解析excel的唯一依据。
3.1.4 Validator类
Validator接口定义了两个方法,分别代表对原始数据转换前的校验以及数据转换后的校验。
/**
* 校验器必须有一个空构造器
*/
public interface Validator {
/**
* 在数据转换前进行校验
*
* @param rawValue
* @param <T>
* @return true:校验通过 false:校验失败
* @throws Exception
*/
default <T> boolean validBefore(String rawValue) throws Exception {
return true;
}
/**
* 在数据转换后进行校验
*
* @param convertedValue
* @param <T>
* @return true:校验通过 false:校验失败
* @throws Exception
*/
default <T> boolean validAfter(Object convertedValue) throws Exception {
return true;
}
}复制
需要注意的是:
如果使用@Valid注解进行使用时,校验器需要提供一个空构造器。
如果使用@ArgsValidators注解进行使用时,校验器需要根据配置提供相对应的有参构造方法。
校验器的组合使用
校验器可以进行多个及联使用,比如某一个字段的校验要求是:
不可以为空
必须是正整数,并且小于100。
那么可以对三个校验器进行拼装完成校验,PostiveIntegerValidator校验器只关注数据是否为正整数,而不用去关注数据是否为空,因为校验器是按照顺序进行校验的,一旦非空校验不通过,后面的校验器不会去执行,也可以选择一个校验器同时做以上三个判断,分开的话可以更加灵活并且容易复用。
public class TestBean {
@Column(headerName = "平台", valid = {NotEmptyValidator.class,RangeValidator.class})
private String platform;
}复制
校验器隐式传参
如果校验器需要一个在运行时才能知道的参数,例如需要根据用户选择的店铺进行校验时,可以使用隐式传参数。
隐式传参数的相关功能由ParameterPassHelp类实现,实现原理即用ThreadLocal保存参数,根据特定KEY获取相对应的参数,KEY与校验器指定的KEY保持一致即可。
*!!如果特殊情况下进行了线程切换,需要手动将参数再传递一遍!!!*
带入参的校验器
校验器需要根据配置提供相对应的有参构造方法。
实现带入参的校验器过程中新引入了@ArgsValidators注解,其有三个参数:
参数名 | 说明 | 默认值 |
---|---|---|
validator | 校验器的class | default |
args | 校验器构造器的参数(多个) | {} |
argsClass | 校验器构造器的参数类型 | {} |
其中args为字符串类型的参数数组,argsClass为参数的class类型,args的长度必须和argsClass的长度相等,并且是能转换的,否则将报错,例如无法将“abc”转换成Integer类型(自己定义了转换方式的除外)。
3.1.5 Converter接口
Converter接口定义了一个方法,通过自定义接口实现可以将cell中的数据转换成所需要的格式。
public interface Converter<S, T> {
T convert(S source) throws Exception;
}复制
如果@Column注解中有配置对应的Converter类,则会使用此Converter进行参数转换,如果没有配置,则默认会使用Spring提供的ConversionService根据所需要的字段类型进行参数的自适应转换。
通过常见的Converter实现类,可以做到固定excel的某一列、去除cell中所有空格、自定义枚举类型转义等功能。
3.2 异常体系
3.2.1 异常体系继承图
3.2.2 异常继承关系说明
ExcelException是抽象类,其内部展示没有字段以及重写方法,目前只是扮演一个tag的角色,有利于业务层去捕获框架中的异常。
ExcelDataWrongException
框架中的异常类,继承于ExcelException,Excel解析过程中的异常信息会被捕获并且封装成ExcelDataWrongException。
public class ExcelDataWrongException extends ExcelException {
private ExcelPos excelPos;
//may be null
private String columnName;
private Object invalidData;
}复制
ExcelPos代表解析哪一个单元格时发生了异常,其内部记录了单元格的行和列信息,invalidData代表了发生异常的单元格的数据,至于发生的异常(包括converter和validator中的异常信息)存放于Throwable中的detailMessage中。
ExcelDataWrongException定义了默认的错误展示格式,其格式为:
*[sheet名称]--->[row:1,column:1]处数据错误,错误数据为:123(数据不能大于100)*
ExcelCompositionException
ExcelCompositionException是一个聚合异常,其内部封装了一个存放ExcelDataWrongException的list集合。
/**
* Excel组合异常类,其内部存放多个异常
*/
public class ExcelCompositionException extends ExcelException {
private final List<ExcelDataWrongException> exceptions;
public ExcelCompositionException(List<ExcelDataWrongException> exceptions) {
this.exceptions = exceptions;
}
}复制