poi实现大数据导出excel

2014-11-12 09:19:11 jimmy609 阅读数 22755

转载地址http://blog.csdn.net/yys79/article/details/26443603


POI之前的版本不支持大数据量处理,如果数据过多则经常报OOM错误,有时候调整JVM大小效果也不是太好。3.8版本的POI新出来了SXSSFWorkbook,可以支持大数据量的操作,只是SXSSFWorkbook只支持.xlsx格式,不支持.xls格式。

    3.8版本的POI对excel的导出操作,一般只使用HSSFWorkbook以及SXSSFWorkbook,HSSFWorkbook用来处理较少的数据量,SXSSFWorkbook用来处理大数据量以及超大数据量的导出。
    HSSFWorkbook的使用方法和之前的版本的使用方法一致,这里就不在陈述使用方法了
    SXSSFWorkbook的使用例子如下:
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 { 
 Workbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk 
 Sheet sh = wb.createSheet(); 
 for(int rownum = 0; rownum < 100000; 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); } 
 }
FileOutputStream out = new FileOutputStream("/temp/sxssf.xlsx"); 
 wb.write(out); 
 out.close();
以前还用xml来处理,现在3.8以上就好办了。
原文地址是:http://blog.sina.com.cn/s/blog_68555ee501015xk2.html
apache官网相关内容地址:http://poi.apache.org/spreadsheet/how-to.html#sxssf

2019-03-19 14:57:48 wanglizheng825034277 阅读数 4860

xls和xlsx

  1. xls是旧版Excel格式文件,xlsx是新版Excel格式文件;而xlsx新版格式其实是一系列文件压缩包,
    如图:
    在这里插入图片描述
  2. xls是以二进制的方式存储,这种格式不易被其他软件读取使用;而xlsx采用了基于XML的ooxml开放文档标准,ooxml使用XML和ZIP技术结合进行文件存储,XML是一个基于文本的格式,而且ZIP容器支持内容的压缩,所以其一大优势是可以大大减小文件的尺寸;
  3. 使用POI来读写Excel文件有两种方式,一种用户模式(UserModel),读取时消耗大量内存,造成OOM问题;一种事件模式(SAX模式),仅仅关注文件内部数据,内存消耗很低;
  4. 导出文件同样如此,使用Workbook普通导出,数据量小的时候可以正常使用,但时间等待仍然很长,这时推荐使用POI提供的SXXFWorkbook处理,其使用时间窗口原理(具体可以查询)限制访问,刷出内存,降低内存消耗,提升效率。
    另外还需要注意,根据你使用的功能,仍然可能消耗大量内存,例如合并区域,超链接,注释……,这些内容只存储在内存中。
    在这里插入图片描述

导入数据(大量)

大量数据导入在网络上搜寻到的相关代码大部分通过集成POI原生的DefaultHandler重写其startElement, endElement, characters方法进行相关的解析,而POI已经将相关逻辑封装在XSSFSheetXMLHandler,只要实现暴露的接口SheetContentsHandler即可。
使用SheetContentsHandler的例子可以参考官方的XLSX2CVS
本例实现该接口:

package cn.skio.venus.api;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.util.SAXHelper;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler;
import org.apache.poi.xssf.eventusermodel.XSSFSheetXMLHandler.SheetContentsHandler;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFComment;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.parsers.ParserConfigurationException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;

/**
 * @autor jasmine
 */
public class ExcelEventParser {
    private String fileName;
    private SimpleSheetContentsHandler handler;
    // 测试使用对比使用SAX和UserModel模式选择(实际使用不需要)
    private Integer saxInterupt;
	private void setHandler(SimpleSheetContentsHandler handler) {
		this.handler = handler;
	}

	// 放置读取数据
    protected List<List<String>> table = new ArrayList<>();

    public ExcelEventParser(String filename, Integer saxInterupt){
        this.fileName = filename;
        this.saxInterupt = saxInterupt;
    }

