package org.ccpit.base.utils.excelUtil;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

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.HSSFComment;
import org.apache.poi.hssf.usermodel.HSSFDataFormat;
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.hssf.util.Region;
import org.apache.poi.ss.usermodel.Cell;

/**
 * ClassName:ExcelTest <br/>
 * Function:
 * 所使用的jar包为org.apache.poi-3.13和jdk1.6，可以使用maven进行管理jar包，仓库为：http://maven
 * .apache.org。可以用来导出表头，表体
 * 要导出的内容可以是list集合、数组也可以是对象。表头可以是一维数组，集合，或者一个对象。表体可以是二维数组
 * ，List<ListArray<T>>或者一维对象数组，
 * 或对象的list集合。在导出时默认设置表头为红色、加粗，表体黑色、不加粗。也可以通过设置font，
 * cellStyle，format等属性，对导出的形式进行设置。
 * 此类并非静态类，该功能为导出excel，使用时并不会产生特别大的流量。如果流量大的话，可以把属性、初始代码块、方法均变为静态的，作为静态工具类使用。
 * 此类不释放流等资源，如果有资源作为参数传进来，需要在外面进行释放资源。
 * 导出方式：1.导出表头与行四个参数分别为表头（可以是一维字符串数组，集合）、表体（二维字符串数组，List<ArrayList<String>>）
 * 单元格cell的数据类型（一维int类型数组）（可以为null）、excel导出后的所在地（本地磁盘的盘符位置，输出流）
 * 2.导出对象，把整个对象作为导出数据的一行进行导出。 3.导出对象中的一部分数据。例如，只导出用户名，年龄，而不导出密码。 4.导出图片功能（未完成）
 * 
 * 在这个类中如果数据的类型不是字符串类型则要将数据类型转化为字符串类型，本类中只做了一些最简单的处理，例如Boolean类型会转化为真、假，
 * 数字类型转化为字符串，日期类型转化为“yyyy--MM--dd”
 * 如果要对这些类型做更个性化的处理，可以继承本类，然后覆盖数据类型转化为字符串的方法，如DateToString(Date
 * value)等等。因为如果使用HSSFCell中的方法例如，cell.setCellValue(Boolean
 * value);等来进行设置的话在excel中出现的内容并非是自己想要的，所以给出了数据内容转化成字符串的方法让子类进行覆盖。
 * 
 * 本类用初始代码块对导出的excel做了一些属性设置，如果需要更加个性化的属性设置，可以利用本类的setSheetPros(....参数列表)等(未完成)
 * 对象导出时，对象属性按照指定顺序进行导出（用了三层循环，有机会要优化下） 合并单元格的导出（未完成） 导入数据（未完成）
 * 
 * 需要优化之处：cell的宽度设置为sheet.autoSizeColumn((short) i);
 * 列的宽度自动适应文本内容的长度，有时候效果不是很理想，虽然不太影响视觉效果，不过最好还是优化下,求出字符串的宽度(未完成)***重点****
 * 
 * 可以进行设置标题，并且可以知道标题占用几个单元格，一般为表头的单元格数量
 * 本地文件所在位置可以用来做测试，测试过后可以删掉。输出流的方式可以用来完成web的交互 Reason: TODO <br/>
 * 
 * 如果要做导入的话还要导入对应的 poi-ooxml，因为excel分为2003之前与2007之后的不同版本，而如果要操作2007之后的版本必须使用XSSF...的相关类，而导入时，
 * 并不能确定导入的是什么版本所以用poi-ooxml提供的WookbookFactory来创建wookbook，更具通用性。
 * 
 * Date: 2015年11月18日 <br/>
 * 
 * @author jinlong
 * @version
 * @since JDK 1.6
 * @see
 */
