POI百万数据快速导出excel

我们经常抱怨POI导出非常缓慢,就是我们绞尽脑汁去修改调整还是很慢!那是因为我们没有认真思考过为什么POI导出慢?

1、在大数据量的时候导出为什么慢,难道仅仅因为数据量大,POI的性能问题?当然不是,其实很多时候是因为我们自身代码,也存在问题。导出慢很大一部分原因在频繁的创建对象,设置对象的属性!

其中最重要的是设置单元格的格式:

CellStyle style2 = workbook.createCellStyle();

如果有20万行数据 ,一共有10列,那等于我要创建200万个对象,这么庞大的对象创建怎么能不卡啦!

那有没有办法让只创建一次对象啦!下面我们就来说代码:

1、使用的依赖包

<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
		<dependency>
		    <groupId>org.apache.poi</groupId>
		    <artifactId>poi-ooxml</artifactId>
		    <version>3.11</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
		<dependency>
		    <groupId>org.apache.poi</groupId>
		    <artifactId>poi</artifactId>
		    <version>3.11</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml-schemas -->
		<dependency>
		    <groupId>org.apache.poi</groupId>
		    <artifactId>poi-ooxml-schemas</artifactId>
		    <version>3.11</version>
		</dependency>
		<dependency>
		    <groupId>com.github.virtuald</groupId>
		    <artifactId>curvesapi</artifactId>
		    <version>1.06</version>
		</dependency>		

2、创建测试使用的实体类。

@Data
public class TransferRecordVo {
	private  String  transferId;
	private  Integer  userId;
	private  String  userName;
	private  Integer  currencyId;
	private  String  currencyName;
	private  Double qty;
	private  Integer  transferType;
	private  String  typeStr;
	private  Date  createTime;
}