    public List<List<String>> parse() {
        OPCPackage opcPackage = null;
        InputStream inputStream = null;

        try {
            FileInputStream fileStream = new FileInputStream(fileName);
            opcPackage = OPCPackage.open(fileStream);
            XSSFReader xssfReader = new XSSFReader(opcPackage);

            StylesTable styles = xssfReader.getStylesTable();
            ReadOnlySharedStringsTable strings = new ReadOnlySharedStringsTable(opcPackage);
            inputStream = xssfReader.getSheetsData().next();

            processSheet(styles, strings, inputStream);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (opcPackage != null) {
                try {
                    opcPackage.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return table;
    }

	// 确定XMLReader解析器,使用SAX模式解析xml文件
    private void processSheet(StylesTable styles, ReadOnlySharedStringsTable strings, InputStream sheetInputStream) throws SAXException, ParserConfigurationException, IOException {
        XMLReader sheetParser = SAXHelper.newXMLReader();

        if (handler == null) {
            setHandler(new SimpleSheetContentsHandler());
        }
        sheetParser.setContentHandler(new XSSFSheetXMLHandler(styles, strings, handler, false));

        try {
            sheetParser.parse(new InputSource(sheetInputStream));
        } catch (RuntimeException e) {
            System.out.println("---> 遇到空行读取文件结束!");
        }
    }

	// 实现SheetContentsHandler
    public class SimpleSheetContentsHandler implements SheetContentsHandler{
        protected List<String> row;
        @Override
        public void startRow(int rowNum) {
            row = new LinkedList<>();
        }

        @Override
        public void endRow(int rowNum) {
        	// 判断是否使用异常作为文件读取结束(有些Excel文件格式特殊,导致很多空行,浪费内存)
            if (saxInterupt == 1) {
                if (row.isEmpty()) {
                    throw new RuntimeException("Excel文件读取完毕");
                }
            }
			// 添加数据到list集合
            table.add(row);
        }

        /**
         * 所有单元格数据转换为string类型,需要自己做数据类型处理
         * @param cellReference 单元格索引
         * @param formattedValue 单元格内容(全部被POI格式化为字符串)
         * @param comment
         */
        @Override
        public void cell(String cellReference, String formattedValue, XSSFComment comment) {
            row.add(formattedValue);
        }

        @Override
        public void headerFooter(String text, boolean isHeader, String tagName) {
        }
    }
}

经测试结果,发现使用SAX模式(抛弃了样式等,只关注数据)仅仅消耗很少内存,效率高;而普通Workbook读取数据(测试文件为5.2MB的有大量空行文件)内存消耗 > 1GB(此时线上系统OOM概率非常大);
在这里插入图片描述

导出数据(大量)

导出数据的话瓶颈主要在于数据写入Excel文件,代码(同样的74273条数据导出)如下:

	// 使用SXSSFwrokbook,大量数据处理快速
	@GetMapping("/outExcel")
    public void outPutExcel(HttpServletResponse response) throws Exception {
        // 每次写100行数据,就刷新数据出缓存
        SXSSFWorkbook wb = new SXSSFWorkbook(100); // keep 100 rows in memory, exceeding rows will be flushed to disk
        Sheet sh = wb.createSheet();
        List<Tmp> tmps = tmpDao.findAll();
        log.info("---> 数据量:{}", tmps.size());

        for(int rowNum = 0; rowNum < tmps.size(); rowNum++){
            Row row = sh.createRow(rowNum);
            Tmp tmp = tmps.get(rowNum);
            Cell cell1 = row.createCell(0);
            cell1.setCellValue(tmp.getSource());

            Cell cell2 = row.createCell(1);
            cell2.setCellValue(tmp.getName());
            Cell cell3 = row.createCell(2);
            cell3.setCellValue(tmp.getPhone());
            Cell cell4 = row.createCell(3);
            cell4.setCellValue(tmp.getCity());
        }

        String fileName = "sxssf.xlsx";
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        wb.write(response.getOutputStream());
        wb.close();
    }
	// XSSFWorkbook, 效率低下
	@GetMapping("/outExcel2")
    public void outPutExcel2(HttpServletResponse response) throws Exception {
        XSSFWorkbook wb = new XSSFWorkbook();
        Sheet sh = wb.createSheet();
        List<Tmp> tmps = tmpDao.findAll();
        log.info("---> 数据量:{}", tmps.size());

        for(int rowNum = 0; rowNum < tmps.size(); rowNum++){
            Row row = sh.createRow(rowNum);
            Tmp tmp = tmps.get(rowNum);
            Cell cell1 = row.createCell(0);
            cell1.setCellValue(tmp.getSource());

            Cell cell2 = row.createCell(1);
            cell2.setCellValue(tmp.getName());
            Cell cell3 = row.createCell(2);
            cell3.setCellValue(tmp.getPhone());
            Cell cell4 = row.createCell(3);
            cell4.setCellValue(tmp.getCity());
        }

        String fileName = "sxssf.xlsx";
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "GBK"));
        wb.write(response.getOutputStream());
        wb.close();
    }

效率对比:

对象 耗时
SXSSFWorkbook 在这里插入图片描述
XSSFWorkbook 在这里插入图片描述

CPU和内存消耗对比:
在这里插入图片描述

总结

