Excel-Boot

GitHub 地址:gitee.com/nw1992/easy…

码云地址:github.com/programmere…

Excel-Boot 是一款 Excel 导入导出解决方案组成的轻量级开源组件。

如果喜欢或愿意使用, 请 star 本项目或者点击 donate 图标捐赠我们

如果是企业使用, 为了产品推广, 请通过评论、Issue、PullRequest README 的企业列表告诉我们企业名称

有任何问题可以通过 issue 或者评论或者添加 QQ 群(716145748)告知我们, 尽力第一时间解决您的问题

使用企业列表:

功能简介

  1. 浏览器导出 Excel 文件(支持单 / 多 sheet)

  2. 浏览器导出 Excel 模板文件

  3. 指定路径生成 Excel 文件(支持单 / 多 sheet)

  4. 返回 Excel 文件(支持单 / 多 sheet)的 OutputStream, 一般用于将 Excel 文件上传到远程, 例如 FTP

  5. 导入 Excel 文件(支持单 / 多 sheet)

功能强大

1. 解决导出大量数据造成的内存溢出问题(支持分页查询数据库、采用 poi 官方推荐 api(SXSSFWorkbook), 实现指定行数刷新到磁盘)

2. 解决导入大量数据造成的内存溢出问题(支持分页插入数据库、采用 poi 官方推荐 api(XSSF and SAX),采用 SAX 模式一行行读取到内存当中去 )

3. 解决含有占位符的空假行造成的读空值问题

4. 解决 Long 类型或者 BigDecimal 的精度不准问题

组件特色

1. 导入可以自定义解析成功或失败的处理逻辑

2. 导出支持分页查询、全量查询, 自定义每条数据的处理逻辑

3. 内置缓存, 3 万条 11 列数据, 排除查询数据所用时间, 第一次导出 2.2s 左右、第二次导出在 1.4s 左右;第一次导入 3.5s 左右、第二次导入 2.5s 左右

4. 注解操作, 轻量且便捷

5. 内置常用正则表达式类 RegexConst(身份证号、手机号、金额、邮件)

6. 可配置是否适配单元格宽度, 默认开启 (单元格内容超过 20 个汉字不再增加宽度, 3 万条 11 列数据, 耗时 50ms 左右, 用时与数据量成正比)

7. 假如出现异常,Sheet、行、列位置也都一并打印

8. 注解中的用户自定义字符串信息以及 Excel 信息已全部 trim, 不用担心存在前后空格的风险

9.Excel 样式简洁、大方、美观

10. 导出的单条数据假如全部属性都为 null 或 0 或 0.0 或 0.00 或空字符串者 null 字符串, 自动忽略, 此特性也可让用户自定义忽略规则

11. 除了直接返回 OutputStream 的方法以外的导出方法, 正常或异常情况都会自动关闭 OutputStrem、Workbook 流

组件需知

导入 & 导出

1. 导入和导出只支持尾缀为 xlsx 的 Excel 文件

2. 标注注解的属性顺序即 Excel 列的排列顺序

3. 时间转化格式 (dateFormat) 默认为“yyyy-MM-dd HH🇲🇲ss“

导入

1. 当导入 Excel, 读取到空行, 则停止读取当前 Sheet 的后面数据行

2. 导入 Excel 文件, 单元格格式使用文本或者常规, 防止出现不可预测异常

3. 导入字段类型支持:Date、Short(short)、Integer(int)、Double(double)、Long(long)、Float(float)、BigDecimal、String 类型

4. 导入 BigDecimal 字段精度默认为 2, roundingMode 默认为 BigDecimal.ROUND_HALF_EVEN, scale 设置为 -1 则不进行格式化

5. 第一行有效单元格内必须包含内容并且以第一行为依据, 导入 Excel 文件列数必须等于标注注解的属性数量