public class ExportExcel<T> {
	// 导出excel表格所用属性
	private HSSFWorkbook workbook = null;
	private HSSFSheet sheet = null;
	private HSSFDataFormat format = null;
	private HSSFFont fontCaption = null;
	private HSSFFont fontHeader = null;
	private HSSFFont fontRows = null;
	private HSSFCellStyle cellStyleCaption = null;
	private HSSFCellStyle cellStyleHeader = null;
	private HSSFCellStyle cellStyleRows = null;
	private HSSFPatriarch patriarch = null;
	private HSSFComment comment = null;
	private HSSFRow rowCaption = null;
	private HSSFRow rowHeader = null;
	private HSSFRow rowBody = null;
	private Boolean flagHeader = false;
	private String pattern = "yyyy-MM-dd";
	private int rowNum = 0;
	// 初始化导出类的属性，作为默认情形，表头为加粗紫褐色，行为正常
	{
		// 创建新的Excel 工作簿
		workbook = new HSSFWorkbook();
		// 在Excel工作簿中建一工作表，其名为缺省值, 也可以指定Sheet名称
		sheet = workbook.createSheet();
		// HSSFSheet sheet = workbook.createSheet("SheetName");
		// sheet.setDefaultColumnWidth((short) 15);
		// 用于格式化单元格的数据
		format = workbook.createDataFormat();

		// 创建新行(row),并将单元格(cell)放入其中. 行号从0开始计算.
		// HSSFRow row =sheet.createRow((short) 0);
		// 设置字体 标题
		fontCaption = workbook.createFont();
		fontCaption.setFontHeightInPoints((short) 20); // 字体高度
		fontCaption.setColor(HSSFColor.ORANGE.index); // 字体颜色
		fontCaption.setFontName(HSSFFont.FONT_ARIAL); // 字体
		fontCaption.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 宽度
		fontCaption.setBold(true);
		// 设置单元格类型
		cellStyleCaption = workbook.createCellStyle();
		cellStyleCaption.setFont(fontCaption);
		cellStyleCaption.setFillForegroundColor(HSSFColor.GREEN.index);
		cellStyleCaption.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		cellStyleCaption.setBorderBottom(HSSFCellStyle.BORDER_DOUBLE);
		cellStyleCaption.setBorderLeft(HSSFCellStyle.BORDER_DOUBLE);
		cellStyleCaption.setBorderRight(HSSFCellStyle.BORDER_DOUBLE);
		cellStyleCaption.setBorderTop(HSSFCellStyle.BORDER_DOUBLE);
		cellStyleCaption.setAlignment(HSSFCellStyle.ALIGN_CENTER);

		// 设置字体 表头
		fontHeader = workbook.createFont();
		fontHeader.setFontHeightInPoints((short) 20); // 字体高度
		fontHeader.setColor(HSSFColor.VIOLET.index); // 字体颜色
		fontHeader.setFontName(HSSFFont.FONT_ARIAL); // 字体
		fontHeader.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 宽度
		fontHeader.setBold(true);
		// 设置单元格类型
		cellStyleHeader = workbook.createCellStyle();
		cellStyleHeader.setFont(fontHeader);
		cellStyleHeader.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
		cellStyleHeader.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		cellStyleHeader.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		cellStyleHeader.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		cellStyleHeader.setBorderRight(HSSFCellStyle.BORDER_THIN);
		cellStyleHeader.setBorderTop(HSSFCellStyle.BORDER_THIN);
		cellStyleHeader.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		// 声明一个画图的顶级管理器
		patriarch = sheet.createDrawingPatriarch();

		// 设置字体 行
		fontRows = workbook.createFont();
		fontRows.setFontHeightInPoints((short) 16); // 字体高度
		fontRows.setColor(HSSFColor.BLUE.index); // 字体颜色
		fontRows.setFontName(HSSFFont.FONT_ARIAL); // 字体
		fontRows.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); // 宽度
		fontRows.setBold(false);
		// 生成并设置另一个样式
		cellStyleRows = workbook.createCellStyle();
		cellStyleRows.setFillForegroundColor(HSSFColor.LIGHT_YELLOW.index);
		cellStyleRows.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
		cellStyleRows.setBorderBottom(HSSFCellStyle.BORDER_THIN);
		cellStyleRows.setBorderLeft(HSSFCellStyle.BORDER_THIN);
		cellStyleRows.setBorderRight(HSSFCellStyle.BORDER_THIN);
		cellStyleRows.setBorderTop(HSSFCellStyle.BORDER_THIN);
		cellStyleRows.setAlignment(HSSFCellStyle.ALIGN_CENTER);
		cellStyleRows.setFont(fontRows);
		cellStyleRows.setWrapText(true);
	}

	// 用来设置sheet单的名字
	public void setSheetName(String sheetName) {
		if (sheet != null) {
			workbook.setSheetName(0, sheetName);
		} else {
			sheet = workbook.createSheet(sheetName);
		}
	}

	// 设置注释
	public void setSheetComment(String commentContent, String commentAuthor) {
		// 注释使用量一般应该较小，所以HSSFPatriarch patriarch 与 HSSFComment comment没有作为成员属性
		try {
			// 定义注释的大小和位置,详见文档
			comment = patriarch.createComment(new HSSFClientAnchor(0, 0, 0, 0,
					(short) 4, 2, (short) 6, 5));
			// 设置注释内容
			if (commentContent != null && commentContent.equals("")) {
				comment.setString(new HSSFRichTextString(commentContent));
			} else {
				throw new RuntimeException("注释设置失败，原因为注释内容为null或空串");
			}
			// 设置注释作者，当鼠标移动到单元格上时可以在状态栏中看到该内容.
			comment.setAuthor(commentAuthor);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 设置注释
	public void setSheetComment(String commentContent) {

		try {
			// 定义注释的大小和位置,详见文档
			comment = patriarch.createComment(new HSSFClientAnchor(0, 0, 0, 0,
					(short) 4, 2, (short) 6, 5));
			// 设置注释内容
			if (commentContent != null && commentContent.equals("")) {
				comment.setString(new HSSFRichTextString(commentContent));
			} else {
				throw new RuntimeException("注释设置失败，原因为注释内容为null或空串");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 创建标题
	public void createCaption(String caption, int merge) {
		rowCaption = sheet.createRow((short) rowNum);
		HSSFCell cellCaption = rowCaption.createCell(0);
		sheet.addMergedRegion(new Region(0, (short) 0, 0, (short)(merge-1)));
		cellCaption.setCellValue(caption);
		cellCaption.setCellStyle(cellStyleCaption);// 设置单元格样式
		rowNum++;
	}

	// 把二维数组、集合数据导出到excel表中
	// 创建导出表头,参数是一维数组
	public void createExportHeader(String[] header) {
		rowHeader = sheet.createRow((short) rowNum);
		for (int i = 0; i < header.length; i++) {
			// 创建单元格
			HSSFCell cell = rowHeader.createCell(i, HSSFCell.CELL_TYPE_STRING);// 创建cell，并制定数据类型
			HSSFRichTextString hssfString = null;
			if (header[i] != null) {
				hssfString = new HSSFRichTextString(header[i]);
			} else {
				hssfString = new HSSFRichTextString("");
			}
			cell.setCellValue(hssfString);// 设置单元格内容
			cell.setCellStyle(cellStyleHeader);// 设置单元格样式
			sheet.autoSizeColumn((short) i); // 列的宽度自动适应文本内容的长度
		}
		rowNum++;
	}

	public void createExportHeader(List<String> header) {
		// List<String> ListTemp = Arrays.asList(header);
		String[] arrTemp = header.toArray(new String[header.size()]);
		createExportHeader(arrTemp);
	}

	// 创建导出行,参数是二维数组
	public void createExportRows(String[][] rows) {

		HSSFCell cell = null;
		List<Integer> flagClumn = new ArrayList<Integer>();
		// 用来标识行号
		for (int i = 0; i < rows.length; i++) {
			rowBody = sheet.createRow((short) rowNum++);
			for (int j = 0; j < rows[i].length; j++) {
				// 创建单元格
				cell = rowBody.createCell(j, HSSFCell.CELL_TYPE_STRING);// 创建cell，并制定数据类型
				HSSFRichTextString hssfString = null;
				if (rows[i][j] != null) {
					hssfString = new HSSFRichTextString(rows[i][j]);
				} else {
					hssfString = new HSSFRichTextString("");
				}
				cell.setCellValue(hssfString);// 设置单元格内容
				cell.setCellStyle(cellStyleRows);// 设置单元格样式

				sheet.autoSizeColumn((short) j); // 列的宽度自动适应文本内容的长度
			}
		}

	}

	public void createExportRows(List<ArrayList<String>> lists) {
		// 把list集合转化为二维数组
		String[][] rows = new String[lists.size()][];
		for (int i = 0; i < rows.length; i++) {
			rows[i] = lists.get(i).toArray(new String[lists.get(i).size()]);
		}
		createExportRows(rows);
	}

	// 导出时的路径
	public void executeExportTo(String filePlace) {// "F://3.xls"
		try {
			if (filePlace != null) {
				FileOutputStream fileOut = new FileOutputStream(filePlace);
				workbook.write(fileOut);
				fileOut.close();
			} else {
				throw new RuntimeException("输出地址为null");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void executeExportTo(OutputStream out) {
		try {
			if (out != null) {
				workbook.write(out);
				out.close();
			} else {
				throw new RuntimeException("输出流为null");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	// 把对象数据导入到excel中
	// 创建对象行
	public void createExportRowsByObject(T[] dataset) {
		List<T> datasetNew = new ArrayList<T>();
		datasetNew = Arrays.asList(dataset);
		createExportRowsByObject(datasetNew);
	}

	// 导出对象的全部内容，如果对象的属性为null，则导出空串
	public void createExportRowsByObject(List<T> dataset) {
		rowBody = null;
		// 遍历集合数据，产生数据行
		Iterator<T> it = dataset.iterator();
//		int rowNum = (flagHeader == true ? 1 : 0);// 用来标识行号
		// 反射属性
		Field[] fields = dataset.get(0).getClass().getDeclaredFields();
		// 创建单元格 传进来的对象集合中的一个对象
		Field field = null;
		HSSFCell cell = null;
		T t = null;
		String fieldName = null;
		HSSFRichTextString richString = null;
		// 反射方法 反射类 反射方法运行后得到的
		Method getMethod = null;
		Class tCls = dataset.get(0).getClass();
		Object value = null;// value为对象类型 所以在判断该数据的类型时也要把基本类型算进来，再进行转化为字符串
		String textValue = null;// 判断值的类型后进行强制类型转换
		while (it.hasNext()) {

			rowBody = sheet.createRow(rowNum);
			t = (T) it.next();
			// 利用反射，根据javabean属性的先后顺序，动态调用getXxx()方法得到属性值
			for (int i = 0; i < fields.length; i++) {
				field = fields[i];

				cell = rowBody.createCell(i);// , HSSFCell.CELL_TYPE_STRING
				cell.setCellStyle(cellStyleRows);

				fieldName = field.getName();
				String getMethodName = "get"
						+ fieldName.substring(0, 1).toUpperCase()
						+ fieldName.substring(1);
				try {
					getMethod = tCls.getMethod(getMethodName, new Class[] {});
					value = getMethod.invoke(t, new Object[] {});
					if (value != null) {
						// 根据数据类型对属性数据进行转化为字符串
						textValue = this.getDataTypeToString(value, cell);
					} else {
						textValue = "";
						cell.setCellType(HSSFCell.CELL_TYPE_BLANK);
					}
					richString = new HSSFRichTextString(textValue);
					cell.setCellValue(richString);
				} catch (Exception e) {
					e.printStackTrace();
				} finally {
					// byte[] bs = textValue.getBytes();
					textValue = null;
					sheet.autoSizeColumn((short) i); // 列的宽度自动适应文本内容的长度

				}
			}
			rowNum++;
		}
	}

	/**
	 * <一句话功能简述> <功能详细描述>
	 * 
	 * @param dataset
	 * @param list
	 *            指定导出该对象的哪些属性作为列
	 * @see [类、类#方法、类#成员]
	 */
	// 导出的excel表中列的顺序为对象的属性的顺序
	// 创建导出的内容为对象属性的一部分，这个方法比先整理出要导出的二维数组，然后在遍历这个二维数组，所运行的代码行数要多进行了代码行的运行，x(1+y)与x的平方进行比较,所以1+y
	// 与 x进行比较 y小于10 所以该方法多运行了
	// 也就是说在双层循环遍历时，应先把符合条件的挑出来，然后再进行遍历，这样比直接进行遍历效率高
	// 单层循环时应该在遍历的过程中直接就把业务逻辑处理了
	public void createExportRowsByObject(T[] dataset, List<String> list) {
		List<T> datasetList = Arrays.asList(dataset);
		createExportRowsByObject(datasetList, list);
	}

	public void createExportRowsByObject(List<T> dataset, List<String> list) {
		// HSSFRow row = null;
		// 遍历集合数据，产生数据行
		Iterator<T> it = dataset.iterator();
//		int rowNum = (flagHeader == true ? 1 : 0);// 用来标识行号
		// 反射属性
		Field[] fields = dataset.get(0).getClass().getDeclaredFields();
		// 创建单元格 传进来的对象集合中的一个对象
		Field field = null;
		HSSFCell cell = null;
		T t = null;
		String fieldName = null;
		HSSFRichTextString richString = null;
		// 反射方法 反射类 反射方法运行后得到的
		Method getMethod = null;
		Class tCls = dataset.get(0).getClass();
		Object value = null;// value为对象类型 所以在判断该数据的类型时也要把基本类型算进来，再进行转化为字符串
		String textValue = null;// 判断值的类型后进行强制类型转换
		int columnNumber;// 用来标记对象中该属性是否要建立一列
		while (it.hasNext()) {
			columnNumber = 0;
			rowBody = sheet.createRow(rowNum);
			t = (T) it.next();
			// 利用反射，根据javabean属性的先后顺序，动态调用getXxx()方法得到属性值
			for (int i = 0; i < fields.length; i++) {
				field = fields[i];
				fieldName = field.getName();
//				System.out.println(fieldName);
				if (list.contains(fieldName)) {
					cell = rowBody.createCell(columnNumber);// //
					// HSSFCell.CELL_TYPE_STRING
					cell.setCellStyle(cellStyleRows);

					String getMethodName = "get"
							+ fieldName.substring(0, 1).toUpperCase()
							+ fieldName.substring(1);
					try {
						getMethod = tCls.getMethod(getMethodName,
								new Class[] {});
						value = getMethod.invoke(t, new Object[] {});
						if (value != null) {
							// 根据数据类型对属性数据进行转化为字符串
							textValue = this.getDataTypeToString(value, cell);
						} else {
							textValue = "";
							cell.setCellType(HSSFCell.CELL_TYPE_BLANK);
						}
						richString = new HSSFRichTextString(textValue);
						cell.setCellValue(richString);
					} catch (Exception e) {
						e.printStackTrace();
					} finally {
						// byte[] bs = textValue.getBytes();
						textValue = null;
						sheet.autoSizeColumn((short) i); // 列的宽度自动适应文本内容的长度
						columnNumber++;
					}
				}
			}
			rowNum++;
		}
	}

	// 导出对象部分属性时，指定属性的导出顺序为list中的先后顺序
	public void createExportRowsByObjectAndSpecifyOrder(List<T> dataset,
			List<String> list) {
		// HSSFRow row = null;
		// 遍历集合数据，产生数据行
		Iterator<T> it = dataset.iterator();
//		int rowNum = (flagHeader == true ? 1 : 0);// 用来标识行号
		// 反射属性
		Field[] fields = dataset.get(0).getClass().getDeclaredFields();
		// 创建单元格 传进来的对象集合中的一个对象
		Field field = null;
		HSSFCell cell = null;
		T t = null;
		String fieldName = null;
		HSSFRichTextString richString = null;
		// 反射方法 反射类 反射方法运行后得到的
		Method getMethod = null;
		Class tCls = dataset.get(0).getClass();
		Object value = null;// value为对象类型 所以在判断该数据的类型时也要把基本类型算进来，再进行转化为字符串
		String textValue = null;// 判断值的类型后进行强制类型转换
		int columnNumber;// 用来标记对象中该属性是否要建立一列
		while (it.hasNext()) {// 行
			columnNumber = 0;
			rowBody = sheet.createRow(rowNum);
			t = (T) it.next();
			// 利用反射，根据javabean属性的先后顺序，动态调用getXxx()方法得到属性值
			for (String pro : list) {// 列
				for (int i = 0; i < fields.length; i++) {// 条件判断，过滤数据
					field = fields[i];
					fieldName = field.getName();
					// System.out.println(fieldName);
					if (pro.equals(fieldName)) {
						cell = rowBody.createCell(columnNumber);// //
						// HSSFCell.CELL_TYPE_STRING
						cell.setCellStyle(cellStyleRows);

						String getMethodName = "get"
								+ fieldName.substring(0, 1).toUpperCase()
								+ fieldName.substring(1);
						try {
							getMethod = tCls.getMethod(getMethodName,
									new Class[] {});
							value = getMethod.invoke(t, new Object[] {});
							if (value != null) {
								// 根据数据类型对属性数据进行转化为字符串
								textValue = this.getDataTypeToString(value,
										cell);
							} else {
								textValue = "";
								cell.setCellType(HSSFCell.CELL_TYPE_BLANK);
							}
							// 如果是图片
							if (textValue == null) {
								// 有图片时，设置行高为60px;
								rowBody.setHeightInPoints(60);
								// 设置图片所在列宽度为80px,注意这里单位的一个换算
								sheet.setColumnWidth(i, (short) (35.7 * 80));
								// sheet.autoSizeColumn(i);
								byte[] bsValue = (byte[]) value;
								HSSFClientAnchor anchor = new HSSFClientAnchor(
										0, 0, 1023, 255, (short) 6,
										rowBody.getRowNum(), (short) 6,
										rowBody.getRowNum());
//								System.out.println(anchor);
								anchor.setAnchorType(2);

								patriarch.createPicture(anchor, workbook
										.addPicture(bsValue,
												HSSFWorkbook.PICTURE_TYPE_PNG));

							} else {// 如果不是图片
								richString = new HSSFRichTextString(textValue);
								cell.setCellValue(richString);
							}
						} catch (Exception e) {
							e.printStackTrace();
						} finally {
							textValue = null;
							sheet.autoSizeColumn((short) list.indexOf(pro)); // 列的宽度自动适应文本内容的长度
							columnNumber++;
						}
						break;
					}
				}
			}
			rowNum++;
		}
	}

	//
	// public Map<Integer, Boolean> columnWhetherOutput(String[] pros, Class
	// cls) {
	// Map<Integer, Boolean> map = new HashMap<Integer, Boolean>();
	// // 把pros中的某一个属性是否属于cls中的属性，如果是则在map中设置相应的键值。用cls做遍历，cls放入到、
	//
	// return map;
	//
	// }
	/**
	 * 这是一个通用的方法，利用了JAVA的反射机制，可以将放置在JAVA集合中并且符号一定条件的数据以EXCEL 的形式输出到指定IO设备上
	 * 
	 * @param title
	 *            表格标题名
	 * @param headers
	 *            表格属性列名数组
	 * @param dataset
	 *            需要显示的数据集合,集合中一定要放置符合javabean风格的类的对象。此方法支持的
	 *            javabean属性的数据类型有基本数据类型及String,Date,byte[](图片数据)
	 * @param out
	 *            与输出设备关联的流对象，可以将EXCEL文档导出到本地文件或者网络中
	 * @param pattern
	 *            如果有时间数据，设定输出格式。默认为"yyy-MM-dd"
	 * @param list
	 *            导出该对象中所指定的属性
	 */
	@SuppressWarnings("unchecked")
	public void exportObject(String title, String[] headers, List<T> dataset,
			List<String> list, OutputStream out) {

		this.setSheetName(title);
		this.createExportHeader(headers);
		createExportRowsByObject(dataset, list);
		this.executeExportTo(out);
	}

	@SuppressWarnings("unchecked")
	public void exportObjectOrder(String title, String[] headers,
			List<T> dataset, List<String> list, OutputStream out) {

		this.setSheetName(title);
		this.createExportHeader(headers);
		createExportRowsByObjectAndSpecifyOrder(dataset, list);
		this.executeExportTo(out);
	}

	// 导出对象的所有属性,默认为对象的属性顺序
	public void exportObject(String title, String[] headers, List<T> dataset,
			OutputStream out) {

		this.setSheetName(title);
		this.createExportHeader(headers);
		// createExportRowsByObject(dataset,list);
		createExportRowsByObject(dataset);
		this.executeExportTo(out);

	}

	public void exportObject(String title, String[] headers, T[] dataset,
			OutputStream out) {

		this.setSheetName(title);
		this.createExportHeader(headers);
		// createExportRowsByObject(dataset,list);
		createExportRowsByObject(dataset);
		this.executeExportTo(out);

	}


	public String getDataTypeToString(Object value, HSSFCell cell) {
		String textValue = null;
		HSSFRichTextString richString = null;

		cell.setCellValue(richString);
		if (value instanceof Boolean) {
			textValue = this.BooleanToString((Boolean) value);
			cell.setCellType(Cell.CELL_TYPE_BOOLEAN);
//			System.out.println(cell.getCellType());
//			System.out.println(11);
		} else if (value instanceof String) {
			textValue = this.StringToString((String) value);
			cell.setCellType(Cell.CELL_TYPE_STRING);
		} else if (value instanceof Double) {
			textValue = this.DoubleToString((Double) value);
			cell.setCellType(Cell.CELL_TYPE_NUMERIC);
		} else if (value instanceof Float) {
			textValue = this.FloatToString((Float) value);
			cell.setCellType(Cell.CELL_TYPE_NUMERIC);
		} else if (value instanceof Integer) {
			textValue = this.IntegerToString((Integer) value);
			cell.setCellType(Cell.CELL_TYPE_NUMERIC);
		} else if (value instanceof Short) {
			textValue = this.ShortToString((Short) value);
			cell.setCellType(Cell.CELL_TYPE_NUMERIC);
		} else if (value instanceof Character) {// 设置为字符串类型，如果是单个字符，可以先判断出是字符串类型，然后该值得字符串类型进行赋值，如果报异常，则
			textValue = this.CharacterToString((Character) value);// 用catch捕捉，然后再去该字符串值的首个字符付给该值对应的对象中的成员属性
			cell.setCellType(Cell.CELL_TYPE_STRING);
		} else if (value instanceof Byte) {
			textValue = this.ByteToString((Byte) value);
			cell.setCellType(Cell.CELL_TYPE_NUMERIC);
		} else if (value instanceof Long) {
			textValue = this.LongToString((Long) value);
			cell.setCellType(Cell.CELL_TYPE_NUMERIC);
		} else if (value instanceof Date) {
			textValue = this.DateToString((Date) value);
			// System.out.println(textValue);
			cell.setCellType(Cell.CELL_TYPE_FORMULA);
		} else if (value instanceof Byte[] || value instanceof byte[]) {// 图片字节码转化为字符串保存到excel中
			textValue = this.byteArrToString((byte[]) value);
			// 有图片时，设置行高为60px;
			cell.setCellType(Cell.CELL_TYPE_FORMULA);
		} else {
			// 其它数据类型都当作字符串简单处理
			textValue = this.ObjectToString(value);
			cell.setCellType(Cell.CELL_TYPE_ERROR);
		}

		return textValue;
	}

	/**
	 * 设置excel的style，主要是cellstyle与font <功能详细描述>
	 * 
	 * @see [类、类#方法、类#成员]
	 */
	public void setWorkbookPros() {
		HSSFWorkbook workbook = this.getWorkbook();
		// todo workbook的属性设置
	}

	public void setSheetPros() {

	}

	public void setDataFormatPros() {

	}

	public void setFontHeaderPros() {

	}

	public void setFontrowsPros() {

	}

	public void setCellStyleHeaderPros() {

	}

	public void setCellStyleRowsPros() {

	}

	public void setPatriarchPros() {

	}

	public void setCommentPros() {

	}

	/**
	 * 数据类型不是字符串时，对其进行转化，得到字符串数据。 <功能详细描述>
	 * 
	 * @param value
	 * @return
	 * @see [类、类#方法、类#成员]
	 */
	// Boolean类型的数据转化为字符串用以保存到excel中
	public String BooleanToString(Boolean value) {
		String text = null;
		if (value != null)
			text = (Boolean) value == true ? "是" : "否";
		return text;
	}

	public String StringToString(String value) {
		String text = null;
		if (value != null)
			text = value;
		return text;
	}

	// Double类型的数据转化为字符串用以保存到excel中
	public String DoubleToString(Double value) {
		String text = null;
		if (value != null)
			text = String.valueOf(value);
		return text;
	}

	// Float类型的数据转化为字符串用以保存到excel中
	public String FloatToString(Float value) {
		String text = null;
		if (value != null)
			text = String.valueOf(value);
		return text;
	}

	// Byte类型的数据转化为字符串用以保存到excel中
	public String ByteToString(Byte value) {
		return null;
	}

	// Short类型的数据转化为字符串用以保存到excel中
	public String ShortToString(Short value) {
		String text = null;
		if (value != null)
			text = String.valueOf(value);
		return text;
	}

	// Long特别情况类型的数据转化为字符串用以保存到excel中
	public String LongToString(Long value) {
		String text = null;
		if (value != null)
			text = String.valueOf(value);
		return text;
	}

	// Integer特别情况类型的数据转化为字符串用以保存到excel中
	public String IntegerToString(Integer value) {
		String text = null;
		if (value != null)
			text = String.valueOf(value);
		return text;
	}

	// Character类型的数据转化为字符串用以保存到excel中
	public String CharacterToString(Character value) {
		String text = null;
		if (value != null)
			text = String.valueOf(value);
		return text;
	}

	// 图片类型的数据转化为字符串用以保存到excel中
	public String byteArrToString(Byte[] value) {
		String text = null;
		if (value != null) {
			text = String.valueOf(value);
		}
		return text;
	}

	// 图片类型的数据转化为字符串用以保存到excel中
	public String byteArrToString(byte[] value) {

		return null;
	}

	// 对象类型的数据转化为字符串用以保存到excel中
	public String DateToString(Date value) {
		String text = null;
		if (value != null) {
			Date date = (Date) value;
			SimpleDateFormat sdf = null;
			if (this.pattern != null) {
				sdf = new SimpleDateFormat(pattern);
			}
			text = sdf.format(date);
		} else {
			text = "";
		}
		return text;
	}

	// 只导出表头
	public void executeExport(String[] header, OutputStream out) {
		this.createExportHeader(header);
		this.executeExportTo(out);
	}

	public void executeExport(List<String> list, OutputStream out) {
		this.createExportHeader(list);
		this.executeExportTo(out);
	}

	// 不带表头，只导出行
	public void executeExport(String[][] rows, OutputStream out) {
		this.createExportRows(rows);
		this.executeExportTo(out);
	}

	public void executeExport(Collection<ArrayList<String>> lists,
			OutputStream out) {
		this.createExportRows((List<ArrayList<String>>) lists);
		this.executeExportTo(out);
	}

	// 导出表头与行四个参数分别为表头（可以是一维字符串数组，集合）、表体（二维字符串数组，List<ArrayList<String>>）
	// 单元格cell的数据类型（一维int类型数组）、excel导出后的所在地（本地磁盘的盘符位置，输出流）
	public void executeExport(String[] header, String[][] rows, OutputStream out) {
		this.createExportHeader(header);
		executeExport(rows, out);
	}

	public void executeExport(String[] header,
			Collection<ArrayList<String>> rows, OutputStream out) {
		this.createExportHeader(header);
		executeExport(rows, out);
	}

	public void executeExport(List<String> list, String[][] rows,
			OutputStream out) {
		this.createExportHeader(list);
		executeExport(rows, out);
	}

	public void executeExport(List<String> list,
			Collection<ArrayList<String>> rows, OutputStream out) {
		this.createExportHeader(list);
		executeExport(rows, out);
	}

	// 只导出表头
	public void executeExport(String[] header, String filePlace) {
		this.createExportHeader(header);
		this.executeExportTo(filePlace);
	}

	public void executeExport(List<String> list, String filePlace) {
		this.createExportHeader(list);
		this.executeExportTo(filePlace);
	}

	// 不带表头，只导出行
	public void executeExport(String[][] rows, String filePlace) {
		this.createExportRows(rows);
		this.executeExportTo(filePlace);
	}

	public void executeExport(Collection<ArrayList<String>> lists,
			String filePlace) {
		this.createExportRows((List<ArrayList<String>>) lists);
		this.executeExportTo(filePlace);
	}

	// 导出表头与行四个参数分别为表头（可以是一维字符串数组，集合）、表体（二维字符串数组，List<ArrayList<String>>）
	// 单元格cell的数据类型（一维int类型数组）、excel导出后的所在地（本地磁盘的盘符位置，输出流）
	public void executeExport(String[] header, String[][] rows, String filePlace) {
		this.createExportHeader(header);
		executeExport(rows, filePlace);
	}

	public void executeExport(String[] header,
			Collection<ArrayList<String>> rows, String filePlace) {
		this.createExportHeader(header);
		executeExport(rows, filePlace);
	}

	public void executeExport(List<String> list, String[][] rows,
			String filePlace) {
		this.createExportHeader(list);
		executeExport(rows, filePlace);
	}

	public void executeExport(List<String> list,
			Collection<ArrayList<String>> rows, String filePlace) {
		this.createExportHeader(list);
		executeExport(rows, filePlace);
	}

	// 对象类型的数据转化为字符串用以保存到excel中
	public String ObjectToString(Object value) {
		String text = null;
		if (value != null)
			text = value.toString();
		return text;
	}

	public HSSFWorkbook getWorkbook() {
		return workbook;
	}

	public void setWorkbook(HSSFWorkbook workbook) {
		this.workbook = workbook;
	}

	public HSSFSheet getSheet() {
		return sheet;
	}

	public void setSheet(HSSFSheet sheet) {
		this.sheet = sheet;
	}

	public HSSFDataFormat getFormat() {
		return format;
	}

	public void setFormat(HSSFDataFormat format) {
		this.format = format;
	}

	public HSSFFont getFontHeader() {
		return fontHeader;
	}

	public void setFontHeader(HSSFFont fontHeader) {
		this.fontHeader = fontHeader;
	}

	public HSSFFont getFontRows() {
		return fontRows;
	}

	public void setFontRows(HSSFFont fontRows) {
		this.fontRows = fontRows;
	}

	public HSSFCellStyle getCellStyleHeader() {
		return cellStyleHeader;
	}

	public void setCellStyleHeader(HSSFCellStyle cellStyleHeader) {
		this.cellStyleHeader = cellStyleHeader;
	}

	public HSSFCellStyle getCellStyleRows() {
		return cellStyleRows;
	}

	public void setCellStyleRows(HSSFCellStyle cellStyleRows) {
		this.cellStyleRows = cellStyleRows;
	}

	public HSSFPatriarch getPatriarch() {
		return patriarch;
	}

	public void setPatriarch(HSSFPatriarch patriarch) {
		this.patriarch = patriarch;
	}

	public HSSFComment getComment() {
		return comment;
	}

	public void setComment(HSSFComment comment) {
		this.comment = comment;
	}

	public Boolean getFlagHeader() {
		return flagHeader;
	}

	public void setFlagHeader(Boolean flagHeader) {
		this.flagHeader = flagHeader;
	}

	public String getPattern() {
		return pattern;
	}

	public void setPattern(String pattern) {
		this.pattern = pattern;
	}
//	public static void main(String[] args) {
//
//		// 测试学生
//		ExportExcel<Student> ex = new ExportExcel<Student>();
//		String[] headers = { "时间", "姓名", "学号" };
//
//		Student[] stus = new Student[4];
//		stus[0] = new Student(new Date(), false, null);
//		stus[1] = new Student(new Date(), true, null);
//		stus[2] = new Student(new Date(), true, null);
//		stus[3] = new Student(new Date(), false, "jinlong");
//		List<String> dataHeader = new ArrayList<String>();
//		dataHeader.add(headers[0]);
//		dataHeader.add(headers[1]);
//		dataHeader.add(headers[2]);
//		dataHeader.add(headers[0]);
//		dataHeader.add(headers[1]);
//		dataHeader.add(headers[2]);
//		dataHeader.add(headers[0]);
//		List<Student> dataset = new ArrayList<Student>();
//		dataset.add(new Student(new Date(), true, null));
//		dataset.add(new Student(new Date(), true, null));
//		dataset.add(new Student(new Date(), false, "asd"));
//		// 测试图书
//		ExportExcel<Book> ex2 = new ExportExcel<Book>();
//		String[] headers2 = { "图书编号", "图书名称", "图书价格", "图书ISBN", "图书出版社", "封面图片" };
//		// String[] headers2 = { "图书价格", "图书名称" };
//		List<String> pros = new ArrayList<String>();
//		List<String> pros1 = new ArrayList<String>();
//		pros.add("name");
//		pros.add("date");
//		// pros.add("b");
//		pros1.add("price");
//		pros1.add("name");
//		pros1.add("author");
//		pros1.add("isbn");
//		pros1.add("compony");
//		pros1.add("id");
//		pros1.add("picture");
//
//		List<Book> dataset2 = new ArrayList<Book>();
//		try {
//			BufferedInputStream bis = new BufferedInputStream(
//					new FileInputStream("F://workspace/ExcelTest/src/back.png"));
//			byte[] buf = new byte[bis.available()];
//
//			while ((bis.read(buf)) != -1) {
//				//
//			}
//			// System.out.println(new String(buf));
//			dataset2.add(new Book(1, "jsp", "222", 300.33f, "1234567", "清华出版社",
//					buf));
//			dataset2.add(new Book(2, "程思想ava编ssssssss程思想程思想", null, 300.33f,
//					"1234567", "阳光出版社", buf));
//			dataset2.add(new Book(3, "DOM艺术", null, 300.33f, "1234567",
//					"清华出版社", buf));
//			dataset2.add(new Book(4, "c++经典", null, 400.33f, "1234567",
//					"清华出版社", buf));
//			dataset2.add(new Book(5, "c#入门", null, 300.33f, "1234567",
//					"汤春秀出版社", buf));
//			String[] ss = { "1", "2", "1", "2" };
//			List<String> list = new ArrayList<String>();
//			List<String> list1 = new ArrayList<String>();
//			list.add(null);
//			list.add("e");
//			list.add("v");
//			list.add("j");
//			list1.add("d多少的第d多少的第三代1d多少的第三代1d多少的第三代1d多少的第三代1d多少的第三代1三代1");
//			list1.add("e");
//			list1.add(null);
//			list1.add("j");
//			String[][] rows = new String[2][2];
//			rows[0][0] = "jin1";
//			rows[0][1] = null;
//			rows[1][0] = "jivvvvvvvvvvvvvvvvvvvn3";
//			rows[1][1] = "jinvv4";
//			List<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
//			lists.add((ArrayList<String>) list);
//			lists.add((ArrayList<String>) list1);
////			int merge = headers2.length>pros.size()?headers2.length:pros.size();
////			ex.createCaption("123", merge);
////			ex.exportObjectOrder("123", headers, dataset, pros,
////					new FileOutputStream("F://object3.xls"));
//			 ex.exportObject("123", headers2, dataset, pros, new
//			 FileOutputStream("F://object1.xls"));
////			 ex2.exportObject("123", headers2, dataset2, pros1, new
////			 FileOutputStream("F://object2.xls"));
////			// OutputStream out = new FileOutputStream("F://a.xls");
////			// OutputStream out2 = new FileOutputStream("F://b.xls");
////			// // 只导出表头
////			 ex.executeExport(headers2, new FileOutputStream("F://c.xls"));
////			 ex.executeExport(dataHeader, new FileOutputStream("F://d.xls"));
////			// //导出头体
////			 ex.executeExport(headers2, lists, new
////			 FileOutputStream("F://e.xls"));
////			 ex.executeExport(headers2, rows, new
////			 FileOutputStream("F://f.xls"));
////			 ex.executeExport(list1, (List<ArrayList<String>>)lists, new
////			 FileOutputStream("F://g.xls"));
////			 ex.executeExport(list1, rows, new FileOutputStream("F://h.xls"));
//////			 只导出表体
//////			 ex.executeExport(lists, cellTypes, filePlace);
//////			 ex.exportExcel(headers, dataset, pros, out);
////			 ex.executeExport(rows, "F://rows.xls");
////			 ex.executeExport((List<ArrayList<String>>)lists,
////			 "F://rows1.xls");
//			// out.close();
//			// System.out.println(1/0);
//			// JOptionPane.showMessageDialog(null, "导出成功!");
////			System.out.println("excel导出成功！");
//		} catch (Exception e) {
//			// JOptionPane.showMessageDialog(null, "导出失败", "消息",
//			// JOptionPane.ERROR_MESSAGE);
//			e.printStackTrace();
//		}
//	}

	// public static void main(String[] args) throws Exception {
	// String[] ss = { "1", "2", "1", "2" };
	// List<String> list = new ArrayList<String>();
	// List<String> list1 = new ArrayList<String>();
	// list.add(null);
	// list.add("e");
	// list.add("v");
	// list.add("j");
	// list1.add("d多少的第d多少的第三代1d多少的第三代1d多少的第三代1d多少的第三代1d多少的第三代1三代1");
	// list1.add("e");
	// list1.add(null);
	// list1.add("j");
	// String[][] rows = new String[2][2];
	// rows[0][0] = "jin1";
	// rows[0][1] = null;
	// rows[1][0] = "jivvvvvvvvvvvvvvvvvvvn3";
	// rows[1][1] = "jinvv4";
	// List<ArrayList<String>> lists = new ArrayList<ArrayList<String>>();
	// lists.add((ArrayList<String>) list);
	// lists.add((ArrayList<String>) list1);
	// ExportExcel et = new ExportExcel();
	// OutputStream out = null;
	// int[] cellTypes = null;
	// et.executeExport(list1, lists, cellTypes, "F://3.xls");
	// }

	// Object[][] oo = Array2TransformList2.getArray2FromList2(lists);
	// // String[][] sss = oo;
	// System.out.println(((String)oo[0][1]).toUpperCase());
	// Student stu1 = new Student(true,"1");
	// Student stu2 = new Student(false,"2");
	// List<Student> list1 = new ArrayList<Student>();
	// list1.add(stu1);
	//
	// List<Student> list2 = new ArrayList<Student>();
	// list2.add(stu2);
	// List<ArrayList<Student>> lists2 = new ArrayList<ArrayList<Student>>();
	// lists2.add((ArrayList<Student>)list1);
	// lists2.add((ArrayList<Student>)list2);
	//
	// Object[][] oo1 = Array2TransformList2.getArray2FromList2(lists2);
	// // String[][] sss = oo;
	// System.out.println(((Student)oo1[1][0]).getB());
	// List<ArrayList<Object>> lists3 =(List<ArrayList<Object>>)
	// Array2TransformList2.getArray2FromList2(rows);
	// System.out.println(lists3.get(0).get(0));
	// List<String> o = Arrays.asList(ss);
	// System.out.println(o);
	// }
}