  1. 大文件读取使用SAX
  2. 大文件写入使用SXSSFWorkbook

参考链接:
[1]: https://blog.csdn.net/Holmofy/article/details/82532311
[2]: https://blog.csdn.net/daiyutage/article/details/53010491
[3]: https://www.cnblogs.com/yfrs/p/5689347.html
[4]: easyexcel

2016-10-13 19:02:54 happyljw 阅读数 48506
   用过POI的人都知道,在POI以前的版本中并不支持大数据量的处理,如果数据量过多还会常报OOM错误,这时候调整JVM的配置参数也不是一个好对策(注:jdk在32位系统中支持的内存不能超过2个G,而在64位中没有限制,但是在64位的系统中,性能并不是太好),好在POI3.8版本新出来了一个SXSSFWorkbook对象,它就是用来解决大数据量以及超大数据量的导入导出操作的,但是SXSSFWorkbook只支持.xlsx格式,不支持.xls格式的Excel文件。

这里普及一下,POI中使用HSSF对象时,excel 2003最多只允许存储65536条数据,一般用来处理较少的数据量,这时对于百万级别数据,Excel肯定容纳不了,而且在计算机性能稍低的机器上测试,就很容易导致堆溢出。而当我升级到XSSF对象时,它可以直接支持excel2007以上版本,因为它采用ooxml格式。这时excel可以支持1048576条数据,单个sheet表就支持近104万条数据了,虽然这时导出100万数据能满足要求,但使用XSSF测试后发现偶尔还是会发生堆溢出,所以也不适合百万数据的导出

 现在我们知道excel2007及以上版本可以轻松实现存储百万级别的数据,但是系统中的大量数据是如何能够快速准确的导入到excel中这好像是个难题,对于一般的web系统,我们为了解决成本,基本都是使用的入门级web服务器tomcat,既然我们不推荐调整JVM的大小,那我们就要针对我们的代码来解决我们要解决的问题。在POI3.8之后新增加了一个类,SXSSFWorkbook,采用当数据加工时不是类似前面版本的对象,它可以控制excel数据占用的内存,他通过控制在内存中的行数来实现资源管理,即当创建对象超过了设定的行数,它会自动刷新内存,将数据写入文件,这样导致打印时,占用的CPU,和内存很少。但有人会说了,我用过这个类啊,他好像并不能完全解决,当数据量超过一定量后还是会内存溢出的,而且时间还很长。对你只是用了这个类,但是你并没有针对你的需求进行相应的设计,仅仅是用了,所以接下来我要说的问题就是,如何通过SXSSFWorkbook以及相应的写入设计来实现百万级别的数据快速写入。

