springboot实现excel的导出(自适应列宽实现)
【说明】废话不多说,直接就是干,⛳️
首先是环境准备
1️⃣:这里我就直接贴出用到的相关maven坐标了
<dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.3.8</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>4.1.2</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>4.1.2</version> </dependency>
【警告】这里根据自己的需求确定版本号
接下来就是上正餐了
【说明】首先对于excel的导出,前端调用接口最后的响应类型要为blob,不然你导出的excel会显示损坏以及打不开
1️⃣: 直接贴代码如下:
public void exportFundOutExcel(HttpServletResponse response, @RequestBody Map<String, Object> data) { ExcelWriter writer = ExcelUtil.getBigWriter(); // 设置默认的行高 writer.setDefaultRowHeight(20); try { // 获取数据 List<Map<String, Object>> list = service.getList(data); String messages = "这是excel的第一行(内容自己看)"; // 这里正常情况是要放到常量类中的,这里为了大家看清楚,或者复制直接用,这里的key要对应上面查出来的Map中的key,这里的value对应的就是你的excel表头了 public static final Map<String,String> FUNDS_OUT_EXCEL_MAP = new LinkedHashMap<>(3); static { FUNDS_OUT_EXCEL_MAP.put("projectName","所属项目"); FUNDS_OUT_EXCEL_MAP.put("managementUnit","建设单位"); FUNDS_OUT_EXCEL_MAP.put("constructionUnit","施工单位"); } // 表头信息 writer.merge(FUNDS_OUT_EXCEL_MAP.size() - 1 , messages , true); FUNDS_OUT_EXCEL_MAP.forEach(writer::addHeaderAlias); // 仅仅获取取别名的字段 writer.setOnlyAlias(true); // 一定要先进性写入数据,再设置列宽 writer.write(list, true); // 获取当前工作表,需要注意的是,SXSSFSheet 在处理大数据量的 Excel 文件时非常有用,但对于小型文件,使用 XSSFSheet(基于内存)可能更为合适。 SXSSFSheet sheet = (SXSSFSheet) writer.getSheet(); // 这里的代码就是实现自适应列宽 //-------------------------------- writer.setSheet(sheet); // 这里默认会只显示后100行数据,所以在设置的时候会Row row = this.sheet.getRow(rownum);row为null // writer.setRowHeight(3,30000); response.resetBuffer(); response.setContentType("application/octet-stream;charset=utf-8"); response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("测试.xlsx", "UTF-8")); writer.flush(response.getOutputStream()); } catch (Exception e) { // 异常处理 } finally { // 关闭writer,释放内存 writer.close(); } }
下面的两种方式都可以放到上面的代码的// 这里的代码就是实现自适应列宽
//--------------------------------这个下
2️⃣:如果是excel中没有涉及到中文的话,那么可以用这种方式实现
// 这里不进行追踪的话会报错,Could not auto-size column. Make sure the column was tracked prior to auto-sizing the column. // 跟踪所有列 sheet.trackAllColumnsForAutoSizing(); for (int i = 0; i < LotConstants.FUNDS_OUT_EXCEL_MAP.size(); i++) { sheet.autoSizeColumn(i); } int columnCount = LotConstants.FUNDS_OUT_EXCEL_MAP.size();
上面的代码我也都做了注释,大致就是必须要先执行追踪,然后再执行下面的,这个对于非中文的excel还是能做到列宽自适应的,已验证
但是对于大部分的情况下,都是含有中文的,那么就需要自己去实现了,目前我还没发现有自带的,具体实现如下
// 获取最大列宽 for (int i = 0; i < columnCount; i++) { final int[] maxColumnWidth = {0}; int finalI = i; // 流处理,异步设置最大列宽 IntStream.range(0, sheet.getLastRowNum() + 1).parallel().forEach(rowIndex -> { Row row = sheet.getRow(rowIndex); Cell cell = row.getCell(finalI); if (cell != null) { // 这里选择将所有格式的都转化为String类型,防止报错->Cannot get a STRING value from a NUMERIC cell DataFormatter dataFormatter = new DataFormatter(); String cellValue = dataFormatter.formatCellValue(cell); // String cellValue = cell.getStringCellValue(); int cellWidth = cellValue.getBytes(StandardCharsets.UTF_8).length; if (cellWidth > maxColumnWidth[0]) { maxColumnWidth[0] = cellWidth; } } }); // 设置列宽,这里之所以要乘256,点进去这个方法可以看到Set the width (in units of 1256th of a character width) The maximum column width for an individual cell is 255 characters. // 至于200就是偏移量 sheet.setColumnWidth(i, maxColumnWidth[0] * 256 + 200); }
完事收工,亲测可用,如果不行请call我,一定是你哪里cv错了
补充一下上面的FUNDS_OUT_EXCEL_MAP常量,这个其实就是为了设置excel的表头,以及对应我们查询出来的字段名,大致如下:
public static final Map<String,String> FUNDS_OUT_EXCEL_MAP = new LinkedHashMap<>(3); static { FUNDS_OUT_EXCEL_MAP.put("projectName","所属项目"); FUNDS_OUT_EXCEL_MAP.put("managementUnit","建设单位"); FUNDS_OUT_EXCEL_MAP.put("constructionUnit","施工单位"); }