6.Date 类型字段,Excel 与时间转化格式 (dateFormat) 相比, 格式要保持一致(反例:2018/12/31 和“yyyy-MM-dd“)并且长度要一致或更长(反例:"2018-12-31" 和 yyyy-MM-dd HH🇲🇲ss"), 否则 SimpleDateFormat 将解析失败, 报 “Unparseable date:”

导出

1. 导出 BigDecimal 字段默认不进行精度格式化

2. 分页查询默认从第一页开始, 每页 3000 条

3.Excel 每超过 2000 条数据, 将内存中的数据刷新到磁盘当中去

4. 使用分 Sheet 导出方法, 每 8 万行数据分 Sheet

5. 当使用(exportResponse、exportStream、generateExcelStream)方法时, 当单个 Sheet 超过 100 万条则会分 Sheet

6. 标注属性类型要与数据库类型保持一致

7. 如果想提高性能, 并且内存允许、并发导出量不大, 可以根据实际场景适量改变分页条数和磁盘刷新量

扩展

1. 新建子类继承 ExcelBoot 类, 使用子类构造器覆盖以下默认参数, 作为通用配置

2. 直接调用以下两个构造器, 用于临时修改配置

/**
* HttpServletResponse 通用导出 Excel 构造器
*/
ExportBuilder(HttpServletResponse response, String fileName, Class excelClass, Integer pageSize, Integer rowAccessWindowSize, Integer recordCountPerSheet, Boolean openAutoColumWidth)
/**
* OutputStream 通用导出 Excel 构造器
*/
ExportBuilder(OutputStream outputStream, String fileName, Class excelClass, Integer pageSize, Integer rowAccessWindowSize, Integer recordCountPerSheet, Boolean openAutoColumWidth)
复制代码
    /**
     * Excel 自动刷新到磁盘的数量
     */
    public static final int DEFAULT_ROW_ACCESS_WINDOW_SIZE = 2000;
    /**
     * 分页条数
     */
    public static final int DEFAULT_PAGE_SIZE = 3000;
    /**
     * 分 Sheet 条数
     */
    public static final int DEFAULT_RECORD_COUNT_PEER_SHEET = 80000;
    /**
     * 是否开启自动适配宽度
     */
    public static final boolean OPEN_AUTO_COLUM_WIDTH = true;
复制代码

版本

当前为 2.0 版本, 新版本正在开发

使用手册

1. 引入 Maven 依赖

2. 将需要导出或者导入的实体属性上标注 @ExportField 或 @ImportField 注解

3. 直接调用导出或导入 API 即可

POM.xml

<dependency>
	<groupId>io.github.magic-core</groupId>
	<artifactId>excel-boot</artifactId>
	<version>2.0</version>
</dependency>
复制代码

导出导入实体对象

/**
* 导出导入实体对象
*/
public class UserEntity {
/**
* Integer 类型字段
*/
@ExportField(columnName = "ID", defaultCellValue = "1")
@ImportField(required = true)
    private Integer id;
/**
* String 类型字段
*/
@ExportField(columnName = "姓名", defaultCellValue = "张三")
@ImportField(regex = IDCARD_REGEX, regexMessage="身份证校验失败")
    private String name;
/**
* BigDecimal 类型字段
*/    
@ExportField(columnName = "收入金额", defaultCellValue = "100", scale = 2, roundingMode=BigDecimal.ROUND_HALF_EVEN)
@ImportField(scale = 2, roundingMode=BigDecimal.ROUND_HALF_EVEN)
    private BigDecimal money;
/**
* Date 类型字段
*/
@ExportField(columnName = "创建时间", dateFormat="yyyy-MM-dd", defaultCellValue = "2019-01-01")
@ImportField(dateFormat="yyyy-MM-dd")
    private Date birthDayTime;
}
复制代码

导出 api-Demo

/**
 * 导出 api-Demo
 * 
 * UserEntity 是标注注解的类,Excel 映射的导出类
 * ParamEntity 是数据层查询的参数对象
 * ResultEntity 是数据层查询到的 List 内部元素
 * UserEntity 可以和 ResultEntity 使用同一个对象, 即直接在数据层查询的结果对象上标注注解 (建议使用两个对象, 实现解耦)
 * 
 * pageQuery 方法是用户自己实现, 根据查询条件和当前页数和每页条数进行数据层查询
 * convert 方法是用户自己实现, 参数就是您查询出来的 list 中的每个元素引用, 您可以对对象属性的转换或者对象的转换, 如果不进行转换, 直接返回参数对象即可
 */
@Controller
@RequestMapping("/export")
public class TestController {
    /**
     * 浏览器导出 Excel
     *
     * @param httpServletResponse
     */
    @RequestMapping("/exportResponse")
    public void exportResponse(HttpServletResponse httpServletResponse) {
        ParamEntity queryQaram = new ParamEntity();
        ExcelBoot.ExportBuilder(httpServletResponse, "Excel 文件名", UserEntity.class).exportResponse(queryQaram,
                new ExportFunction<ParamEntity, ResultEntity>() {
                    /**
                     * @param queryQaram 查询条件对象
                     * @param pageNum    当前页数, 从 1 开始
                     * @param pageSize   每页条数, 默认 3000
                     * @return
                     */
                    @Override
                    public List<ResultEntity> pageQuery(ParamEntity queryQaram, int pageNum, int pageSize) {
                    <span class="hljs-comment">//分页查询操作</span>

                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ArrayList&lt;ResultEntity&gt;();
                }

                <span class="hljs-comment">/**
                 * 将查询出来的每条数据进行转换
                 *
                 * <span class="hljs-doctag">@param</span> o
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> UserEntity <span class="hljs-title">convert</span><span class="hljs-params">(ResultEntity o)</span> </span>{
                    <span class="hljs-comment">//转换操作</span>
                }
            });
}

<span class="hljs-comment">/**
 * 浏览器多sheet导出Excel
 *
 * <span class="hljs-doctag">@param</span> httpServletResponse
 */</span>
<span class="hljs-meta">@RequestMapping</span>(<span class="hljs-string">"/exportMultiSheetResponse"</span>)
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">exportMultiSheetResponse</span><span class="hljs-params">(HttpServletResponse httpServletResponse)</span> </span>{
    ParamEntity queryQaram = <span class="hljs-keyword">new</span> ParamEntity();
    ExcelBoot.ExportBuilder(httpServletResponse, <span class="hljs-string">"Excel文件名"</span>, UserEntity.class).exportMultiSheetStream(queryQaram,
            <span class="hljs-keyword">new</span> ExportFunction&lt;ParamEntity, ResultEntity&gt;() {
                <span class="hljs-comment">/**
                 * <span class="hljs-doctag">@param</span> queryQaram 查询条件对象
                 * <span class="hljs-doctag">@param</span> pageNum    当前页数,从1开始
                 * <span class="hljs-doctag">@param</span> pageSize   每页条数,默认3000
                 * <span class="hljs-doctag">@return</span>
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;ResultEntity&gt; <span class="hljs-title">pageQuery</span><span class="hljs-params">(ParamEntity queryQaram, <span class="hljs-keyword">int</span> pageNum, <span class="hljs-keyword">int</span> pageSize)</span> </span>{

                    <span class="hljs-comment">//分页查询操作</span>

                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ArrayList&lt;ResultEntity&gt;();
                }

                <span class="hljs-comment">/**
                 * 将查询出来的每条数据进行转换
                 *
                 * <span class="hljs-doctag">@param</span> o
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> UserEntity <span class="hljs-title">convert</span><span class="hljs-params">(ResultEntity o)</span> </span>{
                    <span class="hljs-comment">//转换操作</span>
                }
            });
}

<span class="hljs-comment">/**
 * 导出Excel到指定路径
 */</span>
<span class="hljs-meta">@RequestMapping</span>(<span class="hljs-string">"/exportStream"</span>)
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">exportStream</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> FileNotFoundException </span>{
    ParamEntity queryQaram = <span class="hljs-keyword">new</span> ParamEntity();
    ExcelBoot.ExportBuilder(<span class="hljs-keyword">new</span> FileOutputStream(<span class="hljs-keyword">new</span> File(<span class="hljs-string">"C:\\Users\\Excel文件.xlsx"</span>)), <span class="hljs-string">"Sheet名"</span>, UserEntity.class)
            .exportStream(queryQaram, <span class="hljs-keyword">new</span> ExportFunction&lt;ParamEntity, ResultEntity&gt;() {
                <span class="hljs-comment">/**
                 * <span class="hljs-doctag">@param</span> queryQaram 查询条件对象
                 * <span class="hljs-doctag">@param</span> pageNum    当前页数,从1开始
                 * <span class="hljs-doctag">@param</span> pageSize   每页条数,默认3000
                 * <span class="hljs-doctag">@return</span>
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;ResultEntity&gt; <span class="hljs-title">pageQuery</span><span class="hljs-params">(ParamEntity queryQaram, <span class="hljs-keyword">int</span> pageNum, <span class="hljs-keyword">int</span> pageSize)</span> </span>{

                    <span class="hljs-comment">//分页查询操作</span>

                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ArrayList&lt;ResultEntity&gt;();
                }

                <span class="hljs-comment">/**
                 * 将查询出来的每条数据进行转换
                 *
                 * <span class="hljs-doctag">@param</span> o
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> UserEntity <span class="hljs-title">convert</span><span class="hljs-params">(ResultEntity o)</span> </span>{
                    <span class="hljs-comment">//转换操作</span>
                }
            });
}

<span class="hljs-comment">/**
 * 导出多sheet Excel到指定路径
 */</span>
<span class="hljs-meta">@RequestMapping</span>(value = <span class="hljs-string">"exportMultiSheetStream"</span>)
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">exportMultiSheetStream</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> FileNotFoundException </span>{
    ParamEntity queryQaram = <span class="hljs-keyword">new</span> ParamEntity();
    ExcelBoot.ExportBuilder(<span class="hljs-keyword">new</span> FileOutputStream(<span class="hljs-keyword">new</span> File(<span class="hljs-string">"C:\\Users\\Excel文件.xlsx"</span>)), <span class="hljs-string">"Sheet名"</span>, UserEntity.class)
            .exportMultiSheetStream(queryQaram, <span class="hljs-keyword">new</span> ExportFunction&lt;ParamEntity, ResultEntity&gt;() {
                <span class="hljs-comment">/**
                 * <span class="hljs-doctag">@param</span> queryQaram 查询条件对象
                 * <span class="hljs-doctag">@param</span> pageNum    当前页数,从1开始
                 * <span class="hljs-doctag">@param</span> pageSize   每页条数,默认3000
                 * <span class="hljs-doctag">@return</span>
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;ResultEntity&gt; <span class="hljs-title">pageQuery</span><span class="hljs-params">(ParamEntity queryQaram, <span class="hljs-keyword">int</span> pageNum, <span class="hljs-keyword">int</span> pageSize)</span> </span>{

                    <span class="hljs-comment">//分页查询操作</span>

                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ArrayList&lt;ResultEntity&gt;();
                }

                <span class="hljs-comment">/**
                 * 将查询出来的每条数据进行转换
                 *
                 * <span class="hljs-doctag">@param</span> o
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> UserEntity <span class="hljs-title">convert</span><span class="hljs-params">(ResultEntity o)</span> </span>{
                    <span class="hljs-comment">//转换操作</span>
                }
            });
}

<span class="hljs-comment">/**
 * 生成Excel OutputStream对象
 */</span>
<span class="hljs-meta">@RequestMapping</span>(generateStream)
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">generateExcelStream</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> FileNotFoundException </span>{
    ParamEntity queryQaram = <span class="hljs-keyword">new</span> ParamEntity();
    OutputStream outputStream = ExcelBoot.ExportBuilder(<span class="hljs-keyword">new</span> FileOutputStream(<span class="hljs-keyword">new</span> File(<span class="hljs-string">"C:\\Users\\Excel文件.xlsx"</span>)), <span class="hljs-string">"Sheet名"</span>, UserEntity.class)
            .generateExcelStream(queryQaram, <span class="hljs-keyword">new</span> ExportFunction&lt;ParamEntity, ResultEntity&gt;() {
                <span class="hljs-comment">/**
                 * <span class="hljs-doctag">@param</span> queryQaram 查询条件对象
                 * <span class="hljs-doctag">@param</span> pageNum    当前页数,从1开始
                 * <span class="hljs-doctag">@param</span> pageSize   每页条数,默认3000
                 * <span class="hljs-doctag">@return</span>
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;ResultEntity&gt; <span class="hljs-title">pageQuery</span><span class="hljs-params">(ParamEntity queryQaram, <span class="hljs-keyword">int</span> pageNum, <span class="hljs-keyword">int</span> pageSize)</span> </span>{

                    <span class="hljs-comment">//分页查询操作</span>

                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ArrayList&lt;ResultEntity&gt;();
                }

                <span class="hljs-comment">/**
                 * 将查询出来的每条数据进行转换
                 *
                 * <span class="hljs-doctag">@param</span> o
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> UserEntity <span class="hljs-title">convert</span><span class="hljs-params">(ResultEntity o)</span> </span>{
                    <span class="hljs-comment">//转换操作</span>
                }
            });
}

<span class="hljs-comment">/**
 * 生成多Sheet Excel OutputStream对象
 */</span>
<span class="hljs-meta">@RequestMapping</span>(generateMultiSheetStream)
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">generateMultiSheetExcelStream</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> FileNotFoundException </span>{
    ParamEntity queryQaram = <span class="hljs-keyword">new</span> ParamEntity();
    OutputStream outputStream = ExcelBoot.ExportBuilder(<span class="hljs-keyword">new</span> FileOutputStream(<span class="hljs-keyword">new</span> File(<span class="hljs-string">"C:\\Users\\Excel文件.xlsx"</span>)), <span class="hljs-string">"Sheet名"</span>, UserEntity.class)
            .generateMultiSheetExcelStream(queryQaram, <span class="hljs-keyword">new</span> ExportFunction&lt;ParamEntity, ResultEntity&gt;() {
                <span class="hljs-comment">/**
                 * <span class="hljs-doctag">@param</span> queryQaram 查询条件对象
                 * <span class="hljs-doctag">@param</span> pageNum    当前页数,从1开始
                 * <span class="hljs-doctag">@param</span> pageSize   每页条数,默认3000
                 * <span class="hljs-doctag">@return</span>
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> List&lt;ResultEntity&gt; <span class="hljs-title">pageQuery</span><span class="hljs-params">(ParamEntity queryQaram, <span class="hljs-keyword">int</span> pageNum, <span class="hljs-keyword">int</span> pageSize)</span> </span>{

                    <span class="hljs-comment">//分页查询操作</span>

                    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> ArrayList&lt;ResultEntity&gt;();
                }

                <span class="hljs-comment">/**
                 * 将查询出来的每条数据进行转换
                 *
                 * <span class="hljs-doctag">@param</span> o
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> UserEntity <span class="hljs-title">convert</span><span class="hljs-params">(ResultEntity o)</span> </span>{
                    <span class="hljs-comment">//转换操作</span>
                }
            });
}

<span class="hljs-comment">/**
 * 导出Excel模板
 */</span>
<span class="hljs-meta">@RequestMapping</span>(<span class="hljs-string">"/exportTemplate"</span>)
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">exportTemplate</span><span class="hljs-params">(HttpServletResponse httpServletResponse)</span> </span>{
    ExcelBoot.ExportBuilder(httpServletResponse, <span class="hljs-string">"Excel模板名称"</span>, UserEntity.class).exportTemplate();
}

}

复制代码

导入 api-Demo

/**
 * 导入 api-Demo
 * 
 * UserEntity 是标注注解的类, Excel 映射的导入类, onProcess 的 userEntity 参数则是 Excel 每行数据的映射实体
 * ErrorEntity 是封装了每行 Excel 数据常规校验后的错误信息实体, 封装了 sheet 号、行号、列号、单元格值、所属列名、错误信息
 * 
 * onProcess 方法是用户自己实现, 当经过正则或者判空常规校验成功后执行的方法, 参数是每行数据映射的实体
 * convert 方法是用户自己实现, 当经过正则或者判空常规校验失败后执行的方法
 */
@Controller
@RequestMapping("/import")
public class TestController {
    @RequestMapping("/importExcel")
    public void importExcel() throws IOException {
        ExcelBoot.ImportBuilder(new FileInputStream(new File("C:\\Users\\ 导入 Excel 文件.xlsx")),  UserEntity.class)
                .importExcel(new ExcelImportFunction<UserEntity>() {
                <span class="hljs-comment">/**
                 * <span class="hljs-doctag">@param</span> sheetIndex 当前执行的Sheet的索引, 从1开始
                 * <span class="hljs-doctag">@param</span> rowIndex 当前执行的行数, 从1开始
                 * <span class="hljs-doctag">@param</span> resultEntity Excel行数据的实体
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onProcess</span><span class="hljs-params">(<span class="hljs-keyword">int</span> sheetIndex,  <span class="hljs-keyword">int</span> rowIndex,  UserEntity userEntity)</span> </span>{
                    <span class="hljs-comment">//对每条数据自定义校验以及操作</span>
                    <span class="hljs-comment">//分页插入:当读取行数到达用户自定义条数执行插入数据库操作</span>
                }

                <span class="hljs-comment">/**
                 * <span class="hljs-doctag">@param</span> errorEntity 错误信息实体
                 */</span>
                <span class="hljs-meta">@Override</span>
                <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">onError</span><span class="hljs-params">(ErrorEntity errorEntity)</span> </span>{
                    <span class="hljs-comment">//操作每条数据非空和正则校验后的错误信息</span>
                }
            });
}

}

复制代码

Octotree is enabled on this page. Click this button or press cmd shift s (or ctrl shift s) to show it. Support us • Feedback?

  • Java

    Java,是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 程序设计语言和 Java 平台的总称。用 Java 实现的 HotJava 浏览器(支持 Java applet)显示了 Java 的魅力:跨平台、动态的…

    380 引用 • 6 回帖
感谢    赞同    分享    收藏    关注    反对    举报    ...