上海古都建筑设计集团,上海办公室装修设计公司,上海装修公司高质量的内容分享社区,上海装修公司我们不是内容生产者,我们只是上海办公室装修设计公司内容的搬运工平台

【Alibaba工具型技术系列】「EasyExcel技术专题」实战技术针对于项目中常用的Excel操作指南

guduadmin393月前

这里写目录标题

      • EasyExcel教程
        • Maven依赖
        • EasyExcel API分析介绍
        • EasyExcel 注解
        • 通用参数
          • ReadWorkbook(理解成excel对象)参数
          • ReadSheet(就是excel的一个Sheet)参数
          • 注解
          • 参数
            • 通用参数
            • WriteWorkbook(理解成excel对象)参数
            • WriteSheet(就是excel的一个Sheet)参数
            • WriteTable(就把excel的一个Sheet,一块区域看一个table)参数
            • EasyExcel用法指南
              • 简单的读取excel文件
              • 简单的写入excel文件
              • Web上传与下载
              • 详解读取Excel
                • 对象模型
                • 监听器
                • 代码
                • 读取多个sheet
                • 自定义格式转换
                • 多行头
                • 读取表头数据
                • 异常处理
                  • 导出指定的列
                  • 调整指定列顺序
                  • 复杂头写入
                  • 图片导出
                  • 列宽、行高
                  • 动态表头
                  • 合并单元格
                  • web数据写出
                  • 模板格式导出
                    • 简单的Excel模板
                    • 实现模板填充
                    • 复杂的填充
                    • 总结一个工具类
                    • 参考资料

                      EasyExcel教程

                      本文使用的技术是Alibaba集团开源的EasyExcel技术,该技术是针对Apache POI技术的封装和优化,主要解决了POI技术的耗内存问题,并且提供了较好的API使用。

                      • 使用步骤繁琐
                      • 动态写出Excel操作非常麻烦
                      • 对于新手来说,很难在短时间内上手
                      • 读写时需要占用较大的内容,当数据量大时容器发生OOM
                        Maven依赖
                          
                                
                                    com.alibaba
                                    easyexcel
                                    2.2.7
                                
                        

                        EasyExcel API分析介绍

                        • Ø EasyExcel入口类,用于构建开始各种操作

                        • Ø ExcelReaderBuilder ExcelWriterBuilder 构建出一个 ReadWorkbook WriteWorkbook,可以理解成一个excel对象,一个excel只要构建一个

                        • Ø ExcelReaderSheetBuilder ExcelWriterSheetBuilder 构建出一个 ReadSheet WriteSheet对象,可以理解成excel里面的一页,每一页都要构建一个

                        • Ø ReadListener在每一行读取完毕后都会调用ReadListener来处理数据

                        • Ø WriteHandler在每一个操作包括创建单元格、创建表格等都会调用WriteHandler来处理数据

                        • Ø 所有配置都是继承的,Workbook的配置会被Sheet继承,所以在用EasyExcel设置参数的时候,在EasyExcel…sheet()方法之前作用域是整个sheet,之后针对单个sheet

                          EasyExcel 注解

                          • Ø ExcelProperty 指定当前字段对应excel中的那一列。可以根据名字或者Index去匹配。当然也可以不写,默认第一个字段就是index=0,以此类推。千万注意,要么全部不写,要么全部用index,要么全部用名字去匹配。千万别三个混着用,除非你非常了解源代码中三个混着用怎么去排序的。

                          • Ø ExcelIgnore 默认所有字段都会和excel去匹配,加了这个注解会忽略该字段

                          • Ø DateTimeFormat 日期转换,用String去接收excel日期格式的数据会调用这个注解。里面的value参照java.text.SimpleDateFormat

                          • Ø NumberFormat 数字转换,用String去接收excel数字格式的数据会调用这个注解。里面的value参照java.text.DecimalFormat

                          • Ø ExcelIgnoreUnannotated 默认不加ExcelProperty 的注解的都会参与读写,加了不会参与

                            通用参数

                            • Ø ReadWorkbook,ReadSheet 都会有的参数,如果为空,默认使用上级。

                            • Ø converter 转换器,默认加载了很多转换器。也可以自定义。

                            • Ø readListener 监听器,在读取数据的过程中会不断的调用监听器。

                            • Ø headRowNumber 需要读的表格有几行头数据。默认有一行头,也就是认为第二行开始起为数据。

                            • Ø head 与clazz二选一。读取文件头对应的列表,会根据列表匹配数据,建议使用class。

                            • Ø clazz 与head二选一。读取文件的头对应的class,也可以使用注解。如果两个都不指定,则会读取全部数据。

                            • Ø autoTrim 字符串、表头等数据自动trim

                            • Ø password 读的时候是否需要使用密码

                              ReadWorkbook(理解成excel对象)参数
                              • Ø excelType 当前excel的类型 默认会自动判断

                              • Ø inputStream 与file二选一。读取文件的流,如果接收到的是流就只用,不用流建议使用file参数。因为使用了inputStream easyexcel会帮忙创建临时文件,最终还是file

                              • Ø file 与inputStream二选一。读取文件的文件。

                              • Ø autoCloseStream 自动关闭流。

                              • Ø readCache 默认小于5M用 内存,超过5M会使用 EhCache,这里不建议使用这个参数。

                                ReadSheet(就是excel的一个Sheet)参数
                                • Ø sheetNo 需要读取Sheet的编码,建议使用这个来指定读取哪个Sheet

                                • Ø sheetName 根据名字去匹配Sheet,excel 2003不支持根据名字去匹配

                                  注解
                                  • Ø ExcelProperty index 指定写到第几列,默认根据成员变量排序。value指定写入的名称,默认成员变量的名字,多个value可以参照快速开始中的复杂头

                                  • Ø ExcelIgnore 默认所有字段都会写入excel,这个注解会忽略这个字段

                                  • Ø DateTimeFormat 日期转换,将Date写到excel会调用这个注解。里面的value参照java.text.SimpleDateFormat

                                  • Ø NumberFormat 数字转换,用Number写excel会调用这个注解。里面的value参照java.text.DecimalFormat

                                  • Ø ExcelIgnoreUnannotated 默认不加ExcelProperty 的注解的都会参与读写,加了不会参与

                                    参数
                                    通用参数
                                    • Ø WriteWorkbook,WriteSheet ,WriteTable都会有的参数,如果为空,默认使用上级。

                                    • Ø converter 转换器,默认加载了很多转换器。也可以自定义。

                                    • Ø writeHandler 写的处理器。可以实现WorkbookWriteHandler,SheetWriteHandler,RowWriteHandler,CellWriteHandler,在写入excel的不同阶段会调用

                                    • Ø relativeHeadRowIndex 距离多少行后开始。也就是开头空几行

                                    • Ø needHead 是否导出头

                                    • Ø head 与clazz二选一。写入文件的头列表,建议使用class。

                                    • Ø clazz 与head二选一。写入文件的头对应的class,也可以使用注解。

                                    • Ø autoTrim 字符串、表头等数据自动trim

                                      WriteWorkbook(理解成excel对象)参数
                                      • Ø excelType 当前excel的类型 默认xlsx

                                      • Ø outputStream 与file二选一。写入文件的流

                                      • Ø file 与outputStream二选一。写入的文件

                                      • Ø templateInputStream 模板的文件流

                                      • Ø templateFile 模板文件

                                      • Ø autoCloseStream 自动关闭流。

                                      • Ø password 写的时候是否需要使用密码

                                      • Ø useDefaultStyle 写的时候是否是使用默认头

                                        WriteSheet(就是excel的一个Sheet)参数
                                        • Ø sheetNo 需要写入的编码。默认0

                                        • Ø sheetName 需要些的Sheet名称,默认同sheetNo

                                          WriteTable(就把excel的一个Sheet,一块区域看一个table)参数
                                          • Ø tableNo 需要写入的编码。默认0
                                            EasyExcel用法指南
                                            简单的读取excel文件
                                            public void read() {
                                                String fileName = "demo.xlsx";
                                                // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
                                                // 参数一:读取的excel文件路径
                                                // 参数二:读取sheet的一行,将参数封装在DemoData实体类中
                                                // 参数三:读取每一行的时候会执行DemoDataListener监听器
                                                EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
                                            }
                                            
                                            简单的写入excel文件
                                            @Test
                                            public void simpleWrite() {
                                                String fileName = "demo.xlsx";
                                                // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
                                                // 如果这里想使用03 则 传入excelType参数即可
                                                // 参数一:写入excel文件路径
                                                // 参数二:写入的数据类型是DemoData
                                                // data()方法是写入的数据,结果是List集合
                                                EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
                                            }
                                            
                                            Web上传与下载
                                            /**
                                            	excel文件的下载
                                            */
                                            @GetMapping("download")
                                            public void download(HttpServletResponse response) throws IOException {
                                                response.setContentType("application/vnd.ms-excel");
                                                response.setCharacterEncoding("utf-8");
                                                response.setHeader("Content-disposition", "attachment;filename=demo.xlsx");
                                                EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
                                            }
                                            /**
                                            	excel文件的上传
                                            */
                                            @PostMapping("upload")
                                            @ResponseBody
                                            public String upload(MultipartFile file) throws IOException {
                                                EasyExcel.read(file.getInputStream(), DemoData.class, new DemoDataListener()).sheet().doRead();
                                                return "success";
                                            }
                                            
                                            详解读取Excel
                                            对象模型
                                            // 如果没有特殊说明,下面的案例将默认使用这个实体类
                                            public class DemoData {
                                                /**
                                                 * 强制读取第三个 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配
                                                 */
                                                @ExcelProperty(index = 2)
                                            	//我想接收百分比的数字
                                            	@NumberFormat("#.##%")
                                            	@ExcelProperty(value="浮点数标题", converter = CustomStringConverter.class)
                                                private Double doubleData;
                                                /**
                                                 * 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据
                                                 */
                                            	@ExcelProperty(value="字符串标题", converter = CustomStringConverter.class)
                                            	// converter属性定义自己的字符串转换器
                                                private String string;
                                            	
                                            	@DateTimeFormat("yyyy年MM月dd日 HH时mm分ss秒")
                                                @ExcelProperty("日期标题")
                                            	//这里用string 去接日期才能格式化
                                                private Date date;
                                            }
                                            
                                            监听器
                                            // 如果没有特殊说明,下面的案例将默认使用这个监听器
                                            public class DemoDataListener extends AnalysisEventListener {
                                                List list = new ArrayList();
                                                /**
                                                 * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
                                                 */
                                                public DemoDataListener() {}
                                                /**
                                                 * 这个每一条数据解析都会来调用
                                                 *
                                                 * @param data
                                                 * @param context
                                                 */
                                                @Override
                                                public void invoke(DemoData data, AnalysisContext context) {
                                                    System.out.println("解析到一条数据:{}", JSON.toJSONString(data));
                                                    list.add(data);
                                                }
                                                /**
                                                 * 所有数据解析完成了 都会来调用
                                                 *
                                                 * @param context
                                                 */
                                                @Override
                                                public void doAfterAllAnalysed(AnalysisContext context) {
                                                    System.out.println(JSON.toJSONString(list));
                                                }
                                            }
                                            
                                            代码
                                            @Test
                                            public void simpleRead() {
                                                // 写法1:
                                                String fileName = "demo.xlsx";
                                                // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
                                                EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
                                                // 写法2:
                                                fileName = "demo.xlsx";
                                                ExcelReader excelReader = EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).build();
                                                ReadSheet readSheet = EasyExcel.readSheet(0).build();
                                                excelReader.read(readSheet);
                                                // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
                                                excelReader.finish();
                                            }
                                            
                                            读取多个sheet
                                            @Test
                                            public void repeatedRead() {
                                                String fileName = "demo.xlsx";
                                                // 读取全部sheet
                                                // 这里需要注意 DemoDataListener的doAfterAllAnalysed 会在每个sheet读取完毕后调用一次。然后所有sheet都会往同一个DemoDataListener里面写
                                                EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).doReadAll();
                                                // 读取部分sheet
                                                fileName = "demo.xlsx";
                                                ExcelReader excelReader = EasyExcel.read(fileName).build();
                                                // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
                                                // readSheet参数设置读取sheet的序号
                                                ReadSheet readSheet1 =
                                                    EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
                                                ReadSheet readSheet2 =
                                                    EasyExcel.readSheet(1).head(DemoData.class).registerReadListener(new DemoDataListener()).build();
                                                // 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能
                                                excelReader.read(readSheet1, readSheet2);
                                                // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
                                                excelReader.finish();
                                            }
                                            
                                            自定义格式转换
                                            public class CustomStringStringConverter implements Converter {
                                                
                                            	@Override
                                                public Class supportJavaTypeKey() {
                                                    return String.class;
                                                }
                                                @Override
                                                public CellDataTypeEnum supportExcelTypeKey() {
                                                    return CellDataTypeEnum.STRING;
                                                }
                                                /**
                                                 * 这里读的时候会调用
                                                 *
                                                 * @param cellData
                                                 *            NotNull
                                                 * @param contentProperty
                                                 *            Nullable
                                                 * @param globalConfiguration
                                                 *            NotNull
                                                 * @return
                                                 */
                                                @Override
                                                public String convertToJavaData(CellData cellData, ExcelContentProperty contentProperty,
                                                    GlobalConfiguration globalConfiguration) {
                                                    return "自定义:" + cellData.getStringValue();
                                                }
                                                /**
                                                 * 这里是写的时候会调用 不用管
                                                 *
                                                 * @param value
                                                 *            NotNull
                                                 * @param contentProperty
                                                 *            Nullable
                                                 * @param globalConfiguration
                                                 *            NotNull
                                                 * @return
                                                 */
                                                @Override
                                                public CellData convertToExcelData(String value, ExcelContentProperty contentProperty,
                                                    GlobalConfiguration globalConfiguration) {
                                                    return new CellData(value);
                                                }
                                            }
                                            
                                            多行头
                                            @Test
                                            public void complexHeaderRead() {
                                                String fileName = "demo.xlsx";
                                                // 这里 需要指定读用哪个class去读,然后读取第一个sheet 
                                                EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet()
                                                    // 这里可以设置1,因为头就是一行。如果多行头,可以设置其他值。不传入默认1行
                                                    .headRowNumber(1).doRead();
                                            }
                                            
                                            读取表头数据

                                            覆盖监听器invokeHeadMap方法

                                            /**
                                             * 这里会一行行的返回头
                                             * 监听器只需要重写这个方法就可以读取到头信息
                                             * @param headMap
                                             * @param context
                                             */
                                            @Override
                                            public void invokeHeadMap(Map headMap, AnalysisContext context) {
                                                LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap));
                                            }
                                            

                                            异常处理

                                            覆盖监听器onException方法

                                            /**
                                            * 监听器实现这个方法就可以在读取数据的时候获取到异常信息
                                            */
                                            @Override
                                            public void onException(Exception exception, AnalysisContext context) {
                                                LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage());
                                                // 如果是某一个单元格的转换异常 能获取到具体行号
                                                // 如果要获取头的信息 配合invokeHeadMap使用
                                                if (exception instanceof ExcelDataConvertException) {
                                                    ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
                                                    LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(),
                                                        excelDataConvertException.getColumnIndex());
                                                }
                                            }
                                            
                                            导出指定的列
                                            @Test
                                            public void excludeOrIncludeWrite() {
                                            	
                                                String fileName = "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
                                                // 忽略 date 不导出
                                                Set excludeColumnFiledNames = new HashSet();
                                                excludeColumnFiledNames.add("date");
                                                // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
                                                EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("忽略date")
                                                    .doWrite(data());
                                                fileName = "excludeOrIncludeWrite" + System.currentTimeMillis() + ".xlsx";
                                                // 根据用户传入字段 假设我们只要导出 date
                                                Set includeColumnFiledNames = new HashSet();
                                                includeColumnFiledNames.add("date");
                                                // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
                                                EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("导出date")
                                                    .doWrite(data());
                                            }
                                            
                                            调整指定列顺序
                                            public class IndexData {
                                                /**
                                                * 导出的excel第二列和第四列将空置
                                                */
                                                @ExcelProperty(value = "字符串标题", index = 0)
                                                private String string;
                                                @ExcelProperty(value = "日期标题", index = 2)
                                                private Date date;
                                                @ExcelProperty(value = "浮点数标题", index = 4)
                                                private Double doubleData;
                                            }
                                            
                                            复杂头写入
                                            public class ComplexHeadData {
                                                /**
                                                * 主标题 将整合为一个单元格效果如下:
                                                * —————————————————————————
                                                * |          主标题        |
                                                * —————————————————————————
                                                * |字符串标题|日期标题|数字标题|
                                                * —————————————————————————
                                                */
                                                @ExcelProperty({"主标题", "字符串标题"})
                                                private String string;
                                                @ExcelProperty({"主标题", "日期标题"})
                                                private Date date;
                                                @ExcelProperty({"主标题", "数字标题"})
                                                private Double doubleData;
                                            }
                                            

                                            前面属于主标题,后面属于副标题

                                            图片导出
                                            @Data
                                            @ContentRowHeight(200)
                                            @ColumnWidth(200 / 8)
                                            public class ImageData {
                                                // 图片导出方式有5种
                                                private File file;
                                                private InputStream inputStream;
                                                /**
                                                 * 如果string类型 必须指定转换器,string默认转换成string,该转换器是官方支持的
                                                 */
                                                @ExcelProperty(converter = StringImageConverter.class)
                                                private String string;
                                                private byte[] byteArray;
                                                /**
                                                 * 根据url导出 版本2.1.1才支持该种模式
                                                 */
                                                private URL url;
                                            }
                                             @Test
                                            public void imageWrite() throws Exception {
                                                String fileName = "imageWrite" + System.currentTimeMillis() + ".xlsx";
                                                // 如果使用流 记得关闭
                                                InputStream inputStream = null;
                                                try {
                                                    List list = new ArrayList();
                                                    ImageData imageData = new ImageData();
                                                    list.add(imageData);
                                                    String imagePath = "converter" + File.separator + "img.jpg";
                                                    // 放入五种类型的图片 根据实际使用只要选一种即可
                                                    imageData.setByteArray(FileUtils.readFileToByteArray(new File(imagePath)));
                                                    imageData.setFile(new File(imagePath));
                                                    imageData.setString(imagePath);
                                                    inputStream = FileUtils.openInputStream(new File(imagePath));
                                                    imageData.setInputStream(inputStream);
                                                    imageData.setUrl(new URL(
                                                        "https://raw.githubusercontent.com/alibaba/easyexcel/master/src/test/resources/converter/img.jpg"));
                                                    EasyExcel.write(fileName, ImageData.class).sheet().doWrite(list);
                                                } finally {
                                                    if (inputStream != null) {
                                                        inputStream.close();
                                                    }
                                                }
                                            }
                                            
                                            列宽、行高
                                            @Data
                                            @ContentRowHeight(10)
                                            @HeadRowHeight(20)
                                            @ColumnWidth(25)
                                            public class WidthAndHeightData {
                                                @ExcelProperty("字符串标题")
                                                private String string;
                                                @ExcelProperty("日期标题")
                                                private Date date;
                                                /**
                                                 * 宽度为50,覆盖上面的宽度25
                                                 */
                                                @ColumnWidth(50)
                                                @ExcelProperty("数字标题")
                                                private Double doubleData;
                                            }
                                            
                                            • @HeadRowHeight(value = 35) // 表头行高
                                            • @ContentRowHeight(value = 25) // 内容行高
                                            • @ColumnWidth(value = 50) // 列宽

                                              此外还有,自适应宽度,但是这个不是特别精确

                                              @Test
                                              void contextLoads() {
                                                  EasyExcel.write("自适应.xlsx", Student.class)
                                                      .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                                                      .sheet()
                                                      .doWrite(getData());
                                              }
                                              
                                              动态表头
                                              @Test
                                              public void dynamicHeadWrite() {
                                                  String fileName = "dynamicHeadWrite" + System.currentTimeMillis() + ".xlsx";
                                                  EasyExcel.write(fileName)
                                                      // 这里放入动态头
                                                      .head(head()).sheet("模板")
                                                      // 当然这里数据也可以用 List> 去传入
                                                      .doWrite(data());
                                              }
                                              // 动态表头的数据格式List>
                                              private List> head() {
                                                  List> list = new ArrayList>();
                                                  List head0 = new ArrayList();
                                                  head0.add("字符串" + System.currentTimeMillis());
                                                  List head1 = new ArrayList();
                                                  head1.add("数字" + System.currentTimeMillis());
                                                  List head2 = new ArrayList();
                                                  head2.add("日期" + System.currentTimeMillis());
                                                  list.add(head0);
                                                  list.add(head1);
                                                  list.add(head2);
                                                  return list;
                                              }
                                              
                                              合并单元格
                                               @Test
                                               public void mergeWrite() {
                                                   String fileName = "mergeWrite" + System.currentTimeMillis() + ".xlsx";
                                                   LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0);
                                                   EasyExcel.write(fileName, DemoData.class).registerWriteHandler(loopMergeStrategy).sheet("合并单元格")
                                                       .doWrite(data());
                                               }
                                              
                                              • 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写

                                              • 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭

                                                web数据写出
                                                @GetMapping("download")
                                                public void download(HttpServletResponse response) throws IOException {
                                                    response.setContentType("application/vnd.ms-excel");
                                                    response.setCharacterEncoding("utf-8");
                                                    // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
                                                    String fileName = URLEncoder.encode("数据写出", "UTF-8");
                                                    response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
                                                    EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
                                                }
                                                
                                                模板格式导出

                                                如果需要横向填充只需要模板设置好就可以。

                                                简单的Excel模板

                                                【Alibaba工具型技术系列】「EasyExcel技术专题」实战技术针对于项目中常用的Excel操作指南,第1张

                                                public class FillData {
                                                    private String name;
                                                    private double number;
                                                    // getting setting
                                                }
                                                
                                                实现模板填充
                                                @Test
                                                public void simpleFill() {
                                                    String templateFileName = "simple.xlsx";
                                                    // 方案1 根据对象填充
                                                    String fileName = System.currentTimeMillis() + ".xlsx";
                                                    // 这里 会填充到第一个sheet, 然后文件流会自动关闭
                                                    FillData fillData = new FillData();
                                                    fillData.setName("知春秋");
                                                    fillData.setNumber(25);
                                                    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(fillData);
                                                    // 方案2 根据Map填充
                                                    fileName = System.currentTimeMillis() + ".xlsx";
                                                    // 这里 会填充到第一个sheet, 然后文件流会自动关闭
                                                    Map map = new HashMap();
                                                    map.put("name", "知春秋");
                                                    map.put("number", 25);
                                                    EasyExcel.write(fileName).withTemplate(templateFileName).sheet().doFill(map);
                                                }
                                                
                                                • 模板注意 用{} 来表示你要用的变量 如果本来就有"{“,”}" 特殊字符 用"{“,”}"代替
                                                  复杂的填充

                                                  使用List集合的方法批量写入数据,点表示该参数是集合

                                                  @Test
                                                  public void complexFill() {
                                                      String templateFileName = "complex.xlsx";
                                                      String fileName = System.currentTimeMillis() + ".xlsx";
                                                      ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build();
                                                      WriteSheet writeSheet = EasyExcel.writerSheet().build();
                                                      // 如果数据量大 list不是最后一行 参照下一个
                                                      FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build();
                                                      excelWriter.fill(data(), fillConfig, writeSheet);
                                                      excelWriter.fill(data(), fillConfig, writeSheet);
                                                      // 其他参数可以使用Map封装
                                                      Map map = new HashMap();
                                                      excelWriter.fill(map, writeSheet);
                                                      excelWriter.finish();
                                                  }
                                                  
                                                  • 模板注意 用{} 来表示你要用的变量 如果本来就有"{“,”}" 特殊字符 用"{“,”}"代替

                                                  • // {} 代表普通变量 {.} 代表是list的变量
                                                    
                                                  • // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。

                                                  • // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用
                                                    
                                                  • // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存
                                                    

                                                    总结一个工具类

                                                    public class ExcelUtil {
                                                        /**
                                                         * 写出一个 excel 文件到本地
                                                         * 
                                                    * 将类型所有加了 @ExcelProperty 注解的属性全部写出 * * @param fileName 文件名 不要后缀 * @param sheetName sheet名 * @param data 写出的数据 * @param clazz 要写出数据类的Class类型对象 * @param 写出的数据类型 */ public static void writeExcel(String fileName, String sheetName, List data, Class clazz) { writeExcel(null, fileName, sheetName, data, clazz); } /** * 按照指定的属性名进行写出 一个 excel * * @param attrName 指定的属性名 必须与数据类型的属性名一致 * @param fileName 文件名 不要后缀 * @param sheetName sheet名 * @param data 要写出的数据 * @param clazz 要写出数据类的Class类型对象 * @param 要写出的数据类型 */ public static void writeExcel(Set attrName, String fileName, String sheetName, List data, Class clazz) { fileName = StringUtils.isBlank(fileName) ? "学生管理系统" : fileName; sheetName = StringUtils.isBlank(sheetName) ? "sheet0" : sheetName; try(FileOutputStream fos = new FileOutputStream(fileName)) { write(fos,attrName,sheetName,data,clazz); } catch (Exception exception) { exception.printStackTrace(); } } /** * 读取 指定格式的 excel文档 * * @param fileName 文件名 * @param clazz 数据类型的class对象 * @param 数据类型 * @return */ public static List readExcel(String fileName, Class clazz) { return readExcel(fileName, clazz, null); } /** * 取 指定格式的 excel文档 * 注意一旦传入自定义监听器,则返回的list为空,数据需要在自定义监听器里面获取 * * @param fileName 文件名 * @param clazz 数据类型的class对象 * @param readListener 自定义监听器 * @param 数据类型 * @return */ public static List readExcel(String fileName, Class clazz, ReadListener readListener) { try(FileInputStream fis = new FileInputStream(fileName)) { return read(fis,clazz,readListener); } catch (Exception exception) { exception.printStackTrace(); } } /** * 导出 一个 excel * 导出excel所有数据 * @param response * @param fileName 件名 最好为英文,不要后缀名 * @param sheetName sheet名 * @param data 要写出的数据 * @param clazz 要写出数据类的Class类型对象 * @param 要写出的数据类型 */ public static void export(HttpServletResponse response, String fileName, String sheetName, List data, Class clazz) { export(response, null, fileName, sheetName, data, clazz); } /** * 按照指定的属性名进行写出 一个 excel * * @param response * @param attrName 指定的属性名 必须与数据类型的属性名一致 * @param fileName 文件名 最好为英文,不要后缀名 * @param sheetName sheet名 * @param data 要写出的数据 * @param clazz 要写出数据类的Class类型对象 * @param 要写出的数据类型 */ public static void export(HttpServletResponse response, Set attrName, String fileName, String sheetName, List data, Class clazz) { fileName = StringUtils.isBlank(fileName) ? "student-system-manager" : fileName; sheetName = StringUtils.isBlank(sheetName) ? "sheet0" : sheetName; response.setContentType("application/vnd.ms-excel;charset=utf-8"); response.setCharacterEncoding("utf-8"); response.addHeader("Content-disposition", "attachment;filename=" + fileName + ExcelTypeEnum.XLSX.getValue()); try(OutputStream os = response.getOutputStream()) { write(os,attrName,sheetName,data,clazz); } catch (IOException e) { e.printStackTrace(); } } /** * 接收一个excel文件,并且进行解析 * 注意一旦传入自定义监听器,则返回的list为空,数据需要在自定义监听器里面获取 * @param multipartFile excel文件 * @param clazz 数据类型的class对象 * @param readListener 监听器 * @param * @return */ public static List importExcel(MultipartFile multipartFile,Class clazz,ReadListener readListener) { try(InputStream inputStream = multipartFile.getInputStream()) { return read(inputStream,clazz,readListener); } catch (IOException e) { e.printStackTrace(); } } private static void write(OutputStream os, Set attrName, String sheetName, List data, Class clazz) { ExcelWriterBuilder write = EasyExcel.write(os, clazz); // 如果没有指定要写出那些属性数据,则写出全部 if (!CollectionUtils.isEmpty(attrName)) { write.includeColumnFiledNames(attrName); } write.registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet(sheetName).doWrite(data); } private static List read(InputStream in,Class clazz, ReadListener readListener) { List list = new ArrayList<>(); Optional optional = Optional.ofNullable(readListener); EasyExcel.read(in, clazz, optional.orElse(new AnalysisEventListener() { @Override public void invoke(T data, AnalysisContext context) { list.add(data); } @Override public void doAfterAllAnalysed(AnalysisContext context) { System.out.println("解析完成"); } })).sheet().doRead(); return list; } }

                                                    参考资料

                                                    • https://github.com/alibaba/easyexcel/blob/master/docs/API.md 官方api
                                                    • https://github.com/alibaba/easyexcel easyexcel github 地址
                                                    • https://blog.csdn.net/sinat_32366329/article/details/103109058 easyexcel总结
                                                    • https://alibaba-easyexcel.github.io/index.html 官方示例

网友评论

搜索
最新文章
热门文章
热门标签
 
 中年女人梦见头发白了  梦见女人生孩子难产是什么意思  怀孕梦见蛇是男孩还是女孩