 我先举个例子,以前我们数据库中存在大量的数据,我们要查询,怎么办?我们在没有经过设计的时候是这样来处理的,先写一个集合,然后执行jdbc,将返回的结果赋值给list,然后再返回到页面上,但是当数据量大的时候,就会出现数据无法返回,内存溢出的情况,于是我们在有限的时间和空间下,通过分页将数据一页一页的显示出来,这样可以避免了大数据量数据对内存的占用,也提高了用户的体验,在我们要导出的百万数据也是一个道理,内存突发性占用,我们可以限制导出数据所占用的内存,这里我先建立一个list容器,list中开辟10000行的存储空间,每次存储10000行,用完了将内容清空,然后重复利用,这样就可以有效控制内存,所以我们的设计思路就基本形成了,所以分页数据导出共有以下3个步骤:

1、求数据库中待导出数据的行数

2、根据行数求数据提取次数

3、按次数将数据写入文件

通过以上步骤在效率和用户体验性上都有了很高的提高,接下来上代码

public void exportBigDataExcel(ValueDataDto valueDataDto, String path)
			throws IOException {
	// 最重要的就是使用SXSSFWorkbook,表示流的方式进行操作
	// 在内存中保持100行,超过100行将被刷新到磁盘
	SXSSFWorkbook wb = new SXSSFWorkbook(100);
	Sheet sh = wb.createSheet(); // 建立新的sheet对象
	Row row = sh.createRow(0);   // 创建第一行对象
	// -----------定义表头-----------
	Cell cel0 = row.createCell(0);
	cel0.setCellValue("1");
	Cell cel2 = row.createCell(1);
	cel2.setCellValue("2");
	Cell cel3 = row.createCell(2);
	cel3.setCellValue("3");
	Cell cel4 = row.createCell(3);
	// ---------------------------
	List<valuedatabean> list = new ArrayList<valuedatabean>();
	// 数据库中存储的数据行
	int page_size = 10000;
	// 求数据库中待导出数据的行数
	int list_count = this.daoUtils.queryListCount(this.valueDataDao
			.queryExportSQL(valueDataDto).get("count_sql"));
	// 根据行数求数据提取次数
	int export_times = list_count % page_size > 0 ? list_count / page_size
			+ 1 : list_count / page_size;
	// 按次数将数据写入文件
	for (int j = 0; j < export_times; j++) {
		list = this.valueDataDao.queryPageList(this.valueDataDao
				.queryExportSQL(valueDataDto).get("list_sql"), j + 1,
				page_size);
		int len = list.size() < page_size ? list.size() : page_size;
	
<span style="white-space:pre">	</span>	for (int i = 0; i < len; i++) {
			Row row_value = sh.createRow(j * page_size + i + 1);
			Cell cel0_value = row_value.createCell(0);
			cel0_value.setCellValue(list.get(i).getaa());
			Cell cel2_value = row_value.createCell(1);
			cel2_value.setCellValue(list.get(i).getaa());
			Cell cel3_value = row_value.createCell(2);
			cel3_value.setCellValue(list.get(i).getaa_person());
		}
		list.clear(); // 每次存储len行,用完了将内容清空,以便内存可重复利用
	}
	FileOutputStream fileOut = new FileOutputStream(path);
	wb.write(fileOut);
	fileOut.close();
	wb.dispose();
}

到目前已经可以实现百万数据的导出了,但是当我们的业务数据超过200万,300万了呢?如何解决?

这时,直接打印数据到一个工作簿的一个工作表是实现不了的,必须拆分到多个工作表,或者多个工作簿中才能实现。因为一个sheet最多行数为1048576

下面就以这种思路提供另外一种解决方案,直接上代码(后面会附上测试数据库,及案例需要的jar包)

public static void main(String[] args) throws Exception {
	Test3SXXFS tm = new Test3SXXFS();
	tm.jdbcex(true);
}
public void jdbcex(boolean isClose) throws InstantiationException, IllegalAccessException, 
			ClassNotFoundException, SQLException, IOException, InterruptedException {
		
	String xlsFile = "f:/poiSXXFSBigData.xlsx";		//输出文件
	//内存中只创建100个对象,写临时文件,当超过100条,就将内存中不用的对象释放。
	Workbook wb = new SXSSFWorkbook(100);			//关键语句
	Sheet sheet = null;		//工作表对象
	Row nRow = null;		//行对象
	Cell nCell = null;		//列对象

	//使用jdbc链接数据库
	Class.forName("com.mysql.jdbc.Driver").newInstance();  
	String url = "jdbc:mysql://localhost:3306/bigdata?characterEncoding=UTF-8";
	String user = "root";
	String password = "123456";
	//获取数据库连接
	Connection conn = DriverManager.getConnection(url, user,password);   
	Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,ResultSet.CONCUR_UPDATABLE);   
	String sql = "select * from hpa_normal_tissue limit 1000000";   //100万测试数据
	ResultSet rs = stmt.executeQuery(sql);  
	
	ResultSetMetaData rsmd = rs.getMetaData();
	long  startTime = System.currentTimeMillis();	//开始时间
	System.out.println("strat execute time: " + startTime);
		
	int rowNo = 0;		//总行号
	int pageRowNo = 0;	//页行号
		
	while(rs.next()) {
		//打印300000条后切换到下个工作表,可根据需要自行拓展,2百万,3百万...数据一样操作,只要不超过1048576就可以
		if(rowNo%300000==0){
			System.out.println("Current Sheet:" + rowNo/300000);
			sheet = wb.createSheet("我的第"+(rowNo/300000)+"个工作簿");//建立新的sheet对象
			sheet = wb.getSheetAt(rowNo/300000);		//动态指定当前的工作表
			pageRowNo = 0;		//每当新建了工作表就将当前工作表的行号重置为0
		}	
		rowNo++;
		nRow = sheet.createRow(pageRowNo++);	//新建行对象

		// 打印每行,每行有6列数据   rsmd.getColumnCount()==6 --- 列属性的个数
		for(int j=0;j<rsmd.getColumnCount();j++){
			nCell = nRow.createCell(j);
			nCell.setCellValue(rs.getString(j+1));
		}
			
		if(rowNo%10000==0){
			System.out.println("row no: " + rowNo);
		}
//		Thread.sleep(1);	//休息一下,防止对CPU占用,其实影响不大
	}
		
