一、基础介绍请戳:CSV与Excel的对比,POI导出Excel的数据量限制,HSSF、XSSF、SXSSF的区别
二、HSSFWorkbook导出Excel示例
通过poi导出excel的过程大致是这样的:
- 导入POI的jar包,使用对应的POI对象(本篇选择HSSFWorkbook)
- 创建 sheet 表
- 创建 row 行
- 创建 cell 每行的单元格(可设置数据的格式,和单元格的格式)
- 也可在所有数据写好之后,整体对某列某行来设置格式
- 通过IO流输出
sheet,row,cell在建立的时候Index都是从0开始的;
/**
* 生成导出.xls文件,使用HSSFWorkbook
*/
public static File createExcelFile(List<Map<String, String>> exportData,
Map<String, String> rowMapper, String outPutPath,
String excelFileName) {
File excelFile = null;
FileOutputStream fOut = null;
HSSFWorkbook wb = null;
try {
excelFile = File.createTempFile(excelFileName, ".xls", new File(outPutPath));
//wb对象
wb = new HSSFWorkbook();
//创建sheet对象
HSSFSheet sheet = wb.createSheet();
//设置列默认的宽度
sheet.setDefaultColumnWidth(15);
//创建表头行
HSSFRow rowHead = sheet.createRow(0);
//设置表头行内容,可以在这里对表头设置一些样式,标红呀,加粗之类的
//样式代码在下面有示范
int i = 0;
for (String str : rowMapper.values()) {
HSSFCell cellHead = rowHead.createCell(i);
cellHead.setCellValue(str);
i++;
}
单元格格式的创建需在循环体外,不然数据量过大时会报错:“The maximum number of cell styles was exceeded. You can define up to 4000 styles in a .xls workbook”
//设置表格主内容
//单元格格式的创建需在循环体外,不然数据量过大时会报错
HSSFCellStyle textStyle = wb.createCellStyle();
//用于格式化单元格的数据
HSSFDataFormat format = wb.createDataFormat();
//设置为单元格文本格式
textStyle.setDataFormat(format.getFormat("@"));
//不换行
textStyle.setWrapText(false);
int j = 0;
for (Map<String, String> datamap : exportData) {
HSSFRow row = sheet.createRow(j + 1);
int k = 0;
for (String str : datamap.keySet()) {
HSSFCell cell = row.createCell(k);
//判断针对单号数据,需要设置单元格格式为文本格式,避免科学计数法
if (("身份证号").equals(rowMapper.get(str))) {
cell.setCellStyle(textStyle);
cell.setCellValue(datamap.get(str));
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
} else {
cell.setCellValue(datamap.get(str));
}
k++;
}
j++;
}
/*//设置第一列为文本格式
HSSFDataFormat format = wb.createDataFormat();
textStyle.setDataFormat(format.getFormat("@"));
sheet.setDefaultColumnStyle(0, textStyle);*/
fOut = new FileOutputStream(excelFile);
//写内容,xls文件已经可以打开
wb.write(fOut);
//刷新缓冲区
fOut.flush();
} catch (IOException e) {
logger.error("export IOException");
} finally {
try{
fOut.close();
}catch (Exception ex){
logger.error("export io exception");
}
}
return excelFile;
}
三、单元的样式设置,标红加粗之类
// 设置单元格各种样式
// 设置字体
HSSFFont font = wb.createFont();
//字体高度
font.setFontHeightInPoints((short) 11);
//字体颜色
font.setColor(HSSFFont.COLOR_NORMAL);
//字体
font.setFontName("宋体");
//设置单元格里的字体样式,使用上面设置对字体样式,以及设置单元格的格式
HSSFCellStyle cellStyle = wb.createCellStyle();
cellStyle.setFont(font);
//水平布局:居中
cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
//单元格垂直居中
cellStyle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
//换行
cellStyle.setWrapText(true);
四、对于身份证等长数字数据,设置CELL单元格为文本格式
/**
*设置CELL格式为文本格式
*/
HSSFCellStyle cellStyle = wb.createCellStyle();
HSSFDataFormat format = wb.createDataFormat();
//"@"是指文本的数据格式,主要是这段代码
cellStyle.setDataFormat(format.getFormat("@"));
cell.setCellStyle(cellStyle);
cell.setCellValue(你的值);
//CELL_TYPE_STRING是单元格格式,这里写不写没区别…… 原因如下解释
cell.setCellType(HSSFCell.CELL_TYPE_STRING);
踩坑点:
- 通常大家都是想到既然是设置CELL格式肯定是通过cell.setCellType(HSSFCell.CELL_TYPE_STRING)然后插入数据再导出,诚然这种想法是对的,实际上不能起到任何作用,因为这个方法就是EXCEL默认的格式,写不写都一样;
- 如果数据量大的话,系统可能会报错“The maximum number of cell styles was exceeded. You can define up to 4000 styles in a .xls workbook”,原因是
cellStyle
创建的次数太多了,解决这个问题的方法很简单,在循环体外面创建单元格格式(即把它当成一个“全局”变量),不要在循环内部创建; - 自调节单元格尺寸方法
autoSizeColumn()
, api描述说数据较大时耗时非常大, 建议在结果的时候调用一次。(ps:autoSizeColumn会遍历每一列的每一行数据获取最大长度)
Excel的数据格式
图中的数据有数值、货币、时间、日期、文本等格式。这些数据格式在POI中的HSSFDataFormat类里都有相应的定义。 在HSSFDataFormat里一共定义了49种内置的数据格式,如下表所示:
在上面表中,字符串类型所对应的是数据格式为"@"(最后一行),也就是HSSFDataFormat中定义的值为0x31(49)的那行。Date类型的值的范围是0xe-0x11,本例子中的Date格式为"“m/d/yy”",在HSSFDataFormat定义的值为0xe(14)。
POI中Excel文件Cell的类型(单元格格式)
在读取每一个Cell的值的时候,通过getCellType方法获得当前Cell的类型,在Excel中Cell有6种类型,如下表所示:
CellType | 说明 |
---|---|
CELL_TYPE_BLANK | 空值 |
CELL_TYPE_BOOLEAN | 布尔型 |
CELL_TYPE_ERROR | 错误 |
CELL_TYPE_FORMULA | 公式型 |
CELL_TYPE_STRING | 字符串型 |
CELL_TYPE_NUMERIC | 数值型 |
一般都采用CELL_TYPE_STRING和CELL_TYPE_NUMERIC类型,因为在Excel文件中只有字符串和数字。如果Cell的Type为CELL_TYPE_NUMERIC时,还需要进一步判断该Cell的数据格式,因为它有可能是Date类型,在Excel中的Date类型也是以Double类型的数字存储的。Excel中的Date表示当前时间与1900年1月1日相隔的天数,所以需要调用HSSFDateUtil的isCellDateFormatted方法,判断该Cell的数据格式是否是Excel Date类型。如果是,则调用getDateCellValue方法,返回一个Java类型的Date。
五、拼好Excel之后,文件下载方法:
方法1:
//创建xls文件,无内容 0字节
FileOutputStream fOut = new FileOutputStream(xlsFile);
//写内容,xls文件已经可以打开
wb.write(fOut);
//刷新缓冲区
fOut.flush();
//关闭
fOut.close();
方法2:
//生成流对象
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
//将excel写入流
wb.write(byteArrayOutputStream);
//工具类,封装弹出下载框:
String outFile = "excelFile.xls";
DownloadBaseAction down = new DownloadBaseAction();
down.download(byteArrayOutputStream, response, outFile);
方法3:(适用于struts2)
ServletActionContext.getResponse().setContentType("application/octet-stream");
String returnName = ServletActionContext.getResponse().encodeURL( new String("excelFile.xls".getBytes(), "ISO-8859-1"));
ServletActionContext.getResponse().addHeader("Content-Disposition", "attachment;filename=" + returnName);
wb.write(ServletActionContext.getResponse().getOutputStream());