暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Excel中间件(一):简介以及设计思路

Java小透明 2021-09-13
444

一、Excel框架简介 

1.1 简介

本Excel框架是嵌入式的代码中间件,用于屏蔽Excel对上层业务的复杂性,将Excel转换为对程序员更友好的Bean列表,并提供多版本、不定表头、全局异常捕获、举例行过滤、springmvc注解等实用功能特性,除此之外还针对07版本的Excel做了特定的优化,降低其巨大的内存占用,解决了excel将内存撑满的问题。


1.2 目录结构

全文总共有三大部分:

  1. Excel框架简介以及框架的设计思路以及常见类介绍

  2. 实用特性的介绍以及原理解析

  3. 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
sheetexcel表格的sheet编号0
sheetNamesheet名称,优先级高于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;
    }
 }
复制


需要注意的是:

  1. 如果使用@Valid注解进行使用时,校验器需要提供一个空构造器。

  2. 如果使用@ArgsValidators注解进行使用时,校验器需要根据配置提供相对应的有参构造方法。


校验器的组合使用

校验器可以进行多个及联使用,比如某一个字段的校验要求是:

  1. 不可以为空

  2. 必须是正整数,并且小于100。

那么可以对三个校验器进行拼装完成校验,PostiveIntegerValidator校验器只关注数据是否为正整数,而不用去关注数据是否为空,因为校验器是按照顺序进行校验的,一旦非空校验不通过,后面的校验器不会去执行,也可以选择一个校验器同时做以上三个判断,分开的话可以更加灵活并且容易复用。

 public class TestBean {  
  @Column(headerName = "平台", valid = {NotEmptyValidator.class,RangeValidator.class})
     private String platform;
 }
复制


校验器隐式传参

如果校验器需要一个在运行时才能知道的参数,例如需要根据用户选择的店铺进行校验时,可以使用隐式传参数。

隐式传参数的相关功能由ParameterPassHelp类实现,实现原理即用ThreadLocal保存参数,根据特定KEY获取相对应的参数,KEY与校验器指定的KEY保持一致即可。

*!!如果特殊情况下进行了线程切换,需要手动将参数再传递一遍!!!*


带入参的校验器

校验器需要根据配置提供相对应的有参构造方法。

实现带入参的校验器过程中新引入了@ArgsValidators注解,其有三个参数:

参数名说明默认值
validator校验器的classdefault
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;
}
}
复制


文章转载自Java小透明,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论