在做项目的时候,客户都会把数据下载下来,所以一般都会有报表导出的功能,正常的是直接导出为xlsx格式的excel表格,由于博主参与的是停车场项目,在后续项目运行上线的时候,数据量会过大,再去导出的时候会报错 java.lang.IllegalArgumentException: Invalid row number (65536) outside allowable range (0..65535),然后百度发现: excel最大行数,不同版本有所不同。Excel2003版最大行数是65536行。Excel2007开始的版本最大行数是1048576行。 要不分sheet显示,要不改格式。 毋庸置疑,博主被要求改格式,好吧,只能改,改成csv文件的格式。
以上就是后面发生事情的前因。下面就来介绍一下做完之后的经验以及踩过的坑吧。
报表导出为xlsx格式
service层:
public Workbook export(CarRecordDTO carRecordDTO) throws Exception {
Workbook workbook = new Workbook();
Sheet sheet = workbook.createSheet("在线车辆数据");
Row row = sheet.createRow(0);
row.createCell(1).setCellValue("车牌照片");
row.createCell(2).setCellValue("车牌号");
row.createCell(3).setCellValue("进场时间");
row.createCell(4).setCellValue("停车时长");
row.createCell(5).setCellValue("进场闸口");
row.createCell(6).setCellValue("有无跨场");
row.createCell(7).setCellValue("有无校正");
Date currentDate = new Date();
for (int i = 0; i < carRecordList.size(); i++) {
CarRecord carRecord = (CarRecord) carRecordList.get(i);
row = sheet.createRow(i + 1);
ExcelUtil.setCellValue(row, 1, carRecord.getEnterPlatePic());
ExcelUtil.setCellValue(row, 2, carRecord.getPlateNum());
ExcelUtil.setCellValue(row, 3, DateUtil.formatDate(carRecord.getEnterDate(), "yyyy-MM-dd HH:mm"));
Date enterDate = carRecord.getEnterDate();
Long stopTime = (currentDate.getTime() - enterDate.getTime()) / 60000;
ExcelUtil.setCellValue(row, 4, TimeUtils.timeConvert(stopTime.intValue()));
ExcelUtil.setCellValue(row, 5, list.get(carRecord.getEnterGate()));
if (YES.equals(carRecord.getIsCross())) {
ExcelUtil.setCellValue(row, 6, "有跨场");
} else {
ExcelUtil.setCellValue(row, 6, "无跨场");
}
if (YES.equals(carRecord.getIsRevise())) {
ExcelUtil.setCellValue(row, 7, "有校正");
} else {
ExcelUtil.setCellValue(row, 7, "无校正");
}
}
return workbook;
}
controller层:
Workbook workbook = carRecordService.export(carRecordDTO);
super.writeExcel("carRecord.xls",workbook);
protected void writeExcel(String filename, Workbook workbook) throws Exception {
this.response.setContentType("application/octet-stream; charset=iso-8859-1");
StringBuffer contentDisposition = new StringBuffer("attachment; filename=\"");
contentDisposition.append(filename).append("\"");
this.response.setHeader("Content-disposition", contentDisposition.toString());
ServletOutputStream out = this.response.getOutputStream();
workbook.write(out);
out.flush();
out.close();
}
上面的代码就可以导出xlsx格式的excil报表了。。是不是很简单。
报表导出为csv格式
service层:
public File export(CarRecordDTO carRecordDTO) throws Exception {
List<String> listPark = new ArrayList<>();
listPark.add("车牌照片");
listPark.add("车牌号");
listPark.add("进场时间");
listPark.add("停车时长");
listPark.add("进场闸口");
listPark.add("有无跨场");
listPark.add("有无校正");
tempFile = new File("cardRecord.csv");
CsvWriter csvOutput = new CsvWriter(tempFile.getCanonicalPath(), ',', Charset.forName("GBK"));
csvOutput.setEscapeMode(CsvWriter.ESCAPE_MODE_DOUBLED);
// 第一行
for (String s : listPark) {
csvOutput.write(s);
}
csvOutput.endRecord();
// 循环写出数据
Date currentDate = new Date();
for (CarRecord carRecord : carRecordList) {
csvOutput.write(carRecord.getEnterPlatePic());
csvOutput.write(carRecord.getPlateNum());
csvOutput.write(DateUtil.formatDate(carRecord.getEnterDate(), "yyyy-MM-dd HH:mm"));
Date enterDate = carRecord.getEnterDate();
Long stopTime = (currentDate.getTime() - enterDate.getTime()) / 60000;
csvOutput.write(TimeUtils.timeConvert(stopTime.intValue()));
csvOutput.write(list.get(carRecord.getEnterGate()));
if (YES.equals(carRecord.getIsCross())) {
csvOutput.write("有跨场");
} else {
csvOutput.write("无跨场");
}
if (YES.equals(carRecord.getIsRevise())) {
csvOutput.write("有校正");
} else {
csvOutput.write("无校正");
}
csvOutput.endRecord();
}
csvOutput.close();
return tempFile;
}
controller层:
File tempFile = carRecordService.export(carRecordDTO);
java.io.OutputStream out = this.response.getOutputStream();
this.response.reset();
this.response.setContentType("application/csv; charset=iso-8859-1");
this.response.setHeader("content-disposition", "attachment; filename="+tempFile.getPath());
File fileLoad = new java.io.File(tempFile.getCanonicalPath());
long fileLength = fileLoad.length();
FileInputStream in = new FileInputStream(fileLoad);
String length1 = String.valueOf(fileLength);
byte[] b = new byte[10240];
this.response.setHeader("Content_Length", length1);
int n;
while ((n = in.read(b)) != -1) {
out.write(b, 0, n); //每次写入out1024字节
}
in.close();
out.close();
这样就可以导出csv格式的报表了,下面就来讲讲踩到的坑和搞的乌龙吧:
- 因为要引用import com.csvreader.CsvWriter 包,所以就去找相关的依赖包,然后就去maven官网去搜索,
<!-- https://mvnrepository.com/artifact/net.sourceforge.javacsv/javacsv -->
<dependency>
<groupId>net.sourceforge.javacsv</groupId>
<artifactId>javacsv</artifactId>
<version>2.0</version>
</dependency>
把这个放进pom.xml文件中,要用的包还是import不进去,然后怀疑是maven的settings.xml没设置好,然后又前前后后叭叭叭的搞了挺久的,还是没有解决,后来实在没有办法了,向同事大神求助,后来经检查
是把这个按钮不知道什么时候按到了,导致idea离线状态,反正博主已经哭了
-
在写完代码的时候,在本地测试是没有问题的,生成的excil可以存放65535以上的数据,文档打开也是没有问题的,然后部署到dev环境上测试,发现文件名又不是我改的英文名,格式也是乱了,都在同一个单元格里面,又叭叭叭的找问题,最后定位到应该是前端把文档名写死了,格式也有锁定吧(因为是前后端分离的,我基本上没去看前端代码)
-
因为导出的报表由时间格式的,发现格式有问题,我在代码里面写了是yyyy-MM-dd hh:mm但是没有生效,比如2019-10-03 12:05 就显示为2019-10-3 12:5 反正就是很奇怪,百度上别人说要在前后都加"\t",我也试过了,没卵用,但是改excil表格里面单元格的格式是可以的;