热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Alibaba工具型技术系列,实战技术针对于项目中常用的Excel操作指南

ExcelIgnoreUnannotated默认不加ExcelProperty的注解的都会参与读写,加了不会参与通用参数ReadWorkbook,ReadSheet




  • Ø 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 模板

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();``}

.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();``}`







推荐阅读
  • 当unique验证运到图片上传时
    2019独角兽企业重金招聘Python工程师标准model:public$imageFile;publicfunctionrules(){return[[[na ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • CSS高级技巧:动态高亮当前页面导航
    本文介绍了如何使用CSS实现网站导航栏中当前页面的高亮显示,提升用户体验。通过为每个页面的body元素添加特定ID,并结合导航项的类名,可以轻松实现这一功能。 ... [详细]
  • 本文提供了多种方法来计算给定年份和月份的起始日和结束日,并进一步探讨了如何根据年、月、周获取特定周的起始日和结束日。 ... [详细]
  • 深入理解String.Format()方法的应用
    在.NET框架中,String.Format()方法是一种非常实用的工具,它能够帮助开发者以灵活多样的方式格式化字符串。本文将通过一个具体的示例,详细介绍如何利用String.Format()方法处理数值、日期时间和枚举类型的格式化。 ... [详细]
  • 主板市盈率、市净率及股息率的自动化抓取
    本文介绍了如何通过Python脚本自动从中国指数有限公司网站抓取主板的市盈率、市净率和股息率等关键财务指标,并将这些数据存储到CSV文件中。涉及的技术包括网页解析、正则表达式以及异常处理。 ... [详细]
  • 本文详细介绍了ASP.NET缓存的基本概念和使用方法,包括输出缓存、数据缓存及其高级特性,如缓存依赖、自定义缓存和缓存配置文件等。通过合理利用这些缓存技术,可以显著提升Web应用程序的性能。 ... [详细]
  • 本文详细介绍了如何在Kendo UI for jQuery的数据管理组件中,将行标题字段呈现为锚点(即可点击链接),帮助开发人员更高效地实现这一功能。通过具体的代码示例和解释,即使是新手也能轻松掌握。 ... [详细]
  • docker镜像重启_docker怎么启动镜像dock ... [详细]
  • Django 使用slug field时遇到的问题 ... [详细]
  • Django Token 认证详解与 HTTP 401、403 状态码的区别
    本文详细介绍了如何在 Django 中配置和使用 Token 认证,并解释了 HTTP 401 和 HTTP 403 状态码的区别。通过具体的代码示例,帮助开发者理解认证机制及权限控制。 ... [详细]
  • 本文旨在探讨如何利用决策树算法实现对男女性别的分类。通过引入信息熵和信息增益的概念,结合具体的数据集,详细介绍了决策树的构建过程,并展示了其在实际应用中的效果。 ... [详细]
  • java文本编辑器,java文本编辑器设计思路
    java文本编辑器,java文本编辑器设计思路 ... [详细]
  • Logback使用小结
    1一定要使用slf4j的jar包,不要使用apachecommons的jar。否则滚动生成文件不生效,不滚动的时候却生效~~importorg.slf ... [详细]
  • 深入浅出TensorFlow数据读写机制
    本文详细介绍TensorFlow中的数据读写操作,包括TFRecord文件的创建与读取,以及数据集(dataset)的相关概念和使用方法。 ... [详细]
author-avatar
LiangChao
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有