【说明】废话不多说,直接就是干,⛳️
1️⃣:这里我就直接贴出用到的相关maven坐标了
<dependency>
<groupId>cn.hutoolgroupId>
<artifactId>hutool-allartifactId>
<version>5.3.8version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poiartifactId>
<version>4.1.2version>
dependency>
<dependency>
<groupId>org.apache.poigroupId>
<artifactId>poi-ooxmlartifactId>
<version>4.1.2version>
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","施工单位");
}