	long finishedTime = System.currentTimeMillis();	//处理完成时间
	System.out.println("finished execute  time: " + (finishedTime - startTime)/1000 + "m");
		
	FileOutputStream fOut = new FileOutputStream(xlsFile);
	wb.write(fOut);
	fOut.flush();		//刷新缓冲区
	fOut.close();
		
	long stopTime = System.currentTimeMillis();		//写文件时间
	System.out.println("write xlsx file time: " + (stopTime - startTime)/1000 + "m");
		
	if(isClose){
		this.close(rs, stmt, conn);
	}
}
	
//执行关闭流的操作
private void close(ResultSet rs, Statement stmt, Connection conn ) throws SQLException{
	rs.close();   
	stmt.close();   
	conn.close(); 
}

数据库截图:




案例执行结果截图:

             


完美!!!!


数据库脚本及案例相关jar包:

http://pan.baidu.com/s/1pKXQp55


2015-10-29 11:11:53 riapgypm 阅读数 10185

 

     在工作中遇到了要导出30多万条数据的excel文件,写了一个工具类,我用的是POI3.13版本的,至少版本也得是3.8,否则不支持导出大数据。如下:

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFDataFormat;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFCell;

import com.google.common.base.Strings;


public class ExcelUtil {
	
	private  FileOutputStream output;
	private Sheet sheet;
	private SXSSFWorkbook wb;
	private Integer countRow=0;
	private Map<String, PropertyDescriptor>objPropertyMap;
	/**
	 * 初始化
	 * @param xls_write_Address
	 * @param fieldNames
	 * @throws FileNotFoundException
	 */
	public void init_Excel( String path,String fileName,String[] fieldNames) throws FileNotFoundException{
		
		File pathfile=new File(path);
		if(!pathfile.exists()){
			pathfile.mkdirs();
		}
		
		
        output = new FileOutputStream(new File(path+fileName));  //读取的文件路径   
        wb = new SXSSFWorkbook(1000);//内存中保留 10000 条数据,以免内存溢出,其余写入 硬盘      
        sheet = wb.createSheet(String.valueOf("sheet"));  
        wb.setSheetName(0, "sheet");   
        sheet.autoSizeColumn(1);
        Row row = sheet.createRow(countRow++); 
        for(int i=0;i<fieldNames.length;i++){
            Cell cell = row.createCell(i);                     
            cell.setCellType(XSSFCell.CELL_TYPE_STRING);//文本格式                    
            //sheet.setColumnWidth(i, fieldNames[i].length()*384); //设置单元格宽度  
            cell.setCellValue(fieldNames[i]);//写入内容  
        }
        
	}
	
	/**
	 * 
	 * @param datalist
	 * @param dataFields
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 * @throws IOException
	 * @throws IntrospectionException
	 */
	public void write_data_Excel(List<Object> datalist,String[] dataFields) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException, IntrospectionException{
		write_data_Excel(datalist,dataFields,null,null);
	}
	
	public void write_data_Excel(List<Object> datalist,String[] dataFields,Map<String, Map<String, String>> dataDic) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException, IntrospectionException{
		write_data_Excel(datalist,dataFields,dataDic,null);
	}
	
