POI封装二:导出 Export

已整理成完整项目,并进行了优化。看参考地址:

https://gitee.com/andy_longjie/exceltools   或者 https://github.com/youmulongjie/exceltools

POI 导出篇

1、maven jar 包依赖:
<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
		<poi.version>3.12</poi.version>
		<dict>exceltools</dict><!-- 项目名称 -->
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi</artifactId>
			<version>${poi.version}</version>
		</dependency>
		<dependency>
			<groupId>org.apache.poi</groupId>
			<artifactId>poi-ooxml</artifactId>
			<version>${poi.version}</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>3.8.1</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

2、项目目录树:

 

3、定义注解类:

(一):ExcelExportCol.java
/**
 * @package :com.andy.demo.execltools.exports.annotation<br>
 * @author :wanglongjie<br>
 * @createDate :2015年12月2日下午2:26:29<br>
 */
package com.andy.demo.execltools.exports.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 描述:Excel 导出属性注解类<br>
 * <br>
 * 1、导出的类必须添加注解类ExcelExportConfig<br>
 * 2、该注解类用在类属性上,获取Excel的列标题头和列索引(从0开始)<br>
 * 
 * @package :com.andy.demo.execltools.exports.annotation<br>
 * @file :ExcelExportCol.java<br>
 * @author :wanglongjie<br>
 * @createDate :2015年12月2日下午2:26:29<br>
 * 
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface ExcelExportCol {
	/**
	 * 
	 * 描述:列标题头说明 <br>
	 * 
	 * @method :colHeaderDesc<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:27:15 <br>
	 * @return 列标题头说明
	 */
	String colHeaderDesc();

	/**
	 * 
	 * 描述:所在列索引,下标从0开始 <br>
	 * 
	 * @method :cols<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:27:38 <br>
	 * @return 所在列索引,下标从0开始
	 */
	int cols();
}
(二)ExcelExportConfig.java
/**
 * @package :com.andy.demo.execltools.exports.annotation<br>
 * @author :wanglongjie<br>
 * @createDate :2015年12月2日下午2:22:43<br>
 */
package com.andy.demo.execltools.exports.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 描述:Excel 导出注解类 <br>
 * <br>
 * 1、导出的类必须添加该注解类 <br>
 * 2、默认导出的Excel第0行为标题行,对象记录行从第1行开始<br>
 * 
 * @package :com.andy.demo.execltools.exports.annotation<br>
 * @file :ExcelExportConfig.java<br>
 * @author :wanglongjie<br>
 * @createDate :2015年12月2日下午2:22:43<br>
 * 
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface ExcelExportConfig {
	/**
	 * 
	 * 描述: 生成Excel文件的 标题所在的行数,默认为0<br>
	 * 
	 * @method :headerRow<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:23:29 <br>
	 * @return 生成Excel文件的 标题所在的行数
	 */
	int headerRow() default 0;

	/**
	 * 
	 * 描述:生成Excel文件的 对象记录所在的行数,默认从1开始 <br>
	 * 
	 * @method :lineStartRow<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:23:56 <br>
	 * @return 生成Excel文件的 对象记录所在的行数
	 */
	int lineStartRow() default 1;
}

3、导出工具类:

/**
 * Excel 导出 包 <br>
 * @package :com.andy.demo.execltools.exports<br>
 * @author :wanglongjie<br>
 * @createDate :2015年12月2日下午2:20:18<br>
 */
package com.andy.demo.execltools.exports;

import java.beans.PropertyDescriptor;
import java.io.ByteArrayOutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
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.usermodel.XSSFWorkbook;

import com.andy.demo.execltools.exports.annotation.ExcelExportCol;
import com.andy.demo.execltools.exports.annotation.ExcelExportConfig;

/**
 * 描述:Excel 导出工具类 <br>
 * 
 * @package :com.andy.demo.execltools.exports<br>
 * @file :ExcelToolsExport.java<br>
 * @author :wanglongjie<br>
 * @createDate :2015年12月2日下午2:20:18<br>
 * 
 */
public class ExcelToolsExport {
	private static final String DATE_FORMAT = "yyyy-mm-dd";
	private static final String NUMERIC_FORMAT = "#############0.00######";
	private static final int BUFFER_SIZE = 4096 * 10;
	
	/**
	 * 
	 * 描述:将List对象集合 转化为 byte 数组,生成一张sheet的byte数组源 <br>
	 * 
	 * @method :createExcelExport<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午4:02:35 <br>
	 * @param list
	 *            : 对象集合数据源
	 * @param sheetName
	 *            :要生成的 sheet 的名称
	 * @return byte数组
	 * @throws Exception
	 */
	public static <T> byte[] createExcelExport(List<T> list, String sheetName)
			throws Exception {
		checkValidate(list);

		Workbook wb = createWorkbook(true);
		sheetName = (null == sheetName || sheetName.equals("")) ? "sheet1"
				: sheetName;
		Sheet sheet = wb.createSheet(sheetName);
		setExcelHeader(sheet, list.get(0));
		setExcelLines(sheet, list, wb);

		return getByteFormWb(wb);
	}

	/**
	 * 
	 * 描述:将List对象集合 转化为 byte 数组,同一Excel生成多张sheet的byte数组源 <br>
	 * 
	 * @method :createExcelExport<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午4:12:03 <br>
	 * @param map
	 *            : 封装的sheet的数据源集合
	 * @return byte数组
	 * @throws Exception
	 */
	public static byte[] createExcelExport(Map<String, List<?>> map)
			throws Exception {
		if (null != map && map.size() > 0) {
			Workbook wb = createWorkbook(true);

			Iterator<String> it = map.keySet().iterator();
			Sheet sheet = null;// 生成的 sheet 对象
			String sheetName = null;// sheet 名称
			List<?> list = null; // sheet 数据源
			while (it.hasNext()) {
				sheetName = (String) it.next();
				list = map.get(sheetName);

				checkValidate(list);

				sheet = wb.createSheet(sheetName);
				setExcelHeader(sheet, list.get(0));
				setExcelLines(sheet, list, wb);
			}

			return getByteFormWb(wb);
		}
		return null;
	}

	/**
	 * 
	 * 描述:设置 生成Excel的内容记录行 <br>
	 * 
	 * @method :setExcelLines<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午3:23:25 <br>
	 * @param sheet
	 *            :创建的 Sheet对象
	 * @param list
	 *            :对象集合数据源
	 * @param wb
	 *            :创建的WorkBook 工作薄对象
	 * @throws Exception
	 */
	private static <T> void setExcelLines(Sheet sheet, List<T> list, Workbook wb)
			throws Exception {
		int lineStartRow = getLineStartRow(list.get(0).getClass());
		Row row = null;
		for (int i = 0; i < list.size(); i++) {
			row = sheet.createRow(lineStartRow);
			obj2Cell(row, list.get(i), wb);
			lineStartRow++;
		}
	}

	/**
	 * 
	 * 描述:设置 生成Excel的标题头行 <br>
	 * 
	 * @method :setExcelHeader<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午3:20:11 <br>
	 * @param sheet
	 *            :Sheet 对象
	 * @param t
	 *            :Excel 的载体实体类对象
	 * @throws Exception
	 */
	private static <T> void setExcelHeader(Sheet sheet, T t) throws Exception {
		int headRow = getHeaderRow(t.getClass());
		Row row = sheet.createRow(headRow);

		List<Field> list = getExcelExportColAnnoFields(t.getClass());
		ExcelExportCol excelExportCol = null;
		int cols = 0;// 标题列索引
		String colHeaderDesc = null;// 标题头说明
		for (Field f : list) {
			excelExportCol = f.getAnnotation(ExcelExportCol.class);
			cols = excelExportCol.cols();
			colHeaderDesc = excelExportCol.colHeaderDesc();
			row.createCell(cols).setCellValue(colHeaderDesc);
		}
	}

	/**
	 * 
	 * 描述:填充 Excel 数据行 <br>
	 * 
	 * @method :obj2Cell<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午3:59:57 <br>
	 * @param row
	 *            : 创建的Row 行对象
	 * @param t
	 *            :对象数据源
	 * @param wb
	 *            :创建的Workbook 工作薄对象
	 * @throws Exception
	 */
	private static <T> void obj2Cell(Row row, T t, Workbook wb)
			throws Exception {
		List<Field> list = getExcelExportColAnnoFields(t.getClass());

		ExcelExportCol excelExportCol = null;
		Cell cell = null; // 单元格
		int cols = 0;// 单元格 列索引
		Object value = null;// 单元格内容(反射获取的属性值)

		PropertyDescriptor pd = null;
		Method m = null;
		for (Field f : list) {
			excelExportCol = f.getAnnotation(ExcelExportCol.class);
			cols = excelExportCol.cols();

			// 反射获取对象的属性值
			pd = new PropertyDescriptor(f.getName(), t.getClass());
			m = pd.getReadMethod();
			value = m.invoke(t);

			if (null == value) {
				// 属性值为空,则不需要填充单元格,返回
				return;
			}

			cell = row.createCell(cols);
			fillCell(value, cell, wb);
		}
	}

	/**
	 * 
	 * 描述:填充 单元格 <br>
	 * 
	 * @method :fillCell<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午3:57:40 <br>
	 * @param value
	 *            :单元格 内容
	 * @param cell
	 *            :要填充的单元格
	 * @param wb
	 *            : 创建的WorkBook 工作薄对象
	 */
	private static void fillCell(Object value, Cell cell, Workbook wb) {
		if (value instanceof java.util.Date) {
			java.util.Date d = (java.util.Date) value;
			DataFormat format = wb.createDataFormat();
			// 日期格式化
			CellStyle cellStyle = wb.createCellStyle();
			cellStyle.setDataFormat(format.getFormat(DATE_FORMAT));

			cell.setCellStyle(cellStyle);
			cell.setCellValue(d);
			return;
		}

		if (value instanceof java.sql.Date) {
			java.sql.Date d = (java.sql.Date) value;
			cell.setCellValue(d);
			return;
		}

		if (value instanceof Timestamp) {
			Timestamp ts = (Timestamp) value;
			cell.setCellValue(ts);
			return;
		}

		if (value instanceof BigDecimal) {
			BigDecimal b = (BigDecimal) value;
			cell.setCellValue(b.doubleValue());
			return;
		}

		if (value instanceof Double) {
			Double d = (Double) value;
			DataFormat format = wb.createDataFormat();
			// 数字格式化
			CellStyle cellStyle = wb.createCellStyle();
			cellStyle.setDataFormat(format.getFormat(NUMERIC_FORMAT));

			cell.setCellStyle(cellStyle);
			cell.setCellValue(d);
			return;
		}

		if (value instanceof Float) {
			Float f = (Float) value;
			DataFormat format = wb.createDataFormat();
			// 数字格式化
			CellStyle cellStyle = wb.createCellStyle();
			cellStyle.setDataFormat(format.getFormat(NUMERIC_FORMAT));

			cell.setCellStyle(cellStyle);
			cell.setCellValue(f);
			return;
		}

		if (value instanceof Long) {
			Long l = (Long) value;
			cell.setCellValue(l);
			return;
		}

		if (value instanceof Integer) {
			Integer i = (Integer) value;
			cell.setCellValue(i);
			return;
		}

		if (value instanceof Boolean) {
			Boolean b = (Boolean) value;
			cell.setCellValue(b);
			return;
		}

		if (value instanceof String) {
			String s = (String) value;
			cell.setCellValue(s);
			return;
		}

	}

	/**
	 * 
	 * 描述:创建 WorkBook 工作薄对象 <br>
	 * 
	 * @method :createWorkbook<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午3:01:03 <br>
	 * @param flag
	 *            :true:xls(1997-2007) false:xlsx(2007以上)
	 * @return WorkBook 工作薄对象
	 */
	private static Workbook createWorkbook(boolean flag) {
		Workbook wb;
		if (flag) {
			wb = new XSSFWorkbook();
		} else {
			wb = new HSSFWorkbook();
		}
		return wb;
	}

	/**
	 * 
	 * 描述:将创建的 Workbook 工作薄对象转化为byte输出流 <br>
	 * 
	 * @method :getByteFormWb<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:59:10 <br>
	 * @param wb
	 *            : 创建的 Workbook 工作薄对象
	 * @return byte输出流
	 * @throws Exception
	 */
	private static byte[] getByteFormWb(Workbook wb) throws Exception {
		if (null != wb) {
			ByteArrayOutputStream byStream = new ByteArrayOutputStream(
					BUFFER_SIZE);
			wb.write(byStream);
			return byStream.toByteArray();
		}
		return null;
	}

	/**
	 * 
	 * 描述: 读取生成Excel文件的 标题所在的行数 <br>
	 * 
	 * @method :getHeaderRow<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:35:20 <br>
	 * @param cla
	 *            :Excel 的载体实体类
	 * @return
	 * @throws Exception
	 */
	private static <T> int getHeaderRow(Class<T> cla) throws Exception {
		return cla.getAnnotation(ExcelExportConfig.class).headerRow();
	}

	/**
	 * 
	 * 描述:读取生成Excel文件的 对象记录所在的行数 <br>
	 * 
	 * @method :getLineStartRow<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:36:15 <br>
	 * @param cla
	 *            :Excel 的载体实体类
	 * @return
	 * @throws Exception
	 */
	private static <T> int getLineStartRow(Class<T> cla) throws Exception {
		return cla.getAnnotation(ExcelExportConfig.class).lineStartRow();
	}

	/**
	 * 
	 * 描述: 获取Excel的载体实体类中添加ExcelExportCol注解的属性集合<br>
	 * 
	 * @method :getExcelExportColAnnoFields<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:39:16 <br>
	 * @param cla
	 *            :Excel 的载体实体类
	 * @return
	 * @throws java.lang.Exception
	 */
	private static <T> List<Field> getExcelExportColAnnoFields(Class<T> cla)
			throws Exception {
		List<Field> list = new ArrayList<Field>();
		Field[] fields = cla.getDeclaredFields();
		for (Field f : fields) {
			if (f.isAnnotationPresent(ExcelExportCol.class)) {
				list.add(f);
			}
		}
		return list;
	}

	/**
	 * 
	 * 描述:验证导出Excel的载体实体类是否合法 <br>
	 * 
	 * @method :checkValidate<br>
	 * @author :wanglongjie<br>
	 * @createDate :2015年12月2日下午2:54:59 <br>
	 * @param list
	 *            :对象集合数据源
	 * @return
	 * @throws Exception
	 */
	private static boolean checkValidate(List<?> list) throws Exception {
		if (null == list || list.size() == 0) {
			throw new Exception("指定的对象集合数据源为null,或者长度等于0!");
		}
		Class<?> cla = list.get(0).getClass();

		if (!cla.isAnnotationPresent(ExcelExportConfig.class)) {
			throw new Exception("指定的实体类" + list.get(0).getClass().getName()
					+ " 缺少ExcelExportConfig注解!");
		}

		int headerRow = getHeaderRow(cla);
		int lineStartRow = getLineStartRow(cla);

		if (headerRow >= lineStartRow) {
			throw new Exception("指定的实体类" + cla.getName()
					+ " 设置的标题头行应该小于内容记录开始行!");
		}

		if (getExcelExportColAnnoFields(cla).size() == 0) {
			throw new Exception("指定的实体类" + cla.getName()
					+ " 属性缺少ExcelExportCol注解!");
		}

		return true;
	}
}

已整理成完整项目,并进行了优化。看参考地址:

https://gitee.com/andy_longjie/exceltools   或者 https://github.com/youmulongjie/exceltools

 

转载于:https://my.oschina.net/andy1989/blog/540539

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值