Hutool工具类BigExcelWriter导出Excel调用autoSizeColumnAll()方法无法自适应列宽度的问题
看的这个人的
https://blog.csdn.net/weixin_43466094/article/details/108940721
没用啊。还是不自适应。升了包的版本也是无效。看起来比不设置稍微列宽长了一点而已
后来看github上有issue
https://github.com/looly/hutool/issues/1210
以及百度,是中文计算长度的原因
解决:
新建一个MyExcelWriter.java继承BigExcelWriter,重写autoSizeColumnAll方法
public static MyExcelWriter getBigWriter() {
try {
return new MyExcelWriter();
} catch (NoClassDefFoundError var1) {
throw new DependencyException((Throwable) ObjectUtil.defaultIfNull(var1.getCause(), var1), "You need to add dependency of 'poi-ooxml' to your project, and version >= 4.1.2", new Object[0]);
}
}
@Override
public BigExcelWriter autoSizeColumnAll() {
final SXSSFSheet sheet = (SXSSFSheet)this.sheet;
sheet.trackAllColumnsForAutoSizing();
super.autoSizeColumnAll();
for (int i = 0; i <sheet.getRow(sheet.getLastRowNum()).getPhysicalNumberOfCells(); i++) {
// 解决自动设置列宽中文失效的问题
sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 17 / 10);
}
sheet.untrackAllColumnsForAutoSizing();
return this;
}
使用示范:
/**
* test
* @param response
* @throws IOException
*/
@GetMapping("/testAutoSizeColumnAll")
public void testAutoSizeColumnAll(HttpServletResponse response) throws IOException {
List<?> row1 = CollUtil.newArrayList("增速排名", "关键词", "slope值", "周期", "最近一周排名");
List<?> row2 = CollUtil.newArrayList("1", "lysol", "6.00", "2020-26周 - 2020-27周", "5");
List<?> row3 = CollUtil.newArrayList("2", "masks for coronavirus protection", "1.00", "2020-26周 - 2020-27周", "3");
List<List<?>> rows = CollUtil.newArrayList(row1, row2, row3);
// 通过工具类创建writer,默认创建xls格式 todo 改成get
MyExcelWriter writer =MyExcelWriter.getBigWriter();
// 一次性写出内容,使用默认样式,强制输出标题
writer.write(rows, true);
// 设置所有列为自动宽度,不考虑合并单元格
writer.autoSizeColumnAll();
//response为HttpServletResponse对象
response.setContentType("application/vnd.ms-excel;charset=utf-8");
//test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
response.setHeader("Content-Disposition","attachment;filename=test.xls");
//out为OutputStream,需要写出到的目标流
ServletOutputStream out = response.getOutputStream();
writer.flush(out, true);
// 关闭writer,释放内存
writer.close();
//此处记得关闭输出Servlet流
IoUtil.close(out);
}
如何获取列长度, 为第一行writer.merge做准备:
【Hutool Excel】List方式生成Excel
//字段数量
int fieldLength = StaffVo.class.getDeclaredFields().length;
【Hutool Excel】Map方式生成Excel
//字段数量
int fieldLength = rows.get(0).size();
1. SXSSFSheet sheet = (SXSSFSheet) writer.getSheet();
sheet.setColumnWidth(i, sheet.getColumnWidth(i) * 17 / 10);不然它报不能自动转
2. writer.autoSizeColumnAll();在 writer.write(之后
-----------------历经傍晚测试到半夜三点
与是否BigExcel无关
与this无关
与是否直接调封装方法写本地还是转读取为io流网络写出无关
与是否合并首行无关
与特殊字符无关
猜测与 rows 数据结构有关——只支持【行列对象List:行列对象List<List<?>>】写出的方式,才autoSizeColumnAll
都错。
尼玛,不经意限制rows长度后(本意是想把线上数据黏贴一两条出来[列较多],放本地psvm里运行看excel效果是否有变化),发现数据量小时,正常自适应了!数据量大时,就会失效(99可行,100条不行。 ThreadUtil.sleep(30*1000);无效
好巧的数字【妈的,早知道debug了,浪费我这么多时间在这测。这就是不自信debug的下场吗。这估计是为了BigExcel效率而特地限制的吧】,感觉像认为限制的呢,果然,点进原码发现SXSSFSheet _randomAccessWindowSize
原因:
破案了,是BigExcel机制的原因:
https://blog.csdn.net/zlp5201/article/details/21611673
比如内存中限制行数为100,当行号到达101时,行号为0的记录刷新到硬盘并从内存中删除,当行号到达102时,行号为1的记录刷新到硬盘,并从内存中删除,以此类推。
rowAccessWindowSize代表指定的内存中缓存记录数,默认为100,此值可以通过
new SXSSFWorkbook(int rowAccessWindowSize)或SXSSFSheet.setRandomAccessWindowSize(intwindowSize)来设置。
不过,
sheet.setRandomAccessWindowSize(10000);
无效。
SXSSFSheet sheet = (SXSSFSheet) writer.getSheet();
sheet.setRandomAccessWindowSize(5000);
无效。 2020年11月28日 03:55:59
或者是因为我直接写入磁盘得原因,100一次。虽重设无用。
如果写到流呢,会存在100一写的可能吗,会重设有用吗。【没试,但估计指定不可能:flushout又不管你写到哪】
或者换Writer类型【所有对生成后数据样式操作都受此机制影响,比如改行高。我这自适应不就是列宽,和它一码事。】
试试其他方式产生excel能否自适应宽(少量数据时),估计能,因为特么原理明白了:【没试,但估计指定不可能:生成后设置得自适应。这三种方式只是不同的在内存中制造excel的方式而已,而设置自适应又不在这呢。】https://blog.csdn.net/zhangjinwei417/article/details/99413184
试了,BigExcel时,setRandomAccessWindowSize(-1),没用-_-||
【你为了效率都不改fastdfs名了,都异步了,就不该歪做自适应这种影响生成效率的行为了。手动重设列宽效率还行,可以接受。】
本文地址:https://blog.csdn.net/CW_SZDX/article/details/110236881