3、创建工具类(只展示方法)

	public  ByteArrayOutputStream exportExcel2007Two(String title, String[] headers, Collection<T> dataset, ByteArrayOutputStream out, 
				String pattern,String [] cellFormat) {
			// 声明一个工作薄
			SXSSFWorkbook workbook = new SXSSFWorkbook(500);
			// 生成一个表格
			Sheet sheet = workbook.createSheet(title);
			// 设置表格默认列宽度为15个字节
			sheet.setDefaultColumnWidth(20);
			// 生成一个样式
			CellStyle style = workbook.createCellStyle();
			// 设置这些样式
			//style.setFillBackgroundColor(new IndexedColors(java.awt.Color.gray));
			//style.setFillForegroundColor(new IndexedColors(java.awt.Color.gray)); 
			style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
			style.setFillPattern(CellStyle.SOLID_FOREGROUND);
			style.setBorderBottom(CellStyle.BORDER_THIN);
			style.setBorderLeft(CellStyle.BORDER_THIN);
			style.setBorderRight(CellStyle.BORDER_THIN);
			style.setBorderTop(CellStyle.BORDER_THIN);
			style.setAlignment(CellStyle.ALIGN_CENTER);
			// 生成一个字体
			Font font = workbook.createFont();
			font.setBoldweight(Font.BOLDWEIGHT_BOLD);
			font.setFontName("宋体"); 
			font.setColor(IndexedColors.BLACK.getIndex());
			font.setFontHeightInPoints((short) 11);
			// 把字体应用到当前的样式
			style.setFont(font);
			// 生成并设置另一个样式
			CellStyle style2 = workbook.createCellStyle();
			style2.setFillForegroundColor(IndexedColors.WHITE.getIndex()); 
			style2.setFillPattern(CellStyle.SOLID_FOREGROUND);
			style2.setBorderBottom(CellStyle.BORDER_THIN);
			style2.setBorderLeft(CellStyle.BORDER_THIN);
			style2.setBorderRight(CellStyle.BORDER_THIN);
			style2.setBorderTop(CellStyle.BORDER_THIN);
			style2.setAlignment(CellStyle.ALIGN_CENTER);
			style2.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
			// 生成另一个字体
			Font font2 = workbook.createFont();
			font2.setBoldweight(Font.BOLDWEIGHT_NORMAL);
			// 把字体应用到当前的样式
			style2.setFont(font2);
			// 产生表格标题行
			Row row = sheet.createRow(0);
			Cell cellHeader;
			for (int i = 0; i < headers.length; i++) {
				cellHeader = row.createCell(i);
				cellHeader.setCellStyle(style);
				cellHeader.setCellValue(new XSSFRichTextString(headers[i]));
			}
	 
			// 遍历集合数据,产生数据行
			Iterator<T> it = dataset.iterator();
			int index = 0;
			T t;
			Field[] fields;
			Field field;
			XSSFRichTextString richString;
			Pattern p = Pattern.compile("^//d+(//.//d+)?$");
			Matcher matcher;
			String fieldName;
			String getMethodName;
			Cell cell;
			Class tCls;
			Method getMethod;
			Object value;
			String textValue;
			SimpleDateFormat sdf = new SimpleDateFormat(pattern);
			while (it.hasNext()) {
				index++;
				row = sheet.createRow(index);
				t = (T) it.next();
				// 利用反射,根据JavaBean属性的先后顺序,动态调用getXxx()方法得到属性值
				fields = t.getClass().getDeclaredFields();
				for (int i = 0; i < fields.length; i++) {
					cell = row.createCell(i);
					DataFormat df = workbook.createDataFormat();
					style2.setDataFormat(df.getFormat("@"));
					//cell.setCellStyle(style2);
					field = fields[i];
					fieldName = field.getName();
					getMethodName = "get" + fieldName.substring(0, 1).toUpperCase()
							+ fieldName.substring(1);
					try {
						tCls = t.getClass();
						getMethod = tCls.getMethod(getMethodName, new Class[] {});
						value = getMethod.invoke(t, new Object[] {});
						// 判断值的类型后进行强制类型转换
						textValue = null;
						if (value instanceof Date) {
							textValue = sdf.format((Date) value);
						} else {
							// 其它数据类型都当作字符串简单处理
							if (value != null) {
								textValue = value.toString();
							}
						}
						String str = cellFormat[i];
						if (textValue != null) {
							if(str.trim().equals("Integer")){
								style2.setDataFormat(df.getFormat("#0"));
								//cell.setCellStyle(style2);
		                    	cell.setCellValue(Integer.parseInt(textValue));
							}else if(str.trim().equals("Double")){
								style2.setDataFormat(df.getFormat("##0.00000"));	
								//cell.setCellStyle(style2);
		                    	cell.setCellValue(Double.parseDouble(textValue));
							}else {
								richString = new XSSFRichTextString(textValue);
								style2.setDataFormat(df.getFormat("@"));
								//cell.setCellStyle(style2);
								cell.setCellValue(richString);
							}
						}else{
							if(str.trim().equals("Integer")){
								style2.setDataFormat(df.getFormat("#0"));
								//cell.setCellStyle(style2);
		                    	cell.setCellValue(0);
							}else if(str.trim().equals("Double")){
								style2.setDataFormat(df.getFormat("##0.00000"));	
								//cell.setCellStyle(style2);
		                    	cell.setCellValue(0);
							}else {
								//richString = new XSSFRichTextString(textValue);
								style2.setDataFormat(df.getFormat("@"));
								//cell.setCellStyle(style2);
								cell.setCellValue("");
							}	
						}
					} catch (SecurityException e) {
						e.printStackTrace();
					} catch (NoSuchMethodException e) {
						e.printStackTrace();
					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					} catch (InvocationTargetException e) {
						e.printStackTrace();
					} finally {
						// 清理资源
					}
					cell.setCellStyle(style2);
				}
			}
			try {
				workbook.write(out);
			} catch (IOException e) {
				e.printStackTrace();
			}finally{
				try {
					out.close();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			return out;
		}
		

说明:

这里我们设置一个通用的数据行的单元格格式,后面只要跟我们传入的每一列对应的格式,设置单元格格式!

获取对应单元格格式,然后根据格式设置不同的单元格格式,最后设置到单元格格式当中

 cell.setCellStyle(style2);

这样既设置了格式,又少创建了几百万个对象。速度当然快!

可以看到包括生成20万数据,只花了10秒钟!已经算是相当快乐! 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章