POI与JXL写Excel的性能对比

         在java项目中,使用xml配置和反射写了一个通用POI导出Excel数据的方法,发现导出2500行40列数据用了大概30分钟,通过排查发现POI的createCell非常耗损性能。然后采用JXL重构通用Excel数据导出方法,时间只需1s左右。现在把POI和JXL两种导出方法对比如下,也方便以后用到,便于检索。

       POI方式写Excel

	/**
	 * POI方式数据导出 支持duo sheet导出,支持表名、sheet页、标题、副标题单独命名
	 * 该方法由于性能问题,已过期,不推荐使用
	 */ 
	@Deprecated 
	@SuppressWarnings({ "unchecked", "deprecation" })
	@RequestMapping(value = "/exportSheetsData")
	public void exportSheetsData(String reqObjs, String tableName, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
        long s=(new Date()).getTime();
        long s1=0;
		List queryConditions = JSON.parseArray(reqObjs, QueryCondition.class);
		int conCount = queryConditions.size();
		OutputStream fOut = null;
		
		// 产生工作簿对象
		HSSFWorkbook workbook = new HSSFWorkbook();

		// 定义标题样式
		HSSFFont titleFont = workbook.createFont();
		titleFont.setFontHeightInPoints((short) 18);
		titleFont.setFontName("宋体");
		titleFont.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		HSSFCellStyle title = workbook.createCellStyle();
		title.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
		title.setFont(titleFont);
		title.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		title.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		title.setWrapText(true);

		// 定义表头样式
		HSSFFont font = workbook.createFont();
		font.setFontHeightInPoints((short) 12);
		font.setFontName("宋体");
		HSSFCellStyle head = workbook.createCellStyle();
		head.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 垂直居中
		head.setFont(font);
		head.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		head.setBorderBottom((short) 1); // 设置边框样式
		head.setBorderLeft((short) 1); // 左边框
		head.setBorderRight((short) 1); // 右边框
		head.setBorderTop((short) 1); // 顶边框

		// 定义居中样式
		HSSFCellStyle center = workbook.createCellStyle();
		center.setFont(font);
		center.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		center.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
		center.setBorderBottom((short) 1); // 设置边框样式
		center.setBorderLeft((short) 1); // 左边框
		center.setBorderRight((short) 1); // 右边框
		center.setBorderTop((short) 1); // 顶边框
		center.setWrapText(true);

		// 需要自动换行的样式
		HSSFCellStyle huanHang = workbook.createCellStyle();
		huanHang.setFont(font);
		huanHang.setAlignment(HSSFCellStyle.ALIGN_LEFT);
		huanHang.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
		huanHang.setBorderBottom((short) 1); // 设置边框样式
		huanHang.setBorderLeft((short) 1); // 左边框
		huanHang.setBorderRight((short) 1); // 右边框
		huanHang.setBorderTop((short) 1); // 顶边框
		huanHang.setWrapText(true);

		// 定义小数数字样式
		HSSFCellStyle number = workbook.createCellStyle();
		number.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00"));// 小数保留两位
		number.setFont(font);
		number.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		number.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
		number.setBorderBottom((short) 1); // 设置边框样式
		number.setBorderLeft((short) 1); // 左边框
		number.setBorderRight((short) 1); // 右边框
		number.setBorderTop((short) 1); // 顶边框

		// 定义整数数字样式
		HSSFCellStyle intNumber = workbook.createCellStyle();
		intNumber.setDataFormat(HSSFDataFormat.getBuiltinFormat("0"));// 小数保留两位
		intNumber.setFont(font);
		intNumber.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		intNumber.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
		intNumber.setBorderBottom((short) 1); // 设置边框样式
		intNumber.setBorderLeft((short) 1); // 左边框
		intNumber.setBorderRight((short) 1); // 右边框
		intNumber.setBorderTop((short) 1); // 顶边框 

		// 定义居左样式
		HSSFCellStyle left = workbook.createCellStyle();
		left.setFont(font);
		left.setAlignment(HSSFCellStyle.ALIGN_LEFT); 
		left.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
		left.setWrapText(true);

		try {
			for (int qindex = 0; qindex < conCount; qindex++) {
				/*--------------------------------------------
				该段代码为基于xml与反射的数据获取过程  已经略去
				-------------------------------------------------*/
				s1=(new Date()).getTime();
				// 产生工作表对象
				HSSFSheet sheet = workbook.createSheet();
				workbook.setSheetName(qindex, queryCondition.getSheetName() == null ? tableName : queryCondition
						.getSheetName());

				int rowLen = objList.size();
				List colList = query.getColumnList();
				int colLen = colList.size();

				// 创建表头
				int hempty = 0;
           
				// 填充标题
				HSSFRow hrow = sheet.createRow(0);
				HSSFCell cell = hrow.createCell(0);
				hrow.setHeight((short) 1500);
				cell.setCellValue(new HSSFRichTextString(queryCondition.getSheetTitle() != null ? queryCondition.getSheetTitle()
						: queryCondition.getSheetName()));
				cell.setCellStyle(title);
				int lastcol = -1;
				for (int h = 0; h < colLen; ++h) {
					Column hcolumn = colList.get(h);
					if (!hcolumn.getIsServerCondition() && !hcolumn.getHidden() && hcolumn.getIsExport()) {
						lastcol++;
					}
				}
				sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, lastcol));
                int titleRowCount=1;
                //填充副标题
                hrow = sheet.createRow(titleRowCount);
                if(queryCondition.getSheetSubTitle()!=null){
                	titleRowCount=2;
                    cell = hrow.createCell(0);
    				hrow.setHeight((short) 600);
    				cell.setCellValue(new HSSFRichTextString(queryCondition.getSheetSubTitle()));
    				cell.setCellStyle(left);  
    				sheet.addMergedRegion(new CellRangeAddress(1,1,0,lastcol));
    				hrow=sheet.createRow(titleRowCount);
                }       
				hrow.setHeight((short) 600);
				for (int h = 0; h < colLen; ++h) {
					Column hcolumn = colList.get(h);
					if ("rowIndex".equals(hcolumn.getKey())) {
						// 创建序号列
						HSSFCell hcell = hrow.createCell(0);
						hcell.setCellType(HSSFCell.CELL_TYPE_STRING);
						hcell.setCellStyle(head);
						hcell.setCellValue("序号");
						continue;
					}  
					if (!hcolumn.getIsServerCondition() && !hcolumn.getHidden() && hcolumn.getIsExport()) {
						// 创建表头列
						HSSFCell hcell = hrow.createCell(h - hempty);
						hcell.setCellType(HSSFCell.CELL_TYPE_STRING);
						hcell.setCellStyle(head);
						hcell.setCellValue(hcolumn.getHeader());
					} else { 
						++hempty;
					}
					sheet.autoSizeColumn((short) h);
				}   

				// 创建数据列表
				for (int b = 1; b <= rowLen; ++b) {
					// 创建一行数据列
					HSSFRow brow = sheet.createRow(b + titleRowCount);
					brow.setHeight((short) 500);
					int bempty = 0;
					Object obj = objList.get(b - 1);
					Row datarow = new Row();
					Map dataMap = null;
					if(objClass==null) {
						dataMap = (Map)obj;
						datarow.setId(dataMap.get(query.getKey()).toString());
					}else {
						Method method = objClass.getMethod(ObjectUtil.methodName(query.getKey(), "get"));
						datarow.setId((String) method.invoke(obj));
					} 

					for (int i = 0; i < colLen; ++i) {
						Column bcolumn = colList.get(i);
						if ("rowIndex".equals(bcolumn.getKey())) {
							// 设置当前列序号
							HSSFCell bcell = brow.createCell(i);
							bcell.setCellType(HSSFCell.CELL_TYPE_STRING);
							bcell.setCellStyle(intNumber);
							bcell.setCellValue(b);
							continue;
						} 
						String data = "";
						
						if(objClass!=null) {
							data = ObjectUtil.ObjectToString(obj, bcolumn.getKey(), bcolumn.getFormat());
						}else {
							if(Date.class.getName().equals(bcolumn.getClassType())||"date".equals(bcolumn.getClassType().toLowerCase())) {
								data = bcolumn.getFormat()!=null ? DateUtil.format((Date)dataMap.get(bcolumn.getKey().toUpperCase()), bcolumn.getFormat())
										: DateUtil.format((Date)dataMap.get(bcolumn.getKey().toUpperCase()));
							}else {
								if(dataMap.get(bcolumn.getKey().toUpperCase())!=null) {
									data = dataMap.get(bcolumn.getKey().toUpperCase()).toString();
								}
							}
						}
						if (!bcolumn.getIsServerCondition() && !bcolumn.getHidden() && bcolumn.getIsExport()) {
							// 设置当前列值
							HSSFCell bcell = brow.createCell(i - bempty);

							// 单元格对齐
							if (bcolumn.getAlign().equals("center"))
								bcell.setCellStyle(center);
							else if (bcolumn.getAlign().equals("left"))
								bcell.setCellStyle(huanHang);
							// 单元格赋值
							if (bcolumn.getClassType().equals("java.lang.Double") && bcolumn.getSuffix() == null) {
								bcell.setCellStyle(number);
								bcell.setCellValue(Double.parseDouble(data));
							} else if (bcolumn.getClassType().equals("java.lang.Integer")) {
								bcell.setCellStyle(intNumber);
								bcell.setCellValue(Integer.parseInt(data));
							} else if (bcolumn.getSuffix() != null) {
								bcell.setCellValue(data + "%");
							} else {
								bcell.setCellValue(data);
							}
						} else {
							++bempty;
						}
						sheet.autoSizeColumn((short) i);
					}
				}
				//创建sheet完成后,根据前台参数执行 行合并、列合并、多表头等操作
				if(queryCondition.getSheetMethod()!=null){  
					String sheetMethod=queryCondition.getSheetMethod();
					String[] params=sheetMethod.split("_");
					//正文内容考试的行号索引
					int contentBeginIndex=1; 
					//含有副标题
					if(queryCondition.getSheetSubTitle()!=null)
						contentBeginIndex=2;
					if(params[0].equals("rowSpan")){ 
						  for(int i=1;i>>>>>>>>>>>>>>>>>>>>>>>>>>"+((new Date()).getTime()-s)/1000);
		} catch (Exception e) {
		     e.printStackTrace();
		} finally {
			try {
				fOut.flush();
				fOut.close();
			} catch (Exception e2) {
			}
		}
	}
	


      JXL方式写Excel

   

	 /*
         * JXL方式数据导出 支持多 sheet导出,支持表名、sheet页、标题、副标题单独命名
	 * 2014-5-6性能优化
	 */ 
	
	@SuppressWarnings({ "unchecked", "deprecation" })
	@RequestMapping(value = "/exportSheetsDataJXL")
	public void exportSheetsDataJXL(String reqObjs, String tableName, HttpServletRequest request,
			HttpServletResponse response) throws Exception {
        long s=(new Date()).getTime();
        long s1=0;
		List queryConditions = JSON.parseArray(reqObjs, QueryCondition.class);
		int conCount = queryConditions.size();
		String tempfile = System.currentTimeMillis()+"";
		OutputStream fOut = new FileOutputStream(request.getRealPath("/") + "templates" + File.separator + "temp" + File.separator + tempfile + ".xls");
		
		// 产生工作簿对象
		WritableWorkbook  workbook=Workbook.createWorkbook(fOut);

		// 定义标题样式
		WritableFont  titleFont = new WritableFont(WritableFont.TIMES,18,WritableFont.BOLD,false);
		WritableCellFormat title=new WritableCellFormat(titleFont);
		title.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
		title.setAlignment(jxl.format.Alignment.CENTRE);
		title.setBorder(Border.BOTTOM,BorderLineStyle.THIN);
		title.setBorder(Border.LEFT,BorderLineStyle.THIN);
		title.setBorder(Border.RIGHT,BorderLineStyle.THIN);
		title.setBorder(Border.TOP,BorderLineStyle.THIN);
		title.setWrap(true);
		// 定义表头样式
		WritableFont headfont = new WritableFont(WritableFont.TIMES,12,WritableFont.BOLD,false);;
		WritableCellFormat head = new WritableCellFormat(headfont);
		head.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
		head.setAlignment(jxl.format.Alignment.CENTRE);
		head.setBorder(Border.BOTTOM,BorderLineStyle.THIN);
		head.setBorder(Border.LEFT,BorderLineStyle.THIN);
		head.setBorder(Border.RIGHT,BorderLineStyle.THIN);
		head.setBorder(Border.TOP,BorderLineStyle.THIN);
		 
		WritableFont font = new WritableFont(WritableFont.TIMES,12,WritableFont.NO_BOLD,false);;
		// 定义居中样式
		WritableCellFormat center = new WritableCellFormat(font);
		center.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
		center.setAlignment(jxl.format.Alignment.CENTRE);
		center.setBorder(Border.BOTTOM,BorderLineStyle.THIN);
		center.setBorder(Border.LEFT,BorderLineStyle.THIN);
		center.setBorder(Border.RIGHT,BorderLineStyle.THIN);
		center.setBorder(Border.TOP,BorderLineStyle.THIN);

		// 需要自动换行的样式
		WritableCellFormat huanHang = new WritableCellFormat(font);
		huanHang.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
		huanHang.setAlignment(jxl.format.Alignment.CENTRE);
		huanHang.setBorder(Border.BOTTOM,BorderLineStyle.THIN);
		huanHang.setBorder(Border.LEFT,BorderLineStyle.THIN);
		huanHang.setBorder(Border.RIGHT,BorderLineStyle.THIN);
		huanHang.setBorder(Border.TOP,BorderLineStyle.THIN);
		huanHang.setWrap(true);

		// 定义小数数字样式
		NumberFormat nf = new NumberFormat("#.##"); 
		WritableCellFormat number = new WritableCellFormat(nf);
		number.setFont(font);
		number.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
		number.setAlignment(jxl.format.Alignment.CENTRE);
		number.setBorder(Border.BOTTOM,BorderLineStyle.THIN);
		number.setBorder(Border.LEFT,BorderLineStyle.THIN);
		number.setBorder(Border.RIGHT,BorderLineStyle.THIN);
		number.setBorder(Border.TOP,BorderLineStyle.THIN);
		
		// 定义整数数字样式
		NumberFormat intnf = new NumberFormat("#"); 
		WritableCellFormat intNumber = new WritableCellFormat(intnf);
		intNumber.setFont(font);
		intNumber.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
		intNumber.setAlignment(jxl.format.Alignment.CENTRE);
		intNumber.setBorder(Border.BOTTOM,BorderLineStyle.THIN);
		intNumber.setBorder(Border.LEFT,BorderLineStyle.THIN);
		intNumber.setBorder(Border.RIGHT,BorderLineStyle.THIN);
		intNumber.setBorder(Border.TOP,BorderLineStyle.THIN);
		
		// 定义居左样式
		WritableCellFormat left = new WritableCellFormat(font);
		left.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
		left.setBorder(Border.BOTTOM,BorderLineStyle.THIN);
		left.setBorder(Border.LEFT,BorderLineStyle.THIN);
		left.setBorder(Border.RIGHT,BorderLineStyle.THIN);
		left.setBorder(Border.TOP,BorderLineStyle.THIN);		
		left.setWrap(true); 

		CellView cv = new CellView();
		cv.setAutosize(true);
        cv.setSize(18); 
		try {
			for (int qindex = 0; qindex < conCount; qindex++) {
				/*--------------------------------------------
				该段代码为基于xml与反射的数据获取过程  已经略去
				-------------------------------------------------*/				
				s1=(new Date()).getTime();
				// 产生工作表对象
				WritableSheet sheet = workbook.createSheet(queryCondition.getSheetName() == null ? tableName : queryCondition
						.getSheetName(),qindex);

				int rowLen = objList.size();
				List colList = query.getColumnList();
				int colLen = colList.size();

				// 创建表头
				int hempty = 0;
           
				// 填充标题
				Label label=new Label(0,0,queryCondition.getSheetTitle() != null ?queryCondition.getSheetTitle(): queryCondition.getSheetName(),title);
				int lastcol = -1;
				for (int h = 0; h < colLen; ++h) {
					Column hcolumn = colList.get(h);
					if (!hcolumn.getIsServerCondition() && !hcolumn.getHidden() && hcolumn.getIsExport()) {
						lastcol++;
					}
				}
				sheet.addCell(label);
				//sheet.mergeCells(int col1,int row1,int col2,int row2);//左上角到右下角
				sheet.setRowView(0,1500);
				sheet.mergeCells(0, 0, lastcol,0);
                int titleRowCount=1;
                //填充副标题
                if(queryCondition.getSheetSubTitle()!=null){
                	titleRowCount=2;
    				label=new Label(0,1,queryCondition.getSheetSubTitle(),left);
    				sheet.addCell(label);
    				sheet.setRowView(1,600,false);
    				sheet.mergeCells(0,1,lastcol,1);
                }       
                sheet.setRowView(titleRowCount,600,false);
				for (int h = 0; h < colLen; ++h) {
					Column hcolumn = colList.get(h);
					if ("rowIndex".equals(hcolumn.getKey())) {
						// 创建序号列
						label=new Label(0,titleRowCount,"序号",head);
						sheet.addCell(label);
						sheet.setColumnView(0,cv);
						continue;
					}  
					if (!hcolumn.getIsServerCondition() && !hcolumn.getHidden() && hcolumn.getIsExport()) {
						// 创建表头列
						label=new Label(h - hempty,titleRowCount,hcolumn.getHeader(),head);
						sheet.addCell(label);
						sheet.setColumnView(h-hempty,cv);
					} else { 
						++hempty;
					}					 
					
				}      

				// 创建数据列表
				for (int b = 1; b <= rowLen; ++b) {
					// 创建一行数据列
					sheet.setRowView(b+titleRowCount, 500);
					int bempty = 0;
					Object obj = objList.get(b - 1);
					Row datarow = new Row(); 
					Map dataMap = null;
					if(objClass==null) {
						dataMap = (Map)obj;
						datarow.setId(dataMap.get(query.getKey()).toString());
					}else {
						Method method = objClass.getMethod(ObjectUtil.methodName(query.getKey(), "get"));
						datarow.setId((String) method.invoke(obj));
					} 

					for (int i = 0; i < colLen; ++i) {
						Column bcolumn = colList.get(i);
						if ("rowIndex".equals(bcolumn.getKey())) {
							// 设置当前列序号
							jxl.write.Number num=new jxl.write.Number(0,b+titleRowCount,b,intNumber);
							sheet.addCell(num);
							continue; 
						} 
						String data = "";
						 
						if(objClass!=null) {
							data = ObjectUtil.ObjectToString(obj, bcolumn.getKey(), bcolumn.getFormat());
						}else {
							if(Date.class.getName().equals(bcolumn.getClassType())||"date".equals(bcolumn.getClassType().toLowerCase())) {
								data = bcolumn.getFormat()!=null ? DateUtil.format((Date)dataMap.get(bcolumn.getKey().toUpperCase()), bcolumn.getFormat())
										: DateUtil.format((Date)dataMap.get(bcolumn.getKey().toUpperCase()));
							}else {
								if(dataMap.get(bcolumn.getKey().toUpperCase())!=null) {
									data = dataMap.get(bcolumn.getKey().toUpperCase()).toString();
								}
							}
						}
						if (!bcolumn.getIsServerCondition() && !bcolumn.getHidden() && bcolumn.getIsExport()) {
							// 设置当前列值
                            WritableCellFormat format=center;
							// 单元格对齐
							if (bcolumn.getAlign().equals("center")){
								 format=center;
							}
							else if (bcolumn.getAlign().equals("left")){
							     format=left;
							}
								//bcell.setCellStyle(huanHang);
							// 单元格赋值
							
							if (bcolumn.getClassType().equals("java.lang.Double") && bcolumn.getSuffix() == null) {
								jxl.write.Number num1=new jxl.write.Number(i-bempty,b+titleRowCount,Double.parseDouble(data),number);
								sheet.addCell(num1);
								sheet.setColumnView(i-bempty,cv);
							} else if (bcolumn.getClassType().equals("java.lang.Integer")) {
								jxl.write.Number num2=new jxl.write.Number(i-bempty,b+titleRowCount,Integer.parseInt(data),intNumber);
								sheet.addCell(num2);
								sheet.setColumnView(i-bempty,cv);
							} else if (bcolumn.getSuffix() != null) {
								label=new Label(i-bempty,b+titleRowCount,data+"%",format);
								sheet.addCell(label);
								sheet.setColumnView(i-bempty,cv);
							} else {  
								label=new Label(i-bempty,b+titleRowCount,data,format);
								sheet.addCell(label);
								sheet.setColumnView(i-bempty,cv);
							} 
						} else { 
							++bempty;
						} 
						
					}
				}
				//创建sheet完成后,根据前台参数执行 行合并、列合并、多表头等操作
				if(queryCondition.getSheetMethod()!=null){  
					String sheetMethod=queryCondition.getSheetMethod();
					String[] params=sheetMethod.split("_");
					//正文内容考试的行号索引
					int contentBeginIndex=1; 
					//含有副标题
					if(queryCondition.getSheetSubTitle()!=null)
						contentBeginIndex=2;
					if(params[0].equals("rowSpan")){ 
						  for(int i=1;i>>>>>>>>>>>>>>>>>>>>>>>>>>"+((new Date()).getTime()-s)/1000);
		} catch (Exception e) {
		     e.printStackTrace();
		} finally {
			try {
				fOut.flush();
				fOut.close();
			} catch (Exception e2) {
			}
		}
	}


其中,JXL合并单元格的方法为


package com.cnpc.framework.utils;

import jxl.Cell;
import jxl.write.WritableSheet;

public final class JXLExcelUtil {

	/**
	 * 合并单元格(行合并),合并规则:内容相同则合并
	 * 
	 * @param sheet	       合并的sheet
	 * @param colIndex      合并列索引
	 * @return
	 */
	@SuppressWarnings("deprecation")
	public static WritableSheet rowSpan(WritableSheet sheet, int colindex, int contentBeginIndex) throws Exception {
		// 总行数
		int rowNum = sheet.getRows();
		Cell[] cells = sheet.getRow(1);
		// 正文内容应该从第二行开始,第一行为表头的标题
		int startRow = contentBeginIndex;
		String startValue = "";
		for (int i = contentBeginIndex; i <= rowNum; i++) {
			cells = sheet.getRow(i);
			String value = cells[colindex].getContents();
			if (i == contentBeginIndex) {
				startValue = value;
				continue;
			}
			if (StrUtil.isNotBlank(startValue) && StrUtil.isNotBlank(value) && startValue.equals(value)) {
				if (i == rowNum) //sheet.mergeCells(int col1,int row1,int col2,int row2);//左上角到右下角
					sheet.mergeCells(colindex,startRow, colindex,i);
				else
					continue;
			} else {
				if((i-1)>startRow)
					sheet.mergeCells(colindex,startRow, colindex,i - 1);
				startRow = i;
			}
			startValue=value;
		}
		return sheet;
	}
}

你可能感兴趣的:(web开发,数据导入导出)