2018-11-13 20:40:46 qq_16855077 阅读数 109
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森

前提:

由于本人采取的是利用反射的方式,这样的好处,可以兼容,导出所有类型的数据,例如,订单,充值记录等等。

既然是公有的接口,肯定有一定的约束规范。

(1)导出的表头需要自己设置一个动态数组

(2) 头部的宽度需要自己设置,也可以自己写一个方法,根据字体的长度,形成一个头部的动态数组长度。

(3)返回的实体类,一定要遵循,跟头部一一对应的原则,例如:

导出的实体类,name要显示在excel的第一列,名字就得放在number这个字段的前面

1.pom.xml配置

<!-- poi -->
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>3.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>3.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-scratchpad</artifactId>
			<version>3.8</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml-schemas</artifactId>
			<version>3.8</version>
		</dependency>

2.前端代码

2.1jsp页面代码

 <div class="float-r">
		<a class="red_btn_big addOrEditFoodCategory" type="add" onclick="list.exportReCharge()">+ 导出充值记录</a>
</div>

2.2 js代码

	/**
		 * 导出充值交易信息
		 */
		exportReCharge : function() {
			var methodOfPayment = $('#methodOfPayment option:selected').val();
			var paymentStatus = $('#paymentStatus option:selected').val();
			var serviceType = $('#serviceType option:selected').val();
			var startTime = $('#date0').val();
			var endTime = $('#date1').val();
			var keywords = $('#keywords').val();
			layer.confirm('确定导出充值数据吗?', {
				icon : 3,
				title : '提示'
			}, function(index) {
				window.location.href = "export?search=" + keywords
						+ "&channels=" + methodOfPayment + "&state="
						+ paymentStatus + "&serviceType=" + serviceType
						+ "&startTime=" + startTime + "&endTime=" + endTime;
				layer.close(index);
			});
		}

2.3后台controller代码

@RequestMapping("export")
	public void exportCharge(HttpServletRequest request, HttpServletResponse response, OrderExportVo exportVo) {
		Principal principal = getLoginAdminInfo();
		if (null == principal) {
			logger.info("--------------获取登录用户身份信息为空!");
			return;
		}
		HashMap<String, Object> conditionMap = new HashMap<>();

		try {
			boolean superAdmin = false; // 是否为超级管理员
			if(principal.getOperatorId() != null && StringUtils.isBlank(principal.getTreeIds())){// 非超级管理员
				superAdmin = true;
			} 

			PayOrderInfo payOrderInfo = new PayOrderInfo();
			payOrderInfo.setState(exportVo.getState());
			payOrderInfo.setServiceType(exportVo.getServiceType());
			payOrderInfo.setChannels(exportVo.getChannels());
			
			conditionMap.put("payOrderInfo", payOrderInfo);
			conditionMap.put("superAdmin", superAdmin);
			conditionMap.put("operatorId", principal.getOperatorId());
			conditionMap.put("adminId", principal.getTreeIds());
			conditionMap.put("search", exportVo.getSearch());
			conditionMap.put("startTime", exportVo.getStartTime());
			conditionMap.put("endTime", exportVo.getEndTime());
			Collection<OrderVo> dataset = payOrderInfoMapper.getPayOrderList(conditionMap);
			
			
			for (OrderVo orderVo : dataset) {
				String channelsName = "";
				if(orderVo.getChannels() != null){
					channelsName = ChannelsType.getType(orderVo.getChannels()).getDesc();
				}
				orderVo.setChannelsName(channelsName);
				orderVo.setStateName(OrderState.getType(orderVo.getState()).getDesc());
				String serviceTypeName="";
				if(orderVo.getServiceType() != null){
					serviceTypeName = ServiceType.getType(orderVo.getServiceType()).getDesc();
				}
				orderVo.setServiceTypeName(serviceTypeName);
			}
			
			ExportExcelUtils<OrderVo> excelUtils = new ExportExcelUtils<>();
			SXSSFWorkbook exportExcel = null;
			String[] headers = { "用户名","手机号","充值金额","退款金额", "余额", "充值平台", "订单号", "支付时间", "支付状态", "支付类型", "操作者" };
			int[] widths = {68,90,80,80,80,85,189,140,68,68,68};
			exportExcel = excelUtils.exportExcel("充值", headers,widths, dataset, response.getOutputStream());
			String currentDate = TimeUtils.getCurrentTimeStr("yyyyMMddHHmmss");
			excelUtils.createSXSSFWorkbook(exportExcel, response, "充值记录" + currentDate + ".xlsx");
		} catch (IOException e) {
			logger.info("导出充值交易记录失败!", e.getMessage());
		}
	}

2.4 excel辅助类

package com.parwa.web.util;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 导出Excel工具 
 * @author wude
 *
 * @param <T>
 */
public class ExportExcelUtils<T> {
	private static final Logger logger = LoggerFactory.getLogger(ExportExcelUtils.class);

	public void exportExcel(String title, Collection<T> dataset, OutputStream out) {
		exportExcel(title, null, dataset, out, "yyyy-MM-dd HH:mm:ss");
	}
	
	public void exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out) {
		exportExcel(title, headers, dataset, out, "yyyy-MM-dd HH:mm:ss");
	}
	
	/**
	 * 生成excel
	 * @param title     sheet名称
	 * @param headers   表头
	 * @param width     宽
	 * @param dataset   当前list对象
	 * @param out 
	 * @return
	 */
	public SXSSFWorkbook exportExcel(String title, String[] headers,int[] width,Collection<T> dataset, OutputStream out) {
		SXSSFWorkbook exportExcel = exportBigDataExcel(title, headers,width,dataset, out, "yyyy-MM-dd HH:mm:ss");
		return exportExcel;
	}
	
	/**
	 * 创建excel文档
	 * @param wb
	 * @param response
	 * @param fileName   文件名称
	 * @throws IOException
	 */
    public  void createSXSSFWorkbook(Workbook wb,HttpServletResponse response,String fileName) throws IOException {
        ServletOutputStream out = null;
        try {
            // 设置响应头
            response.addHeader("Content-Disposition", "attachment;filename="
                    + new String(fileName.getBytes("GBK"), "ISO8859_1"));
            out = response.getOutputStream();
            wb.write(out);
        } catch (Exception e) {
        	logger.info("导出excel报错!",e.getMessage());
        } finally {
            if (out != null) {
                    out.close();
            }
        }
    }
	
	
	/**
	 * 利用了JAVA的反射机制,可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
	 * @param title 表格标题名
	 * @param title 列宽度
	 * @param headers 表格属性列名数组
	 * @param dataset 需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)
	 * @param out 与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
	 * @param pattern 如果有时间数据,设定输出格式。默认为"yyy-MM-dd HH:mm:ss"
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public SXSSFWorkbook exportBigDataExcel(String title, String[] headers,int[] width,Collection<T> dataset, OutputStream out, String pattern) {
		/** 声明一个工作簿 **/
		SXSSFWorkbook workbook = new SXSSFWorkbook(100);   //100为内存缓存数据
		if (dataset == null || dataset.size() == 0) {
	            // 防止数据为空的情况下,excel无法打开
			workbook.createSheet();
	        return workbook;
	    }
		/** 声明一个表格 **/
		Sheet sheet = workbook.createSheet(title);
		/** 设置表格默认列宽度为15个字节 **/
		sheet.setDefaultColumnWidth((int) 16);
		sheet.autoSizeColumn(1);
		/** 生成样式,用于表格标题行 **/
		CellStyle style = workbook.createCellStyle();
		/** 设置样式 **/
		style.setFillForegroundColor(IndexedColors.LEMON_CHIFFON.index);
	    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.setColor(IndexedColors.VIOLET.index);
	    font.setFontHeightInPoints((short) 13);
	    font.setBoldweight(Font.BOLDWEIGHT_BOLD);
	    /** 将字体应用到样式中 **/
	    style.setFont(font);
	    
	    /** 样式二,用于表格内容行 **/
	    CellStyle style2 = workbook.createCellStyle();
	    style2.setFillForegroundColor(IndexedColors.WHITE.index);
	    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();
	    font.setFontHeightInPoints((short) 12);
	    font2.setBoldweight(Font.BOLDWEIGHT_NORMAL);
	    font2.setColor(IndexedColors.BLACK.index);
	    style2.setFont(font2);
	    /** 声明画图顶级管理器 **/
	    Drawing patriarch = sheet.createDrawingPatriarch();
	    
	    /** 设置表格标题行 **/
	    Row row = sheet.createRow(0);
	    for (int i = 0; i < headers.length; i++) {
	       Cell cell = row.createCell(i);
	       cell.setCellStyle(style);
	       XSSFRichTextString text = new XSSFRichTextString(headers[i]);
	       cell.setCellValue(text);
	       sheet.setColumnWidth(i, (int) (width[i] * 35.7));
	    }
	    
	    /** 以下是数据内容 **/
	    Iterator<T> it = dataset.iterator();
	    int index = 0;
	    while(it.hasNext() && it != null){
	    	index++;
	    	row = sheet.createRow(index);
	    	T t = (T) it.next();
	    	/** 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值 **/
	    	Field[] fields = t.getClass().getDeclaredFields();
	    	for(int i = 0;i < fields.length;i++){
	    		if(i == headers.length){
	    			break;
	    		}
	    		Cell cell = row.createCell(i);
	            
	            Field field = fields[i];
	            String fieldName = field.getName();
	            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
	            
	            try {
	                Class tCls = t.getClass();
	                Method getMethod = tCls.getMethod(getMethodName, new Class[] {});
	                Object value = getMethod.invoke(t, new Object[] {});
	                /** 判断值的类型后进行强制类型转换 **/
	                String textValue = null;
	                if (value instanceof Boolean) {
	                	boolean bValue = (Boolean) value;
	                	textValue = "是";
	                	if (!bValue) {
	                		textValue ="否";
	                	}
	                } else if (value instanceof Date) {
	                	Date date = (Date) value;
	                	SimpleDateFormat sdf = new SimpleDateFormat(pattern);
	                    textValue = sdf.format(date);
	                } else if (value instanceof byte[]) {
	                	/** 有图片时,设置行高为60px **/
	                	row.setHeightInPoints(60);
	                	/** 设置图片所在列宽度为80px,注意这里单位的一个换算 **/
	                	sheet.setColumnWidth(i, (short) (35.7 * 80));
	                	byte[] bsValue = (byte[]) value;
	                	XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0, 1023, 255, (short) 6, index, (short) 6, index);
	                 	anchor.setAnchorType(2);
	                	patriarch.createPicture(anchor, workbook.addPicture(bsValue, Workbook.PICTURE_TYPE_JPEG));
	                } else if(value instanceof Calendar){
	                	Calendar cale = Calendar.getInstance();  
	                	Date tasktime = cale.getTime();  
	                	SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	                	textValue = df.format(tasktime);
	                } else{
	                	/** 其它数据类型都当作字符串简单处理 **/
	                	if(value != null){
	                		textValue = value.toString();
	                	}
	                }
	                /** 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成 **/
	                if(textValue!=null){
	                	Pattern p = Pattern.compile("^//d+(//.//d+)?$");  
	                	Matcher matcher = p.matcher(textValue);
	                	if(matcher.matches()){
	                		/** 是数字当作double处理 **/
	                		cell.setCellValue(Double.parseDouble(textValue));
	                   }else{
	                	   XSSFRichTextString richString = new XSSFRichTextString(textValue);
	                	   Font font3 = workbook.createFont();
	                	   font3.setColor(IndexedColors.BLACK.index);
	                	   richString.applyFont(font3);
	                	   cell.setCellValue(richString);
	                   }
	                }else{
	                	cell.setCellValue("");
	                }
	            } catch (Exception e) {
	            	e.printStackTrace();
	            	logger.info("导出excel报错!",e.getMessage());
	            } finally {
	                //清理资源
	            }
	            cell.setCellStyle(style2);
	    	}
	    }
		return workbook;
	}
	
	/**
	 * 利用了JAVA的反射机制,可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
	 * @param title 表格标题名
	 * @param headers 表格属性列名数组
	 * @param dataset 需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)
	 * @param out 与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
	 * @param pattern 如果有时间数据,设定输出格式。默认为"yyy-MM-dd HH:mm:ss"
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public HSSFWorkbook exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out, String pattern) {
		/** 声明一个工作簿 **/
		HSSFWorkbook workbook = new HSSFWorkbook();
		/** 声明一个表格 **/
		HSSFSheet sheet = workbook.createSheet(title);
		/** 设置表格默认列宽度为15个字节 **/
		sheet.setDefaultColumnWidth((int) 16);
		sheet.autoSizeColumn(1);
		/** 生成样式,用于表格标题行 **/
		HSSFCellStyle style = workbook.createCellStyle();
		/** 设置样式 **/
		style.setFillForegroundColor(HSSFColor.LEMON_CHIFFON.index);
	    style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
	    style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
	    style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
	    style.setBorderRight(HSSFCellStyle.BORDER_THIN);
	    style.setBorderTop(HSSFCellStyle.BORDER_THIN);
	    style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
	    /** 生成字体 **/
	    HSSFFont font = workbook.createFont();
	    font.setColor(HSSFColor.VIOLET.index);
	    font.setFontHeightInPoints((short) 12);
	    font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
	    /** 将字体应用到样式中 **/
	    style.setFont(font);
	    
	    /** 样式二,用于表格内容行 **/
	    HSSFCellStyle style2 = workbook.createCellStyle();
	    style2.setFillForegroundColor(HSSFColor.WHITE.index);
	    style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
	    style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
	    style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
	    style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
	    style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
	    style2.setAlignment(HSSFCellStyle.ALIGN_LEFT);
	    style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
      	/** 字体二 **/
	    HSSFFont font2 = workbook.createFont();
	    font2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
	    font2.setColor(HSSFColor.BLACK.index);
	    style2.setFont(font2);
	    /** 声明画图顶级管理器 **/
	    HSSFPatriarch patriarch = sheet.createDrawingPatriarch();
	    
	    /** 设置表格标题行 **/
	    HSSFRow row = sheet.createRow(0);
	    for (int i = 0; i < headers.length; i++) {
	       HSSFCell cell = row.createCell(i);
	       cell.setCellStyle(style);
	       HSSFRichTextString text = new HSSFRichTextString(headers[i]);
	       cell.setCellValue(text);
	    }
	    
	    /** 以下是数据内容 **/
	    Iterator<T> it = dataset.iterator();
	    int index = 0;
	    while(it.hasNext() && it != null){
	    	index++;
	    	row = sheet.createRow(index);
	    	T t = (T) it.next();
	    	/** 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值 **/
	    	Field[] fields = t.getClass().getDeclaredFields();
	    	for(int i = 0;i < fields.length;i++){
	    		HSSFCell cell = row.createCell(i);
	            
	            Field field = fields[i];
	            String fieldName = field.getName();
	            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
	            
	            try {
	                Class tCls = t.getClass();
	                Method getMethod = tCls.getMethod(getMethodName, new Class[] {});
	                Object value = getMethod.invoke(t, new Object[] {});
	                /** 判断值的类型后进行强制类型转换 **/
	                String textValue = null;
	                if (value instanceof Boolean) {
	                	boolean bValue = (Boolean) value;
	                	textValue = "是";
	                	if (!bValue) {
	                		textValue ="否";
	                	}
	                } else if (value instanceof Date) {
	                	Date date = (Date) value;
	                	SimpleDateFormat sdf = new SimpleDateFormat(pattern);
	                    textValue = sdf.format(date);
	                } else if (value instanceof byte[]) {
	                	/** 有图片时,设置行高为60px **/
	                	row.setHeightInPoints(60);
	                	/** 设置图片所在列宽度为80px,注意这里单位的一个换算 **/
	                	sheet.setColumnWidth(i, (short) (35.7 * 80));
	                	byte[] bsValue = (byte[]) value;
	                	HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) 6, index, (short) 6, index);
	                 	anchor.setAnchorType(2);
	                	patriarch.createPicture(anchor, workbook.addPicture(bsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));
	                } else if(value instanceof Calendar){
	                	Calendar cale = Calendar.getInstance();  
	                	Date tasktime = cale.getTime();  
	                	SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	                	textValue = df.format(tasktime);
	                } else{
	                	/** 其它数据类型都当作字符串简单处理 **/
	                	if(value != null){
	                		textValue = value.toString();
	                	}
	                }
	                /** 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成 **/
	                if(textValue!=null){
	                	Pattern p = Pattern.compile("^//d+(//.//d+)?$");  
	                	Matcher matcher = p.matcher(textValue);
	                	if(matcher.matches()){
	                		/** 是数字当作double处理 **/
	                		cell.setCellValue(Double.parseDouble(textValue));
	                   }else{
	                	   HSSFRichTextString richString = new HSSFRichTextString(textValue);
	                	   HSSFFont font3 = workbook.createFont();
	                	   font3.setColor(HSSFColor.BLACK.index);
	                	   richString.applyFont(font3);
	                	   cell.setCellValue(richString);
	                   }
	                }else{
	                	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 {
	                //清理资源
	            }
	    	}
	    }
		return workbook;
	}
	
	
	public static void main(String[] args) {
		Timestamp time = TimeUtils.getCurrentTime();
		if(time instanceof Date){
			System.out.println("时间类型");
		}
	}
}

可能存在问题 

实体类

 因为set get是遵守驼峰规则的,按道理生成的get方法应该是getHMaxTemp,但是这里却不是,就是因为h后面接的是大写字母,如果是thMaxTemp,生成的get方法,就是getThMaxTemp,所以编码的时候,保持一个良好的习惯很重要,但是,项目用了一段时间,如果只是这个大小写的问题,就大改动,这样改动量也太大勒,这里我分享另外一种方法。

找到这个工具类的String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);,如上图所示换成下面的图片效果

需要增加一个辅助反射类

ReflectUtil.java


package com.cloudtech.web.util;
 
import java.lang.reflect.Field;
import java.util.ArrayList;

import com.cloudtech.web.entity.RuleCode;
 
public class ReflectUtil {
 
    /**
     * 使用反射设置变量值
     *
     * @param target 被调用对象
     * @param fieldName 被调用对象的字段,一般是成员变量或静态变量,不可是常量!
     * @param value 值
     * @param <T> value类型,泛型
     */
    public static <T> void setValue(Object target,String fieldName,T value) {
        try {
            Class c = target.getClass();
            Field f = c.getDeclaredField(fieldName);
            f.setAccessible(true);
            f.set(target, value);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
 
    /**
     * 使用反射获取变量值
     *
     * @param target 被调用对象
     * @param fieldName 被调用对象的字段,一般是成员变量或静态变量,不可以是常量
     * @param <T> 返回类型,泛型
     * @return 值
     */
    public static <T> T getValue(Object target,String fieldName) {
        T value = null;
        try {
            Class c = target.getClass();
            Field f = c.getDeclaredField(fieldName);
            f.setAccessible(true);
            value = (T) f.get(target);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return value;
    }
    
    public static void main(String[] args) {
		RuleCode code = new RuleCode();
		code.setId(1234);
		//Object value = ReflectUtil.getValue(code, "id");
		System.out.println(code.getId());
    /*	String s ="avgSpd gt hThreeMaxSpd";
    	String replace = s.replace("gt", "");
    	String[] split = replace.split(" ");
    	System.out.println();*/
	}
}

 3.对比

建议用后面这种,毕竟可以兼容实体类字段命名不规范的问题

4.优化后excel辅助类

注意:使用的时候,使用反射方式,去掉多余的代码,使用SXSSFWorkbook,性能更优

package com.cloudtech.web.util;

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;

import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFPatriarch;
import org.apache.poi.hssf.usermodel.HSSFRichTextString;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Drawing;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 导出Excel工具
 * 
 * @author wude
 *
 * @param <T>
 */
public class ExportExcelUtils<T> {
	private static final Logger logger = LoggerFactory.getLogger(ExportExcelUtils.class);

	public void exportExcel(String title, Collection<T> dataset, OutputStream out) {
		exportExcel(title, null, dataset, out, "yyyy-MM-dd HH:mm:ss");
	}

	/**
	 * 生成excel
	 * 
	 * @param title
	 *            sheet名称
	 * @param headers
	 *            表头
	 * @param width
	 *            宽
	 * @param dataset
	 *            当前list对象
	 * @param out
	 * @return
	 */
	public SXSSFWorkbook exportExcel(String title, String[] headers, int[] width, Collection<T> dataset,
			OutputStream out) {
		SXSSFWorkbook exportExcel = exportBigDataExcel(title, headers, width, dataset, out, "yyyy-MM-dd HH:mm:ss");
		return exportExcel;
	}

	public SXSSFWorkbook exportMapExcel(String title, String[] headers, int[] width,
			LinkedHashMap<String, LinkedHashMap<String, Object>> dataset, OutputStream out) {
		SXSSFWorkbook exportExcel = exportBigMapDataExcel(title, headers, width, dataset, out, "yyyy-MM-dd HH:mm:ss");
		return exportExcel;
	}

	/**
	 * 创建excel文档
	 * 
	 * @param wb
	 * @param response
	 * @param fileName
	 *            文件名称
	 * @throws IOException
	 */
	public void createSXSSFWorkbook(Workbook wb, HttpServletResponse response, String fileName) throws IOException {
		ServletOutputStream out = null;
		try {
			// 设置响应头
			response.addHeader("Content-Disposition",
					"attachment;filename=" + new String(fileName.getBytes("GBK"), "ISO8859_1"));
			out = response.getOutputStream();
			wb.write(out);
		} catch (Exception e) {
			logger.info("导出excel报错!", e.getMessage());
		} finally {
			if (out != null) {
				out.close();
			}
		}
	}

	/**
	 * 利用了JAVA的反射机制,可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
	 * 
	 * @param title
	 *            表格标题名
	 * @param title
	 *            列宽度
	 * @param headers
	 *            表格属性列名数组
	 * @param dataset
	 *            需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。
	 *            此方法支持的javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)
	 * @param out
	 *            与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
	 * @param pattern
	 *            如果有时间数据,设定输出格式。默认为"yyy-MM-dd HH:mm:ss"
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public SXSSFWorkbook exportBigDataExcel(String title, String[] headers, int[] width, Collection<T> dataset,
			OutputStream out, String pattern) {
		/** 声明一个工作簿 **/
		SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 100为内存缓存数据
		if (dataset == null || dataset.size() == 0) {
			// 防止数据为空的情况下,excel无法打开
			workbook.createSheet();
			return workbook;
		}
		/** 声明一个表格 **/
		Sheet sheet = workbook.createSheet(title);
		/** 设置表格默认列宽度为15个字节 **/
		sheet.setDefaultColumnWidth((int) 16);
		sheet.autoSizeColumn(1);
		/** 生成样式,用于表格标题行 **/
		CellStyle style = workbook.createCellStyle();
		/** 设置样式 **/
		style.setFillForegroundColor(IndexedColors.LEMON_CHIFFON.index);
		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.setColor(IndexedColors.VIOLET.index);
		font.setFontHeightInPoints((short) 13);
		font.setBoldweight(Font.BOLDWEIGHT_BOLD);
		/** 将字体应用到样式中 **/
		style.setFont(font);

		/** 样式二,用于表格内容行 **/
		CellStyle style2 = workbook.createCellStyle();
		style2.setFillForegroundColor(IndexedColors.WHITE.index);
		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();
		font.setFontHeightInPoints((short) 12);
		font2.setBoldweight(Font.BOLDWEIGHT_NORMAL);
		font2.setColor(IndexedColors.BLACK.index);
		style2.setFont(font2);
		/** 声明画图顶级管理器 **/
		Drawing patriarch = sheet.createDrawingPatriarch();

		/** 设置表格标题行 **/
		Row row = sheet.createRow(0);
		for (int i = 0; i < headers.length; i++) {
			Cell cell = row.createCell(i);
			cell.setCellStyle(style);
			XSSFRichTextString text = new XSSFRichTextString(headers[i]);
			cell.setCellValue(text);
			sheet.setColumnWidth(i, (int) (width[i] * 35.7));
		}

		/** 以下是数据内容 **/
		Iterator<T> it = dataset.iterator();
		int index = 0;
		while (it.hasNext() && it != null) {
			index++;
			row = sheet.createRow(index);
			T t = (T) it.next();
			/** 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值 **/
			Field[] fields = t.getClass().getDeclaredFields();
			for (int i = 0; i < fields.length; i++) {
				if (i == headers.length) {
					break;
				}
				Cell cell = row.createCell(i);

				Field field = fields[i];
				String fieldName = field.getName();

				try {
					Object value = ReflectUtil.getValue(t, fieldName);
					/** 判断值的类型后进行强制类型转换 **/
					String textValue = null;
					if (value == null) {
						cell.setCellValue("");
					} else {
						if (value instanceof Boolean) {
							boolean bValue = (Boolean) value;
							textValue = "是";
							if (!bValue) {
								textValue = "否";
							}
							cell.setCellValue(textValue);
						} else if (value instanceof Date) {
							Date date = (Date) value;
							SimpleDateFormat sdf = new SimpleDateFormat(pattern);
							textValue = sdf.format(date);
							cell.setCellValue(textValue);
						} else if (value instanceof Integer) {
							if (value != null) {
								int intValue = new BigDecimal(value.toString()).intValue();
								cell.setCellValue(intValue);
							}
						} else {
							/** 其它数据类型都当作字符串简单处理 **/
							if (value != null) {
								textValue = value.toString();
								cell.setCellValue(textValue);
							}
						}
					}
				} catch (Exception e) {
					e.printStackTrace();
					logger.info("导出excel报错!", e.getMessage());
				} finally {
					// 清理资源
				}
				cell.setCellStyle(style2);
			}
		}
		return workbook;
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public SXSSFWorkbook exportBigMapDataExcel(String title, String[] headers, int[] width,
			LinkedHashMap<String, LinkedHashMap<String, Object>> dataset, OutputStream out, String pattern) {
		/** 声明一个工作簿 **/
		SXSSFWorkbook workbook = new SXSSFWorkbook(100); // 100为内存缓存数据
		if (dataset == null || dataset.size() == 0) {
			// 防止数据为空的情况下,excel无法打开
			workbook.createSheet();
			return workbook;
		}
		/** 声明一个表格 **/
		Sheet sheet = workbook.createSheet(title);
		/** 设置表格默认列宽度为15个字节 **/
		sheet.setDefaultColumnWidth((int) 16);
		sheet.autoSizeColumn(1);
		/** 生成样式,用于表格标题行 **/
		CellStyle style = workbook.createCellStyle();
		/** 设置样式 **/
		style.setFillForegroundColor(IndexedColors.LEMON_CHIFFON.index);
		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.setColor(IndexedColors.VIOLET.index);
		font.setFontHeightInPoints((short) 13);
		font.setBoldweight(Font.BOLDWEIGHT_BOLD);
		/** 将字体应用到样式中 **/
		style.setFont(font);

		/** 样式二,用于表格内容行 **/
		CellStyle style2 = workbook.createCellStyle();
		style2.setFillForegroundColor(IndexedColors.WHITE.index);
		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();
		font.setFontHeightInPoints((short) 12);
		font2.setBoldweight(Font.BOLDWEIGHT_NORMAL);
		font2.setColor(IndexedColors.BLACK.index);
		style2.setFont(font2);
		/** 声明画图顶级管理器 **/
		Drawing patriarch = sheet.createDrawingPatriarch();

		/** 设置表格标题行 **/
		Row row = sheet.createRow(0);
		for (int i = 0; i < headers.length; i++) {
			Cell cell = row.createCell(i);
			cell.setCellStyle(style);
			XSSFRichTextString text = new XSSFRichTextString(headers[i]);
			cell.setCellValue(text);
			sheet.setColumnWidth(i, (int) (width[i] * 35.7));
		}

		/** 以下是数据内容 **/
		int index = 0;
		for (Entry<String, LinkedHashMap<String, Object>> key : dataset.entrySet()) {
			index++;
			row = sheet.createRow(index);

			Cell cell = row.createCell(0);
			cell.setCellValue(key.getKey());
			cell.setCellStyle(style2);

			LinkedHashMap<String, Object> hourValues = key.getValue();
			int i = 1;
			for (Entry<String, Object> hourKey : hourValues.entrySet()) {
				cell = row.createCell(i);
				try {
					/** 判断值的类型后进行强制类型转换 **/
					String textValue = hourKey.getValue().toString();
					cell.setCellValue(textValue);
				} catch (Exception e) {
					e.printStackTrace();
					logger.info("导出excel报错!", e.getMessage());
				} finally {
					// 清理资源
				}
				cell.setCellStyle(style2);
				i++;
			}
		}
		/*
		 * Iterator<T> it = (Iterator<T>) dataset.keySet().iterator(); int index
		 * = 0; while (it.hasNext() && it != null) { index++; row =
		 * sheet.createRow(index); T t = (T) it.next();
		 *//** 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值 **/
		/*
		 * Field[] fields = t.getClass().getDeclaredFields(); for (int i = 0; i
		 * < fields.length; i++) { if (i == headers.length) { break; } Cell cell
		 * = row.createCell(i);
		 * 
		 * Field field = fields[i]; String fieldName = field.getName(); //
		 * String getMethodName = "get" + fieldName.substring(0, //
		 * 1).toUpperCase() + fieldName.substring(1);
		 * 
		 * try { Class tCls = t.getClass(); Object value =
		 * ReflectUtil.getValue(t, fieldName); // Method getMethod =
		 * tCls.getMethod(getMethodName, new // Class[] {}); // Object value =
		 * getMethod.invoke(t, new Object[] {});
		 *//** 判断值的类型后进行强制类型转换 **/
		/*
		 * String textValue = null; if (value instanceof Boolean) { boolean
		 * bValue = (Boolean) value; textValue = "是"; if (!bValue) { textValue =
		 * "否"; } } else if (value instanceof Date) { Date date = (Date) value;
		 * SimpleDateFormat sdf = new SimpleDateFormat(pattern); textValue =
		 * sdf.format(date); } else if (value instanceof byte[]) {
		 *//** 有图片时,设置行高为60px **/
		/*
		 * row.setHeightInPoints(60);
		 *//** 设置图片所在列宽度为80px,注意这里单位的一个换算 **/
		/*
		 * sheet.setColumnWidth(i, (short) (35.7 * 80)); byte[] bsValue =
		 * (byte[]) value; XSSFClientAnchor anchor = new XSSFClientAnchor(0, 0,
		 * 1023, 255, (short) 6, index, (short) 6, index);
		 * anchor.setAnchorType(2); patriarch.createPicture(anchor,
		 * workbook.addPicture(bsValue, Workbook.PICTURE_TYPE_JPEG)); } else if
		 * (value instanceof Calendar) { Calendar cale = Calendar.getInstance();
		 * Date tasktime = cale.getTime(); SimpleDateFormat df = new
		 * SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); textValue =
		 * df.format(tasktime); } else {
		 *//** 其它数据类型都当作字符串简单处理 **/
		/*
		 * if (value != null) { textValue = value.toString(); } }
		 *//** 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成 **/
		/*
		 * if (textValue != null) { Pattern p =
		 * Pattern.compile("^//d+(//.//d+)?$"); Matcher matcher =
		 * p.matcher(textValue); if (matcher.matches()) {
		 *//** 是数字当作double处理 **//*
								 * cell.setCellValue(Double.parseDouble(
								 * textValue)); } else { XSSFRichTextString
								 * richString = new
								 * XSSFRichTextString(textValue); Font font3 =
								 * workbook.createFont();
								 * font3.setColor(IndexedColors.BLACK.index);
								 * richString.applyFont(font3);
								 * cell.setCellValue(richString); } } else {
								 * cell.setCellValue(""); } } catch (Exception
								 * e) { e.printStackTrace();
								 * logger.info("导出excel报错!", e.getMessage()); }
								 * finally { // 清理资源 }
								 * cell.setCellStyle(style2); } }
								 */
		return workbook;
	}

	/**
	 * 利用了JAVA的反射机制,可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
	 * 
	 * @param title
	 *            表格标题名
	 * @param headers
	 *            表格属性列名数组
	 * @param dataset
	 *            需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。
	 *            此方法支持的javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)
	 * @param out
	 *            与输出设备关联的流对象,可以将EXCEL文档导出到本地文件或者网络中
	 * @param pattern
	 *            如果有时间数据,设定输出格式。默认为"yyy-MM-dd HH:mm:ss"
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public HSSFWorkbook exportExcel(String title, String[] headers, Collection<T> dataset, OutputStream out,
			String pattern) {
		/** 声明一个工作簿 **/
		HSSFWorkbook workbook = new HSSFWorkbook();
		/** 声明一个表格 **/
		HSSFSheet sheet = workbook.createSheet(title);
		/** 设置表格默认列宽度为15个字节 **/
		sheet.setDefaultColumnWidth((int) 16);
		sheet.autoSizeColumn(1);
		/** 生成样式,用于表格标题行 **/
		HSSFCellStyle style = workbook.createCellStyle();
		/** 设置样式 **/
		style.setFillForegroundColor(HSSFColor.LEMON_CHIFFON.index);
		style.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		style.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		style.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		style.setBorderRight(HSSFCellStyle.BORDER_THIN);
		style.setBorderTop(HSSFCellStyle.BORDER_THIN);
		style.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		/** 生成字体 **/
		HSSFFont font = workbook.createFont();
		font.setColor(HSSFColor.VIOLET.index);
		font.setFontHeightInPoints((short) 12);
		font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD);
		/** 将字体应用到样式中 **/
		style.setFont(font);

		/** 样式二,用于表格内容行 **/
		HSSFCellStyle style2 = workbook.createCellStyle();
		style2.setFillForegroundColor(HSSFColor.WHITE.index);
		style2.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		style2.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		style2.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		style2.setBorderRight(HSSFCellStyle.BORDER_THIN);
		style2.setBorderTop(HSSFCellStyle.BORDER_THIN);
		style2.setAlignment(HSSFCellStyle.ALIGN_LEFT);
		style2.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER);
		/** 字体二 **/
		HSSFFont font2 = workbook.createFont();
		font2.setBoldweight(HSSFFont.BOLDWEIGHT_NORMAL);
		font2.setColor(HSSFColor.BLACK.index);
		style2.setFont(font2);
		/** 声明画图顶级管理器 **/
		HSSFPatriarch patriarch = sheet.createDrawingPatriarch();

		/** 设置表格标题行 **/
		HSSFRow row = sheet.createRow(0);
		for (int i = 0; i < headers.length; i++) {
			HSSFCell cell = row.createCell(i);
			cell.setCellStyle(style);
			HSSFRichTextString text = new HSSFRichTextString(headers[i]);
			cell.setCellValue(text);
		}

		/** 以下是数据内容 **/
		Iterator<T> it = dataset.iterator();
		int index = 0;
		while (it.hasNext() && it != null) {
			index++;
			row = sheet.createRow(index);
			T t = (T) it.next();
			/** 利用反射,根据javabean属性的先后顺序,动态调用getXxx()方法得到属性值 **/
			Field[] fields = t.getClass().getDeclaredFields();
			for (int i = 0; i < fields.length; i++) {
				HSSFCell cell = row.createCell(i);

				Field field = fields[i];
				String fieldName = field.getName();
				String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

				try {
					Class tCls = t.getClass();
					Method getMethod = tCls.getMethod(getMethodName, new Class[] {});
					Object value = getMethod.invoke(t, new Object[] {});
					/** 判断值的类型后进行强制类型转换 **/
					String textValue = null;
					if (value instanceof Boolean) {
						boolean bValue = (Boolean) value;
						textValue = "是";
						if (!bValue) {
							textValue = "否";
						}
					} else if (value instanceof Date) {
						Date date = (Date) value;
						SimpleDateFormat sdf = new SimpleDateFormat(pattern);
						textValue = sdf.format(date);
					} else if (value instanceof byte[]) {
						/** 有图片时,设置行高为60px **/
						row.setHeightInPoints(60);
						/** 设置图片所在列宽度为80px,注意这里单位的一个换算 **/
						sheet.setColumnWidth(i, (short) (35.7 * 80));
						byte[] bsValue = (byte[]) value;
						HSSFClientAnchor anchor = new HSSFClientAnchor(0, 0, 1023, 255, (short) 6, index, (short) 6,
								index);
						anchor.setAnchorType(2);
						patriarch.createPicture(anchor, workbook.addPicture(bsValue, HSSFWorkbook.PICTURE_TYPE_JPEG));
					} else if (value instanceof Calendar) {
						Calendar cale = Calendar.getInstance();
						Date tasktime = cale.getTime();
						SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
						textValue = df.format(tasktime);
					} else {
						/** 其它数据类型都当作字符串简单处理 **/
						if (value != null) {
							textValue = value.toString();
						}
					}
					/** 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成 **/
					if (textValue != null) {
						Pattern p = Pattern.compile("^//d+(//.//d+)?$");
						Matcher matcher = p.matcher(textValue);
						if (matcher.matches()) {
							/** 是数字当作double处理 **/
							cell.setCellValue(Double.parseDouble(textValue));
						} else {
							HSSFRichTextString richString = new HSSFRichTextString(textValue);
							HSSFFont font3 = workbook.createFont();
							font3.setColor(HSSFColor.BLACK.index);
							richString.applyFont(font3);
							cell.setCellValue(richString);
						}
					} else {
						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 {
					// 清理资源
				}
			}
		}
		return workbook;
	}

	public static void main(String[] args) {
		Timestamp time = TimeUtils.getCurrentTime();
		if (time instanceof Date) {
			System.out.println("时间类型");
		}
	}

}

4.性能分析

列有69列,导出excel分析

优化前:

通过图片,我们可以发现sql的时间很长,当然跟我的列有关,69列

5w数据需要31.42s,而1w数据是6.5s,我们是不是可以做一些优化。列入拿1w作为切割,5w数据分为5次查询出来,再组装数据,是不是可以提升查询数据。所以,这里需要使用多线程。这样整个导出的时长就短了不少。

 

优化后:

通过数据分析,发现,性能方面有质的提高,而且缓存数大小,性能没有什么明显的提示,所以建议缓存数还是设置为100把 

 

缓存数:

设置为100后,超过100的部分会写入硬盘,而不是所有的都存放在内存中

性能优化部分: 

/** 如果不是图片数据,就利用正则表达式判断textValue是否全部由数字组成 **/
					if (textValue != null) {
						Pattern p = Pattern.compile("^//d+(//.//d+)?$");
						Matcher matcher = p.matcher(textValue);
						if (matcher.matches()) {
							/** 是数字当作double处理 **/
							cell.setCellValue(Double.parseDouble(textValue));
						} else {
							XSSFRichTextString richString = new XSSFRichTextString(textValue);
							Font font3 = workbook.createFont();
							font3.setColor(IndexedColors.BLACK.index);
							richString.applyFont(font3);
							cell.setCellValue(richString);
						}
					} else {
						cell.setCellValue("");
					}

主要是正则方面的判断,消耗勒大量的数据,导致时间很长

2017-06-21 19:00:00 ajing4030 阅读数 837
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森

2007格式:

excel2007文件格式与之前版本不同,之前版本采用的是微软自己的存储格式。07版内容的存储采用XML格式,所以,理所当然的,对大数据量的xlsx文件的读取采用的也是XML的处理方式SAX。

    同之前的版本一样,大数据量文件的读取采用的是事件模型eventusermodel。usermodel模式需要将文件一次性全部读到内存中,07版的既然采用的存储模式是xml,解析用的DOM方式也是如此,这种模式操作简单,容易上手,但是对于大量数据占用的内存也是相当可观,在Eclipse中经常出现内存溢出。

    下面就是采用eventusermodel对07excel文件读取。

    同上篇,我将当前行的单元格数据存储到List中,抽象出 optRows 方法,该方法会在每行末尾时调用,方法参数为当前行索引curRow(int型)及存有行内单元格数据的List。继承类只需实现该行级方法即可。

  1. package com.gaosheng.util.xls;  
  2.   
  3. import java.io.InputStream;  
  4. import java.sql.SQLException;  
  5. import java.util.ArrayList;  
  6. import java.util.Iterator;  
  7. import java.util.List;  
  8.   
  9. import org.apache.poi.xssf.eventusermodel.XSSFReader;  
  10. import org.apache.poi.xssf.model.SharedStringsTable;  
  11. import org.apache.poi.xssf.usermodel.XSSFRichTextString;  
  12. import org.apache.poi.openxml4j.opc.OPCPackage;  
  13. import org.xml.sax.Attributes;  
  14. import org.xml.sax.InputSource;  
  15. import org.xml.sax.SAXException;  
  16. import org.xml.sax.XMLReader;  
  17. import org.xml.sax.helpers.DefaultHandler;  
  18. import org.xml.sax.helpers.XMLReaderFactory;  
  19.   
  20. /** 
  21.  * XSSF and SAX (Event API) 
  22.  */  
  23. public abstract class XxlsAbstract extends DefaultHandler {  
  24.     private SharedStringsTable sst;  
  25.     private String lastContents;  
  26.     private boolean nextIsString;  
  27.   
  28.     private int sheetIndex = -1;  
  29.     private List<String> rowlist = new ArrayList<String>();  
  30.     private int curRow = 0;     //当前行  
  31.     private int curCol = 0;     //当前列索引  
  32.     private int preCol = 0;     //上一列列索引  
  33.     private int titleRow = 0;   //标题行,一般情况下为0  
  34.     private int rowsize = 0;    //列数  
  35.       
  36.     //excel记录行操作方法,以行索引和行元素列表为参数,对一行元素进行操作,元素为String类型  
  37. //  public abstract void optRows(int curRow, List<String> rowlist) throws SQLException ;  
  38.       
  39.     //excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型  编写自己的业务
  40.     public abstract void optRows(int sheetIndex,int curRow, List<String> rowlist) throws SQLException;  
  41.       
  42.     //只遍历一个sheet,其中sheetId为要遍历的sheet索引,从1开始,1-3  
  43.     public void processOneSheet(String filename,int sheetId) throws Exception {  
  44.         OPCPackage pkg = OPCPackage.open(filename);  
  45.         XSSFReader r = new XSSFReader(pkg);  
  46.         SharedStringsTable sst = r.getSharedStringsTable();  
  47.           
  48.         XMLReader parser = fetchSheetParser(sst);  
  49.   
  50.         // rId2 found by processing the Workbook  
  51.         // 根据 rId# 或 rSheet# 查找sheet  
  52.         InputStream sheet2 = r.getSheet("rId"+sheetId);  
  53.         sheetIndex++;  
  54.         InputSource sheetSource = new InputSource(sheet2);  
  55.         parser.parse(sheetSource);  
  56.         sheet2.close();  
  57.     }  
  58.   
  59.     /** 
  60.      * 遍历 excel 文件 
  61.      */  
  62.     public void process(String filename) throws Exception {  
  63.         OPCPackage pkg = OPCPackage.open(filename);  
  64.         XSSFReader r = new XSSFReader(pkg);  
  65.         SharedStringsTable sst = r.getSharedStringsTable();  
  66.   
  67.         XMLReader parser = fetchSheetParser(sst);  
  68.   
  69.         Iterator<InputStream> sheets = r.getSheetsData();  
  70.         while (sheets.hasNext()) {  
  71.             curRow = 0;  
  72.             sheetIndex++;  
  73.             InputStream sheet = sheets.next();  
  74.             InputSource sheetSource = new InputSource(sheet);  
  75.             parser.parse(sheetSource);  
  76.             sheet.close();  
  77.         }  
  78.     }  
  79.   
  80.     public XMLReader fetchSheetParser(SharedStringsTable sst)  
  81.             throws SAXException {  
  82.         XMLReader parser = XMLReaderFactory  
  83.                 .createXMLReader("org.apache.xerces.parsers.SAXParser");  
  84.         this.sst = sst;  
  85.         parser.setContentHandler(this);  
  86.         return parser;  
  87.     }  
  88.   
  89.     public void startElement(String uri, String localName, String name,  
  90.             Attributes attributes) throws SAXException {  
  91.         // c => 单元格  
  92.         if (name.equals("c")) {  
  93.             // 如果下一个元素是 SST 的索引,则将nextIsString标记为true  
  94.             String cellType = attributes.getValue("t");  
  95.             String rowStr = attributes.getValue("r");  
  96.             curCol = this.getRowIndex(rowStr);  
  97.             if (cellType != null && cellType.equals("s")) {  
  98.                 nextIsString = true;  
  99.             } else {  
  100.                 nextIsString = false;  
  101.             }  
  102.         }  
  103.         // 置空  
  104.         lastContents = "";  
  105.     }  
  106.   
  107.     public void endElement(String uri, String localName, String name)  
  108.             throws SAXException {  
  109.         // 根据SST的索引值的到单元格的真正要存储的字符串  
  110.         // 这时characters()方法可能会被调用多次  
  111.         if (nextIsString) {  
  112.             try {  
  113.                 int idx = Integer.parseInt(lastContents);  
  114.                 lastContents = new XSSFRichTextString(sst.getEntryAt(idx))  
  115.                         .toString();  
  116.             } catch (Exception e) {  
  117.   
  118.             }  
  119.         }  
  120.   
  121.         // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引  
  122.         // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符  
  123.         if (name.equals("v")) {  
  124.             String value = lastContents.trim();  
  125.             value = value.equals("")?" ":value;  
  126.             int cols = curCol-preCol;  
  127.             if (cols>1){  
  128.                 for (int i = 0;i < cols-1;i++){  
  129.                     rowlist.add(preCol,"");  
  130.                 }  
  131.             }  
  132.             preCol = curCol;  
  133.             rowlist.add(curCol-1, value);  
  134.         }else {  
  135.             //如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法  
  136.             if (name.equals("row")) {  
  137.                 int tmpCols = rowlist.size();  
  138.                 if(curRow>this.titleRow && tmpCols<this.rowsize){  
  139.                     for (int i = 0;i < this.rowsize-tmpCols;i++){  
  140.                         rowlist.add(rowlist.size(), "");  
  141.                     }  
  142.                 }  
  143.                 try {  
  144.                     optRows(sheetIndex,curRow,rowlist);  
  145.                 } catch (SQLException e) {  
  146.                     e.printStackTrace();  
  147.                 }  
  148.                 if(curRow==this.titleRow){  
  149.                     this.rowsize = rowlist.size();  
  150.                 }  
  151.                 rowlist.clear();  
  152.                 curRow++;  
  153.                 curCol = 0;  
  154.                 preCol = 0;  
  155.             }  
  156.         }  
  157.     }  
  158.   
  159.     public void characters(char[] ch, int start, int length)  
  160.             throws SAXException {  
  161.         //得到单元格内容的值  
  162.         lastContents += new String(ch, start, length);  
  163.     }  
  164.       
  165.     //得到列索引,每一列c元素的r属性构成为字母加数字的形式,字母组合为列索引,数字组合为行索引,  
  166.     //如AB45,表示为第(A-A+1)*26+(B-A+1)*26列,45行  
  167.     public int getRowIndex(String rowStr){  
  168.         rowStr = rowStr.replaceAll("[^A-Z]""");  
  169.         byte[] rowAbc = rowStr.getBytes();  
  170.         int len = rowAbc.length;  
  171.         float num = 0;  
  172.         for (int i=0;i<len;i++){  
  173.             num += (rowAbc[i]-'A'+1)*Math.pow(26,len-i-1 );  
  174.         }  
  175.         return (int) num;  
  176.     }  
  177.   
  178.     public int getTitleRow() {  
  179.         return titleRow;  
  180.     }  
  181.   
  182.     public void setTitleRow(int titleRow) {  
  183.         this.titleRow = titleRow;  
  184.     }  
  185. }  



20003格式:

  1. package com.gaosheng.util.xls;  
  2. import java.io.FileInputStream;  
  3. import java.io.FileNotFoundException;  
  4. import java.io.IOException;  
  5. import java.io.PrintStream;  
  6. import java.sql.SQLException;  
  7. import java.util.ArrayList;  
  8. import java.util.List;  
  9.   
  10. import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener;  
  11. import org.apache.poi.hssf.eventusermodel.HSSFEventFactory;  
  12. import org.apache.poi.hssf.eventusermodel.HSSFListener;  
  13. import org.apache.poi.hssf.eventusermodel.HSSFRequest;  
  14. import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener;  
  15. import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder.SheetRecordCollectingListener;  
  16. import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord;  
  17. import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord;  
  18. import org.apache.poi.hssf.model.HSSFFormulaParser;  
  19. import org.apache.poi.hssf.record.BOFRecord;  
  20. import org.apache.poi.hssf.record.BlankRecord;  
  21. import org.apache.poi.hssf.record.BoolErrRecord;  
  22. import org.apache.poi.hssf.record.BoundSheetRecord;  
  23. import org.apache.poi.hssf.record.FormulaRecord;  
  24. import org.apache.poi.hssf.record.LabelRecord;  
  25. import org.apache.poi.hssf.record.LabelSSTRecord;  
  26. import org.apache.poi.hssf.record.NoteRecord;  
  27. import org.apache.poi.hssf.record.NumberRecord;  
  28. import org.apache.poi.hssf.record.RKRecord;  
  29. import org.apache.poi.hssf.record.Record;  
  30. import org.apache.poi.hssf.record.SSTRecord;  
  31. import org.apache.poi.hssf.record.StringRecord;  
  32. import org.apache.poi.hssf.usermodel.HSSFWorkbook;  
  33. import org.apache.poi.poifs.filesystem.POIFSFileSystem;  
  34.   
  35. public abstract class HxlsAbstract implements HSSFListener {  
  36.     private int minColumns;  
  37.     private POIFSFileSystem fs;  
  38.     private PrintStream output;  
  39.   
  40.     private int lastRowNumber;  
  41.     private int lastColumnNumber;  
  42.   
  43.     /** Should we output the formula, or the value it has? */  
  44.     private boolean outputFormulaValues = true;  
  45.   
  46.     /** For parsing Formulas */  
  47.     private SheetRecordCollectingListener workbookBuildingListener;  
  48.     private HSSFWorkbook stubWorkbook;  
  49.   
  50.     // Records we pick up as we process  
  51.     private SSTRecord sstRecord;  
  52.     private FormatTrackingHSSFListener formatListener;  
  53.   
  54.     /** So we known which sheet we're on */  
  55.     private int sheetIndex = -1;  
  56.     private BoundSheetRecord[] orderedBSRs;  
  57.     @SuppressWarnings("unchecked")  
  58.     private ArrayList boundSheetRecords = new ArrayList();  
  59.   
  60.     // For handling formulas with string results  
  61.     private int nextRow;  
  62.     private int nextColumn;  
  63.     private boolean outputNextStringRecord;  
  64.   
  65.     private int curRow;  
  66.     private List<String> rowlist;  
  67.     @SuppressWarnings"unused")  
  68.     private String sheetName;  
  69.   
  70.     public HxlsAbstract(POIFSFileSystem fs)  
  71.             throws SQLException {  
  72.         this.fs = fs;  
  73.         this.output = System.out;  
  74.         this.minColumns = -1;  
  75.         this.curRow = 0;  
  76.         this.rowlist = new ArrayList<String>();  
  77.     }  
  78.   
  79.     public HxlsAbstract(String filename) throws IOException,  
  80.             FileNotFoundException, SQLException {  
  81.         this(new POIFSFileSystem(new FileInputStream(filename)));  
  82.     }  
  83.       
  84.     //excel记录行操作方法,以行索引和行元素列表为参数,对一行元素进行操作,元素为String类型  
  85. //  public abstract void optRows(int curRow, List<String> rowlist) throws SQLException ;  
  86.       
  87.     //excel记录行操作方法,以sheet索引,行索引和行元素列表为参数,对sheet的一行元素进行操作,元素为String类型  
  88.     public abstract void optRows(int sheetIndex,int curRow, List<String> rowlist) throws SQLException;  
  89.       
  90.     /** 
  91.      * 遍历 excel 文件 
  92.      */  
  93.     public void process() throws IOException {  
  94.         MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(  
  95.                 this);  
  96.         formatListener = new FormatTrackingHSSFListener(listener);  
  97.   
  98.         HSSFEventFactory factory = new HSSFEventFactory();  
  99.         HSSFRequest request = new HSSFRequest();  
  100.   
  101.         if (outputFormulaValues) {  
  102.             request.addListenerForAllRecords(formatListener);  
  103.         } else {  
  104.             workbookBuildingListener = new SheetRecordCollectingListener(  
  105.                     formatListener);  
  106.             request.addListenerForAllRecords(workbookBuildingListener);  
  107.         }  
  108.   
  109.         factory.processWorkbookEvents(request, fs);  
  110.     }  
  111.       
  112.     /** 
  113.      * HSSFListener 监听方法,处理 Record 
  114.      */  
  115.     @SuppressWarnings("unchecked")  
  116.     public void processRecord(Record record) {  
  117.         int thisRow = -1;  
  118.         int thisColumn = -1;  
  119.         String thisStr = null;  
  120.         String value = null;  
  121.           
  122.         switch (record.getSid()) {  
  123.         case BoundSheetRecord.sid:  
  124.             boundSheetRecords.add(record);  
  125.             break;  
  126.         case BOFRecord.sid:  
  127.             BOFRecord br = (BOFRecord) record;  
  128.             if (br.getType() == BOFRecord.TYPE_WORKSHEET) {  
  129.                 // Create sub workbook if required  
  130.                 if (workbookBuildingListener != null && stubWorkbook == null) {  
  131.                     stubWorkbook = workbookBuildingListener  
  132.                             .getStubHSSFWorkbook();  
  133.                 }  
  134.   
  135.                 // Works by ordering the BSRs by the location of  
  136.                 // their BOFRecords, and then knowing that we  
  137.                 // process BOFRecords in byte offset order  
  138.                 sheetIndex++;  
  139.                 if (orderedBSRs == null) {  
  140.                     orderedBSRs = BoundSheetRecord  
  141.                             .orderByBofPosition(boundSheetRecords);  
  142.                 }  
  143.                 sheetName = orderedBSRs[sheetIndex].getSheetname();  
  144.             }  
  145.             break;  
  146.   
  147.         case SSTRecord.sid:  
  148.             sstRecord = (SSTRecord) record;  
  149.             break;  
  150.   
  151.         case BlankRecord.sid:  
  152.             BlankRecord brec = (BlankRecord) record;  
  153.   
  154.             thisRow = brec.getRow();  
  155.             thisColumn = brec.getColumn();  
  156.             thisStr = "";  
  157.             break;  
  158.         case BoolErrRecord.sid:  
  159.             BoolErrRecord berec = (BoolErrRecord) record;  
  160.   
  161.             thisRow = berec.getRow();  
  162.             thisColumn = berec.getColumn();  
  163.             thisStr = "";  
  164.             break;  
  165.   
  166.         case FormulaRecord.sid:  
  167.             FormulaRecord frec = (FormulaRecord) record;  
  168.   
  169.             thisRow = frec.getRow();  
  170.             thisColumn = frec.getColumn();  
  171.   
  172.             if (outputFormulaValues) {  
  173.                 if (Double.isNaN(frec.getValue())) {  
  174.                     // Formula result is a string  
  175.                     // This is stored in the next record  
  176.                     outputNextStringRecord = true;  
  177.                     nextRow = frec.getRow();  
  178.                     nextColumn = frec.getColumn();  
  179.                 } else {  
  180.                     thisStr = formatListener.formatNumberDateCell(frec);  
  181.                 }  
  182.             } else {  
  183.                 thisStr = '"' + HSSFFormulaParser.toFormulaString(stubWorkbook,  
  184.                         frec.getParsedExpression()) + '"';  
  185.             }  
  186.             break;  
  187.         case StringRecord.sid:  
  188.             if (outputNextStringRecord) {  
  189.                 // String for formula  
  190.                 StringRecord srec = (StringRecord) record;  
  191.                 thisStr = srec.getString();  
  192.                 thisRow = nextRow;  
  193.                 thisColumn = nextColumn;  
  194.                 outputNextStringRecord = false;  
  195.             }  
  196.             break;  
  197.   
  198.         case LabelRecord.sid:  
  199.             LabelRecord lrec = (LabelRecord) record;  
  200.   
  201.             curRow = thisRow = lrec.getRow();  
  202.             thisColumn = lrec.getColumn();  
  203.             value = lrec.getValue().trim();  
  204.             value = value.equals("")?" ":value;  
  205.             this.rowlist.add(thisColumn, value);  
  206.             break;  
  207.         case LabelSSTRecord.sid:  
  208.             LabelSSTRecord lsrec = (LabelSSTRecord) record;  
  209.   
  210.             curRow = thisRow = lsrec.getRow();  
  211.             thisColumn = lsrec.getColumn();  
  212.             if (sstRecord == null) {  
  213.                 rowlist.add(thisColumn, " ");  
  214.             } else {  
  215.                 value =  sstRecord  
  216.                 .getString(lsrec.getSSTIndex()).toString().trim();  
  217.                 value = value.equals("")?" ":value;  
  218.                 rowlist.add(thisColumn,value);  
  219.             }  
  220.             break;  
  221.         case NoteRecord.sid:  
  222.             NoteRecord nrec = (NoteRecord) record;  
  223.   
  224.             thisRow = nrec.getRow();  
  225.             thisColumn = nrec.getColumn();  
  226.             // TODO: Find object to match nrec.getShapeId()  
  227.             thisStr = '"' + "(TODO)" + '"';  
  228.             break;  
  229.         case NumberRecord.sid:  
  230.             NumberRecord numrec = (NumberRecord) record;  
  231.   
  232.             curRow = thisRow = numrec.getRow();  
  233.             thisColumn = numrec.getColumn();  
  234.             value = formatListener.formatNumberDateCell(numrec).trim();  
  235.             value = value.equals("")?" ":value;  
  236.             // Format  
  237.             rowlist.add(thisColumn, value);  
  238.             break;  
  239.         case RKRecord.sid:  
  240.             RKRecord rkrec = (RKRecord) record;  
  241.   
  242.             thisRow = rkrec.getRow();  
  243.             thisColumn = rkrec.getColumn();  
  244.             thisStr = '"' + "(TODO)" + '"';  
  245.             break;  
  246.         default:  
  247.             break;  
  248.         }  
  249.   
  250.         // 遇到新行的操作  
  251.         if (thisRow != -1 && thisRow != lastRowNumber) {  
  252.             lastColumnNumber = -1;  
  253.         }  
  254.   
  255.         // 空值的操作  
  256.         if (record instanceof MissingCellDummyRecord) {  
  257.             MissingCellDummyRecord mc = (MissingCellDummyRecord) record;  
  258.             curRow = thisRow = mc.getRow();  
  259.             thisColumn = mc.getColumn();  
  260.             rowlist.add(thisColumn," ");  
  261.         }  
  262.   
  263.         // 如果遇到能打印的东西,在这里打印  
  264.         if (thisStr != null) {  
  265.             if (thisColumn > 0) {  
  266.                 output.print(',');  
  267.             }  
  268.             output.print(thisStr);  
  269.         }  
  270.   
  271.         // 更新行和列的值  
  272.         if (thisRow > -1)  
  273.             lastRowNumber = thisRow;  
  274.         if (thisColumn > -1)  
  275.             lastColumnNumber = thisColumn;  
  276.   
  277.         // 行结束时的操作  
  278.         if (record instanceof LastCellOfRowDummyRecord) {  
  279.             if (minColumns > 0) {  
  280.                 // 列值重新置空  
  281.                 if (lastColumnNumber == -1) {  
  282.                     lastColumnNumber = 0;  
  283.                 }  
  284.             }  
  285.             // 行结束时, 调用 optRows() 方法  
  286.             lastColumnNumber = -1;  
  287.             try {  
  288.                 optRows(sheetIndex,curRow, rowlist);  
  289.             } catch (SQLException e) {  
  290.                 e.printStackTrace();  
  291.             }  
  292.             rowlist.clear();  
  293.         }  
  294.     }  
  295. }  


###########大数据导出导出时采用SXSSFWorkbook处理大数据###################
/**创建空模板 利用SXSSF技术,降低内存使用率**/

Workbook wb =  new SXSSFWorkbook(1000);
Sheet sheet = wb.createSheet();

spring在上传excel文件时,有时候会有缓存,即上传的excel解析后会有重复,所有contrllor层时,一定要使用注解@scoper='prototype"

2013-04-28 16:27:48 wangweiyan89 阅读数 4090
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森

工作中遇到大数据导出excel内存溢出的问题,在使用jxl和POI3.8之前的版本都找不到很好的解决办法,通过设置jvm内存效果也不理想。但是在POI3.8以上版本中提供了SXSSFWorkbook的新类,可以通过参数设置常驻内存中的行数,防止OOM异常!

但是SXSSFWorkbook仅仅支持excel2007格式,也就是说SXSSFWorkbook只支持.xlsx格式,不支持.xls格式。在写入excel时,需要生成大量的数据的时候,通过刷新的方式将excel内存信息刷新到硬盘的方式,提供写入数据的效率。以下是导出的例子:

import junit.framework.Assert;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellReference;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

    public static void main(String[] args) throws Throwable {
        SXSSFWorkbook wb = new SXSSFWorkbook(100); //设置最大行数,如果不想做限制可以设置为-1
        Sheet sh = wb.createSheet();
        for(int rownum = 0; rownum < 1000; rownum++){
            Row row = sh.createRow(rownum);
            for(int cellnum = 0; cellnum < 10; cellnum++){
                Cell cell = row.createCell(cellnum);
                String address = new CellReference(cell).formatAsString();
                cell.setCellValue(address);
            }

        }

        // Rows with rownum < 900 are flushed and not accessible
        for(int rownum = 0; rownum < 900; rownum++){
          Assert.assertNull(sh.getRow(rownum));
        }

        // ther last 100 rows are still in memory
        for(int rownum = 900; rownum < 1000; rownum++){
            Assert.assertNotNull(sh.getRow(rownum));
        }
        
        FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx");
        wb.write(out);
        out.close();

        // dispose of temporary files backing this workbook on disk
        wb.dispose();
    }
但是有些客户要求是2003excel,当导大数据是就比较复杂,下面的连接是我在网上看的一些资料,网上的做法大多数是分批导出之后再打包成压缩文件供用户下载,也有的是导出后再合并多个excel文件的方式!!

http://blog.csdn.net/yrsheng/article/details/4100393

2011-03-31 13:23:10 aeoluswind 阅读数 19
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森
[url=http://www.neverevernote.com/?p=17]excel的大数据量用POI写入 香菜个人博客[/url]

昨天刚解决了POI的大数据量写,今天又碰到一个问题,客户把50万的数据用excel传了过来T.T
普通的读取依然会OOM

无奈继续查资料。记得看到一篇文章上说XSSF默认用DOM解析XML的,那必然会OOM了,于是开始找用SAX读的例子,找到了应该比较经典的FromHowTo.java(http://svn.apache.org/repos/asf/poi/trunk/src/examples/src/org/apache/poi/xssf/eventusermodel/examples/FromHowTo.java)

用这个例子还是碰到了挺多问题
1. 写入的逻辑会嵌入到这个读取里..它并没有提供比较友好的getRow之类的一行一行处理的方法..导致我的代码写地很猥琐..
2. SharedStringsTable sst = r.getSharedStringsTable();这段代码依然会抛OOM. 看提问频道有一个哥们也碰到了同样的问题..都已经用SAX解析了还是OOM是挺尴尬的..目前的解决方法是开大了一些内存..- -..简单有效..基本上代码跑过了这行以后的读取就不怕OOM了..
2019-08-01 15:59:18 weixin_40049583 阅读数 36
  • 基于SSM的POI导入导出Excel实战

    本课程将给大家分享如何基于SSM实现POI导入导出Excel,并讲解目前企业级JavaWeb应用mvc三层模式的开发流程,可让初学者或者职场萌新掌握如何基于SSM整合第三方框架并采用mvc三层开发模式实现自己的业务模块!

    1265 人正在学习 去看看 钟林森

百万数据POI操作(一)

概述

​ 我们都知道Excel可以分为早期的Excel2003版本(使用POI的HSSF对象操作)和Excel2007版本(使用POI的XSSF操作),两者对百万数据的支持如下:

  • Excel 2003:在POI中使用HSSF对象时,excel 2003最多只允许存储65536条数据,一般用来处理较少的数据量。这时对于百万级别数据,Excel肯定容纳不了。
  • Excel 2007:当POI升级到XSSF对象时,它可以直接支持excel2007以上版本,因为它采用ooxml格式。这时excel可以支持1048576条数据,单个sheet表就支持近百万条数据。但实际运行时还可能存在问题,原因是执行POI报表所产生的行对象,单元格对象,字体对象,他们都不会销毁,这就导致OOM的风险

JDK性能监控工具

没有性能监控工具一切推论都只能停留在理论阶段,我们可以使用Java的性能监控工具来监视程序的运行情况,包括CUP,垃圾回收,内存的分配和使用情况,这让程序的运行阶段变得更加可控,也可以用来证明我们的推测。这里我们使用JDK提供的性能工具Jvisualvm来监控程序运行。

​ VisualVM 是Netbeans的profile子项目,已在JDK中自带,能够监控线程,内存情况,查看方法的CPU时间和内存中的对 象,已被GC的对象,反向查看分配的堆栈。

​ Jvisualvm位于JAVA_HOME/bin目录下,直接双击就可以打开该程序。如果只是监控本地的java进程,是不需要配置参数的,直接打开就能够进行监控。首先我们需要在本地打开一个Java程序,例如我打开员工后台管理系统进程,这时在jvisualvm界面就可以看到与IDEA相关的Java进程了

Jvisualvm的使用

Jvisualvm使用起来比较简单,双击点击当前运行的进程即可进入到程序的监控界面:

在这里插入图片描述

  • 双击Jvisualvm.exe

在这里插入图片描述

  • 概述:可以看到进程的启动参数。
  • 监视:左上:cpu利用率,gc状态的监控,右上:堆利用率,永久内存区的利用率,左下:类的监控,右下:线程的监控
  • 线程:能够显示线程的名称和运行的状态,在调试多线程时必不可少,而且可以点进一个线程查看这个线程的详细运行情况

百万数据POI操作(二)SXSSFWorkBook处理百万数据报表打印

需求

使用Apache POI完成百万数据量的Excel报表导出。

分析

​ 基于XSSFWork导出Excel报表,是通过将所有单元格对象保存到内存中,当所有的Excel单元格全部创建完成之后一次性写入到Excel并导出。当百万数据级别的Excel导出时,随着表格的不断创建,内存中对象越来越多,直至内存溢出。ApachePoi提供了SXSSFWork对象,专门用于处理大数据量Excel报表导出。

​ 在实例化SXSSFWork这个对象时,可以指定在内存中所产生的POI导出相关对象的数量(默认100),一旦内存中的对象的个数达到这个指定值时,就将内存中的这些对象的内容写入到磁盘中(XML的文件格式),就可以将这些对象从内存中销毁,以后只要达到这个值,就会以类似的处理方式处理,直至Excel导出完成。

Api

SXSSFWorkbook

  • 处理大数据量excel报表生成的:将已经使用过的内存元素,即使删除(poi4采用)或者保存到本地磁盘(poi3)

  • 使用条件:

    (1) 不支持模板打印

    (2)不支持太多的样式对象

实现

步骤1:模拟百万数据的导出

package cn.zonhar.web.controller.cargo;

import cn.zonhar.entity.cargo.Contract;
import cn.zonhar.entity.cargo.ContractExample;
import cn.zonhar.entity.system.User;
import cn.zonhar.entity.utils.DeleteStatus;
import cn.zonhar.entity.vo.ContractProductVo;
import cn.zonhar.service.cargo.ContractProductService;
import cn.zonhar.service.cargo.ContractService;
import cn.zonhar.web.controller.BaseController;
import cn.zonhar.web.utils.DownloadUtil;
import com.alibaba.dubbo.config.annotation.Reference;
import com.github.pagehelper.PageInfo;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.List;

/**
 * @author zonhar
 * @date 2019/7/27
 * 购销合同
 */
@Controller
@RequestMapping("/cargo/contract")
public class ContractController extends BaseController {

    @Reference
    private ContractService contractService;
    @Reference
    private ContractProductService contractProductService;


    @RequestMapping(value = "/print", name = "去出货表页面")
    public String toPrint() {
        return "/cargo/print/contract-print";
    }

  

    /**
     * 处理百万级导出
     *
     * @param inputDate 出货时间
     * @return
     */
    @RequestMapping(value = "/printExcel", name = "打印出货表")
    public void printExcel(String inputDate) throws IOException {
        Workbook workbook = new SXSSFWorkbook();

        Sheet sheet = workbook.createSheet("出货表");


        //出货表.xls ,设置每列列宽
        sheet.setColumnWidth(0, 0 * 256);
        sheet.setColumnWidth(1, 26 * 256);
        sheet.setColumnWidth(2, 12 * 256);
        sheet.setColumnWidth(3, 30 * 256);
        sheet.setColumnWidth(4, 12 * 256);
        sheet.setColumnWidth(5, 15 * 256);
        sheet.setColumnWidth(6, 10 * 256);
        sheet.setColumnWidth(7, 10 * 256);
        sheet.setColumnWidth(8, 8 * 256);

        //合并单元格
        sheet.addMergedRegion(new CellRangeAddress(0, 0, 1, 8));
        /**
         * 创建第一行
         */
        Row row = sheet.createRow(0);
        row.setHeightInPoints(36);
        Cell cell = row.createCell(1);
        cell.setCellStyle(this.bigTitle(workbook));
        String value = inputDate.replace("-0", "-").replace("-", "年") + "月份出货表";
        cell.setCellValue(value);
        /**
         * 创建第二行
         */
        row = sheet.createRow(1);
        row.setHeightInPoints(26);
        String titles[] = new String[]{"客户", "订单号", "货号", "数量", "工厂",
                "工厂交期", "船期", "贸易条款"};
        for (int i = 0; i < titles.length; i++) {
            cell = row.createCell(i + 1);
            cell.setCellValue(titles[i]);
            cell.setCellStyle(this.title(workbook));
        }

        /**
         * 导出数据行
         */
        String companyId = getLoginCompanyId();
        List<ContractProductVo> list =
                contractProductService.findByShipTime(companyId, inputDate);

        if (list != null && list.size() > 0) {
            int index = 2;
            for (ContractProductVo cp : list) {
                for (int i = 0; i < 6000; i++) {


                    row = sheet.createRow(index++);
                    row.setHeightInPoints(24);

                    cell = row.createCell(1);
                    cell.setCellValue(cp.getCustomName());
                    //  cell.setCellStyle(this.text((workbook)));

                    cell = row.createCell(2);
                    cell.setCellValue(cp.getContractNo());
                    //  cell.setCellStyle(this.text(workbook));

                    cell = row.createCell(3);
                    cell.setCellValue(cp.getProductNo());
                    //  cell.setCellStyle(this.text(workbook));

                    cell = row.createCell(4);
                    cell.setCellValue(cp.getCnumber());
                    // cell.setCellStyle(this.text(workbook));

                    cell = row.createCell(5);
                    cell.setCellValue(cp.getFactoryName());
                    //  cell.setCellStyle(this.text(workbook));

                    cell = row.createCell(6);
                    cell.setCellValue(cp.getDeliveryPeriod());
                    //  cell.setCellStyle(this.text(workbook));

                    cell = row.createCell(7);
                    cell.setCellValue(new SimpleDateFormat("yyyy-MM-dd").format(cp.getShipTime()));
                    // cell.setCellStyle(this.text(workbook));

                    cell = row.createCell(8);
                    cell.setCellValue(cp.getTradeTerms());
                    //  cell.setCellStyle(this.text(workbook));
                }
            }
        }

        //导出下载
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        workbook.write(bos);
        new DownloadUtil().download(bos, response, "出货表.xlsx");


    }
  
}

堆内存的消耗:

在这里插入图片描述

导出后的大小:

在这里插入图片描述

在这里插入图片描述

POI读写EXCEL文件

阅读数 124

没有更多推荐了,返回首页