	/**
	 * 写数据
	 * @param datalist
	 * @param dataFields
	 * @throws IOException
	 * @throws IntrospectionException
	 * @throws IllegalAccessException
	 * @throws IllegalArgumentException
	 * @throws InvocationTargetException
	 */
    public  void write_data_Excel(List<Object> datalist,String[] dataFields,Map<String, Map<String, String>> dataDic,Map<String,Integer> dataFormat) throws IOException, IntrospectionException, IllegalAccessException, IllegalArgumentException, InvocationTargetException  {
    	
		CellStyle cellStyle =  wb.createCellStyle();  
		cellStyle.setDataFormat(HSSFDataFormat.getBuiltinFormat("0.00"));              		
		ZipSecureFile.setMinInflateRatio(0l);
		
        for(int i=0;i<datalist.size();i++){  
            Row row = sheet.createRow(countRow++);  
            Object obj=datalist.get(i);           
			BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());  
			PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
			if(objPropertyMap==null){
				objPropertyMap=new HashMap<String, PropertyDescriptor>();
				for(PropertyDescriptor des:propertyDescriptors){
					objPropertyMap.put(des.getName(), des);
				}
			}
            for(int cols=0;cols<dataFields.length;cols++){  
            	String dataField=dataFields[cols];
            	Object value="";
                if (objPropertyMap.get(dataField)!=null) {  
                    // 得到property对应的getter方法  
                    Method gettter = objPropertyMap.get(dataField).getReadMethod();  
                    value=gettter.invoke(obj);
                    if(value instanceof Date){
                    	Date date=(Date)value;
                    	value=DateUtil.dateFormat("yyyy-MM-dd HH:mm:ss", date);
                    	value=value.toString().replaceAll(" 00:00:00", "");
                    	//数据字典的匹配
                    }else {
                    	if(dataDic!=null && dataDic.get(dataField)!=null){
                    		value=dataDic.get(dataField).get(value+"");
                    	}
                    }
                }  
                
                if(value==null){
                	value="";
                }
                Cell cell = row.createCell(cols);     
                
            	if(dataFormat!=null && dataFormat.get(dataField)!=null){
            		int format=dataFormat.get(dataField);

            		switch(format){
	            		case 10:
		            	    cell.setCellStyle(cellStyle);  
		            		cell.setCellType(XSSFCell.CELL_TYPE_NUMERIC);//数字格式
		            		if(!Strings.isNullOrEmpty(value.toString())){
		            			cell.setCellValue(Double.valueOf(value.toString()));//写入内容  
		            		}
		            		break;
	            		case XSSFCell.CELL_TYPE_NUMERIC:
		            		cell.setCellType( XSSFCell.CELL_TYPE_NUMERIC);//数字格式
		            		if(!Strings.isNullOrEmpty(value.toString())){
		            			cell.setCellValue(Double.valueOf(value.toString()));//写入内容  
		            		}
		            		break;
            		}

            	}else{
            		cell.setCellType(XSSFCell.CELL_TYPE_STRING);//文本格式    
            		cell.setCellValue(value.toString());//写入内容  
            	}
            	
               // sheet.setColumnWidth(cols, value.toString().length()*384); //设置单元格宽度  
              
            }   
        }    
          
    }  
    /**
     * 写文件
     * @throws IOException
     */
    public void write_excel_disk() throws IOException{
        wb.write(output);
        output.close(); 
    }
}

测试的调用方法为:

    	
    	ExcelUtil util=new ExcelUtil();
    	Date date=new Date();
    	String strDate=DateUtil.dateFormat("yyyy/MM/dd", date);
    	String path=ParameterConstants.UPLOAD_FILE_PATH+"excel/skcx/"+strDate+"/";
    	String fileName=date.getTime()+".xlsx";
    	
    	util.init_Excel(path,fileName, new String[]{"日期","时间","处理时间","编号","状态","金额"});
    	String[] datefiles=new String[]{"billDueDate","insertedTime","processTime","userNo","results","money"};//对象的属性名字
    	
    	/**
    	 * 定义数据字典
    	 */
    	Map<String, String> resultsMap=new HashMap<String, String>();
    	resultsMap.put("0", "未处理");
    	resultsMap.put("1", "收款成功");
    	resultsMap.put("2", "收款失败");
    	Map<String, Map<String,String>> properyMap=new HashMap<String, Map<String,String>>();
    	properyMap.put("results", resultsMap);//可以多个
    	
    	/**
    	 * 定义数据格式
    	 */
    	Map <String,Integer> dataFormat =new HashMap<String,Integer>();
    	dataFormat.put("money", 10);//带两位小数数字

    	int countPage=1;
    	command.setPageSize(2000);////数据量太大,分批读取数据,一次读取2000条
    	command.setCurPageNo(countPage++);
    	BaseEntity entity=viewBillDeductResultsService.getBillDeductResultsByConditionsQuery(command);
    	//从数据库里循环读出所有数据
    	while(entity!=null && entity.getListObject()!=null){
    		util.write_data_Excel(entity.getListObject(), datefiles, properyMap,dataFormat);
    		command.setCurPageNo(countPage++);
    		entity=viewBillDeductResultsService.getBillDeductResultsByConditionsQuery(command);
    	}
    	//将文件写在硬盘上
    	util.write_excel_disk();
        return new ModelAndView("redirect:../../upload/excel/word/"+strDate+"/"+fileName);//防止直接导出造成内存溢出,所以先存放在硬盘上,再去下载


2018-11-13 20:40:46 qq_16855077 阅读数 765

前提:

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

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

(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("");
					}

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