excel是我们工作最常见的应用,不管是对于文档打印还是操作都很方便,并且在开发java中,也可以对excel进行操作,那java怎么操作excel?下面来我们就来给大家讲解一下java操作excel的几种方式。
Java操作Excel三种方式POI、Hutool、EasyExcel。
1.ApachePOI
Apache POI 是用Java编写的免费开源的跨平台的 Java API,Apache POI提供API给Java程式对Microsoft Office格式档案读和写的功能。POI为“Poor Obfuscation Implementation”的首字母缩写,意为“简洁版的模糊实现”。
ApachePOI功能结构:
HSSF [1] - 提供读写Microsoft Excel XLS格式档案的功能。 XSSF [1] - 提供读写Microsoft Excel OOXML XLSX格式档案的功能。 HWPF [1] - 提供读写Microsoft Word DOC格式档案的功能。 HSLF [1] - 提供读写Microsoft PowerPoint格式档案的功能。 HDGF [1] - 提供读Microsoft Visio格式档案的功能。 HPBF [1] - 提供读Microsoft Publisher格式档案的功能。 HSMF [1] - 提供读Microsoft Outlook格式档案的功能。
2.Hutool简介
Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。
Hutool中的工具方法来自每个用户的精雕细琢,它涵盖了Java开发底层代码中的方方面面,它既是大型项目开发中解决小问题的利器,也是小型项目中的效率担当;
Hutool是项目中“util”包友好的替代,它节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务,同时可以最大限度的避免封装不完善带来的bug。
3.EasyExcel简介
EasyExcel是阿里巴巴开源的一款Excel操作工具,简单易用,功能强大,节省内存,性能彪悍。
HutoolExcel实现验证
Mave依赖配置
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>3.0.5</version> </dependency>
ByteToInputStreamUtil
package com.zrj.easyexcel.excel; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.InputStream; /** * 输入流与字节转换 * * @author zrj * @since 2021/12/27 **/ public class ByteToInputStreamUtil { /** * 字节转输入流 * * @param buf * @return java.io.InputStream */ public static InputStream byte2Input(byte[] buf) { return new ByteArrayInputStream(buf); } /** * 输入流转字节 * * @param inStream * @return byte[] */ public static byte[] input2byte(InputStream inStream) throws Exception { ByteArrayOutputStream swapStream = new ByteArrayOutputStream(); byte[] buff = new byte[100]; int rc = 0; while ((rc = inStream.read(buff, 0, 100)) > 0) { swapStream.write(buff, 0, rc); } byte[] in2b = swapStream.toByteArray(); return in2b; } }
CommentWriteHandler
package com.zrj.easyexcel.excel; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.excel.write.handler.AbstractRowWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import org.apache.poi.hssf.usermodel.HSSFClientAnchor; import org.apache.poi.hssf.usermodel.HSSFRichTextString; import org.apache.poi.ss.usermodel.*; import org.apache.poi.xssf.usermodel.XSSFClientAnchor; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; /** * 批注处理器 * * @author zrj * @since 2021/12/29 **/ public class CommentWriteHandler extends AbstractRowWriteHandler { /** * sheet名称KEY */ public static final String SHEETNAME_NAME = "sheetName"; /** * 文档后缀名 */ private String extension; /** * 列索引key */ public static final String COLINDEX_NAME = "colIndex"; /** * 行索引key */ public static final String ROWINDEX_NAME = "rowIndex"; /** * 批注内容key */ public static final String COMMENTCONTENT_NAME = "commentContent"; /** * sheet页名称列表 */ private List < String > sheetNameList; /** * 批注集合 */ List < Map < String, String >> commentList = new ArrayList < > (10); /** * CommentWriteHandler * * @param commentList * @param extension */ public CommentWriteHandler(List < Map < String, String >> commentList, String extension) { this.commentList = commentList != null && commentList.size() > 0 ? commentList.stream() .filter(x - > x.keySet() .contains(SHEETNAME_NAME) == true && x.get(SHEETNAME_NAME) != null && StrUtil.isNotBlank(x.get(SHEETNAME_NAME) .toString()) && x.keySet() .contains(COLINDEX_NAME) == true && x.get(COLINDEX_NAME) != null && StrUtil.isNotBlank(x.get(COLINDEX_NAME) .toString()) && x.keySet() .contains(ROWINDEX_NAME) == true && x.get(ROWINDEX_NAME) != null && StrUtil.isNotBlank(x.get(ROWINDEX_NAME) .toString()) && x.keySet() .contains(COMMENTCONTENT_NAME) == true && x.get(COMMENTCONTENT_NAME) != null && StrUtil.isNotBlank(x.get(COMMENTCONTENT_NAME) .toString()) ) .collect(Collectors.toList()) : new ArrayList < > (); sheetNameList = this.commentList.stream() .map(x - > x.get(SHEETNAME_NAME) .toString()) .collect(Collectors.toList()); this.extension = extension; } /** * 生成批注信息 * * @param sheetName sheet页名称 * @param rowIndex 行号 * @param columnIndex 列号 * @param commentContent 批注内容 * @return */ public static Map < String, String > createCommentMap(String sheetName, int rowIndex, int columnIndex, String commentContent) { Map < String, String > map = new HashMap < > (); //sheet页名称 map.put(SHEETNAME_NAME, sheetName); //行号 map.put(ROWINDEX_NAME, rowIndex + ""); //列号 map.put(COLINDEX_NAME, columnIndex + ""); //批注内容 map.put(COMMENTCONTENT_NAME, commentContent); return map; } /** * 功能描述 * @param writeSheetHolder * @param writeTableHolder * @param row * @param relativeRowIndex * @param isHead * @return void */ @Override public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row , Integer relativeRowIndex, Boolean isHead) { Sheet sheet = writeSheetHolder.getSheet(); //不需要添加批注,或者当前sheet页不需要添加批注 if (commentList == null || commentList.size() <= 0 || sheetNameList.contains(sheet.getSheetName()) == false) { return; } //获取当前行的批注信息 List < Map < String, String >> rowCommentList = commentList.stream() .filter(x - > StrUtil.equals(x.get(SHEETNAME_NAME) .toString(), sheet.getSheetName()) && relativeRowIndex == Integer.parseInt(x.get(ROWINDEX_NAME))) .collect(Collectors.toList()); //当前行没有批注信息 if (rowCommentList == null || rowCommentList.size() <= 0) { return; } List < String > colIndexList = rowCommentList.stream() .map(x - > x.get(COLINDEX_NAME)) .distinct() .collect(Collectors.toList()); for (String colIndex: colIndexList) { //同一单元格的批注信息 List < Map < String, String >> cellCommentList = rowCommentList.stream() .filter(x - > StrUtil.equals(colIndex, x.get(COLINDEX_NAME))) .collect(Collectors.toList()); if (CollectionUtil.isEmpty(cellCommentList)) { continue; } //批注内容拼成一条 String commentContent = cellCommentList.stream() .map(x - > x.get(COMMENTCONTENT_NAME)) .collect(Collectors.joining()); Cell cell = row.getCell(Integer.parseInt(colIndex)); addComment(cell, commentContent, extension); } //删除批注信息 commentList.remove(rowCommentList); //重新获取要添加的sheet页姓名 sheetNameList = commentList.stream() .map(x - > x.get(SHEETNAME_NAME) .toString()) .collect(Collectors.toList()); } /** * 给Cell添加批注 * * @param cell 单元格 * @param value 批注内容 * @param extension 扩展名 */ public static void addComment(Cell cell, String value, String extension) { Sheet sheet = cell.getSheet(); cell.removeCellComment(); if ("xls".equals(extension)) { ClientAnchor anchor = new HSSFClientAnchor(); // 关键修改 anchor.setDx1(0); anchor.setDx2(0); anchor.setDy1(0); anchor.setDy2(0); anchor.setCol1(cell.getColumnIndex()); anchor.setRow1(cell.getRowIndex()); anchor.setCol2(cell.getColumnIndex() + 5); anchor.setRow2(cell.getRowIndex() + 6); // 结束 Drawing drawing = sheet.createDrawingPatriarch(); Comment comment = drawing.createCellComment(anchor); // 输入批注信息 comment.setString(new HSSFRichTextString(value)); // 将批注添加到单元格对象中 cell.setCellComment(comment); } else if ("xlsx".equals(extension)) { ClientAnchor anchor = new XSSFClientAnchor(); // 关键修改 anchor.setDx1(0); anchor.setDx2(0); anchor.setDy1(0); anchor.setDy2(0); anchor.setCol1(cell.getColumnIndex()); anchor.setRow1(cell.getRowIndex()); anchor.setCol2(cell.getColumnIndex() + 5); anchor.setRow2(cell.getRowIndex() + 6); // 结束 Drawing drawing = sheet.createDrawingPatriarch(); Comment comment = drawing.createCellComment(anchor); // 输入批注信息 comment.setString(new XSSFRichTextString(value)); // 将批注添加到单元格对象中 cell.setCellComment(comment); } } }
EasyExcelUtils
package com.zrj.easyexcel.excel; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.builder.ExcelWriterBuilder; import com.alibaba.excel.write.metadata.WriteSheet; import com.zrj.easyexcel.entity.DemoData; import com.zrj.easyexcel.excel.read.ReadTest; import com.zrj.easyexcel.excel.write.WriteTest; import org.junit.Test; import java.io.File; import java.util.*; /** * EasyExcel测试类 * * @author zrj * @since 2021/12/29 **/ public class EasyExcelUtils { /** * EasyExcel读写测试类 */ @Test public void easyExcelReadWriteTest() { //EasyExcel读测试类 ReadTest readTest = new ReadTest(); //EasyExcel写测试类 WriteTest writeTest = new WriteTest(); } /** * EasyExcel 批量添加批注 */ @Test public void batchAddCommentTest() { try { //构建数据 List < DemoData > demoDataList = new ArrayList < > (10); demoDataList.add(DemoData.builder() .string("张三") .date(new Date()) .doubleData(3.14) .build()); demoDataList.add(DemoData.builder() .string("王五") .date(new Date()) .doubleData(6.68) .build()); demoDataList.add(DemoData.builder() .string("赵六") .date(new Date()) .doubleData(8.32) .build()); demoDataList.add(DemoData.builder() .string("李四") .date(new Date()) .doubleData(8.66) .build()); //定义文件路径 String filepath = System.getProperty("user.dir") + File.separator + "excel" + File.separator + "EasyExcelCommentWriteTest3.xlsx"; String sheetName = "批注模板"; List < Map < String, String >> commentList = new ArrayList < > (); commentList.add(CommentWriteHandler.createCommentMap(sheetName, 0, 1, "第一条批注。")); commentList.add(CommentWriteHandler.createCommentMap(sheetName, 1, 1, "第二条批注。")); // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 这里要注意inMemory 要设置为true,才能支持批注。目前没有好的办法解决 不在内存处理批注。这个需要自己选择。 EasyExcel.write(filepath, DemoData.class) .inMemory(Boolean.TRUE) .registerWriteHandler(new CommentWriteHandler(commentList, "xlsx")) .sheet(sheetName) .doWrite(demoDataList); System.out.println("批注模板完成,模板地址:" + filepath); } catch (Exception e) { e.printStackTrace(); } } }
Java操作Excel就是POI、Hutool以及EasyExcel这三种方式,我们可以选择任意一种进行操作,感兴趣的朋友可以自己尝试一下哦!最后大家如果想要了解更多java实例知识,敬请关注奇Q工具网。
推荐阅读: