POI-Excel生成------JAVA实现Excel表单数据导出功能(优化版)

注意:

  1. 具体的包结构在这里就不说明了,读者可以自行安排包结构。
  2. 请使用POILoadExcelUtils对外工具类进行Excel模板导出或是Excel数据导出。
  3. 注意titleNameArr数组元素和 fieldNameArr数组元素按索引位置的一一对应关系。

1、一些常量

package com.dsanjun.poi.constant;

/**
 * 常量
 * 
 * @author dyw
 * @date 2019年9月1日
 */
public class Constants {
	/**
	 * 07版excel后缀名
	 */
	public static String EXCEL_SUFFIX_07 = "xlsx";
	/**
	 * 03版excel后缀名
	 */
	public static String EXCEL_SUFFIX_03 = "xls";
}

2、Excel后缀名错误异常

package com.dsanjun.poi.exception;

/**
 * Excel后缀名错误异常
 * 
 * @author dyw
 *
 */
public class NoSuchExcelSuffixException extends RuntimeException {
	private static final long serialVersionUID = 7849681800154791175L;
	public static final String MESSAGE = "Excel form suffix name error";

	public NoSuchExcelSuffixException() {
		super(MESSAGE);
	}
}

3、一些封装数据的对象

封装表头对象列表和表单数据的对象

package com.dsanjun.poi.bean;

import java.util.List;
import java.util.Map;

/**
 * Excel表格数据对象
 * 
 * @author dyw
 * @date 2019年9月3日
 */
public final class ExcelData {
	/** 表头 */
	private List<TitleCell> titleList;
	/** 表单数据 */
	private List<Map<String, Object>> content;

	public List<TitleCell> getTitleList() {
		return titleList;
	}

	/**
	 * 初始化一个含有表头行的表格数据对象
	 * 
	 * @param titleList
	 * @return
	 */
	public ExcelData initTitleList(List<TitleCell> titleList) {
		this.titleList = titleList;
		return this;
	}

	/**
	 * 初始化一个含有数据行的表格数据对象
	 * 
	 * @param content
	 * @return
	 */
	public ExcelData initContent(List<Map<String, Object>> content) {
		this.content = content;
		return this;
	}

	public void setTitleList(List<TitleCell> titleList) {
		this.titleList = titleList;
	}

	public List<Map<String, Object>> getContent() {
		return content;
	}

	public void setContent(List<Map<String, Object>> content) {
		this.content = content;
	}

	@Override
	public String toString() {
		return "ExcelData [titleList=" + titleList + ", content=" + content + "]";
	}
}

表头对象

package com.dsanjun.poi.bean;

/**
 * 列标题单元格
 * 
 * @author dyw
 * @date 2019年9月3日
 */
public final class TitleCell {
	private Integer index;
	private String name;

	private TitleCell(Integer index, String name) {
		this.index = index;
		this.name = name;
	}

	public static TitleCell getInstance(Integer index, String name) {
		return new TitleCell(index, name);
	}

	public Integer getIndex() {
		return index;
	}

	public void setIndex(Integer index) {
		this.index = index;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public String toString() {
		return "Title [index=" + index + ", name=" + name + "]";
	}
}

4、核心业务对象

创建工具

package com.dsanjun.poi.create;

import java.io.IOException;
import java.io.OutputStream;
import org.apache.poi.ss.usermodel.Workbook;
import com.dsanjun.poi.bean.ExcelData;

/**
 * 工具
 * 
 * @author dyw
 * @date 2019年9月5日
 */
public class ExcelCreater {

	/**
	 * 创建Excel工作簿
	 * 
	 * @param suffix    文件后缀
	 * @param excelData 表单数据对象
	 * @return Workbook
	 */
	public static Workbook workbook(String suffix, ExcelData excelData) {
		return new ExcelHander().initWorkbook(suffix).initSheet().createRows(0, excelData).create();
	}

	/**
	 * 导出Excel表单到输出流
	 * 
	 * @param suffix    文件后缀
	 * @param excelData 表单数据对象
	 * @param out       输出流
	 */
	public static void load(String suffix, ExcelData excelData, OutputStream out) {
		try {
			workbook(suffix, excelData).write(out);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

Excel构造器

package com.dsanjun.poi.create;

import java.text.SimpleDateFormat;
import java.util.Date;
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.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import com.dsanjun.poi.bean.ExcelData;
import com.dsanjun.poi.bean.TitleCell;
import com.dsanjun.poi.constant.Constants;
import com.dsanjun.poi.exception.NoSuchExcelSuffixException;

/**
 * 创建表单(链式构造器)
 * 
 * @author dyw
 * @date 2019年9月2日
 */
public final class ExcelHander {
	/**
	 * POI-Workbook表单对象
	 */
	private Workbook workbook;

	/**
	 * 构造完成
	 * 
	 * @return Workbook
	 */
	public Workbook create() {
		return workbook;
	}

	/**
	 * 创建行数据(当ExcelData不包含行数据时,只创建表头)
	 */
	public ExcelHander createRows(int sheetIndex, ExcelData excelData) {
		int sign = 0;
		Sheet sheet = workbook.getSheetAt(sheetIndex);
		List<TitleCell> titleList = excelData.getTitleList();
		if (titleList != null && titleList.size() > 0) {
			createExcelTilte(sheet, titleList);
			sign = sign + 1;
		}
		List<Map<String, Object>> content = excelData.getContent();
		if (content != null && content.size() > 0) {
			for (int i = 0; i < content.size(); i++) {
				createRow(sheet, i + sign, titleList, content.get(i));
			}
		}
		return this;
	}

	/**
	 * 创建表头
	 * 
	 * @param sheet
	 * @param titleList
	 */
	public void createExcelTilte(Sheet sheet, List<TitleCell> titleList) {
		Row titleRow = sheet.createRow(0);
		for (TitleCell title : titleList) {
			Cell titleCell = titleRow.createCell(title.getIndex());
			titleCell.setCellValue(title.getName());
		}
	}

	/**
	 * 创建指定sheet的指定行
	 * 
	 * @param sheet
	 * @param titleList
	 * @param rowData
	 */
	public void createRow(Sheet sheet, int rowIndex, List<TitleCell> titleList, Map<String, Object> rowData) {
		for (int i = 0; i < rowData.size(); i++) {
			Row contentRow = sheet.createRow(rowIndex);
			for (int j = 0; j < titleList.size(); j++) {
				TitleCell headTitle = titleList.get(j);
				String headerName = headTitle.getName();
				Object data = rowData.get(headerName);
				if (data instanceof String) {
					contentRow.createCell(j).setCellValue((String) data);
				} else if (data instanceof Double) {
					contentRow.createCell(j).setCellValue((Double) data);
				} else if (data instanceof Date) {
					String formatStr = "yyyy年MM月dd日 HH:mm:ss";
					SimpleDateFormat format = new SimpleDateFormat(formatStr);
					contentRow.createCell(j).setCellValue(format.format((Date) data));
				} else if (data instanceof Long) {
					contentRow.createCell(j).setCellValue((Long) data);
				} else if (data instanceof Float) {
					contentRow.createCell(j).setCellValue((Float) data);
				} else if (data instanceof Integer) {
					contentRow.createCell(j).setCellValue((Integer) data);
				}
			}
		}
	}

	/**
	 * 指定sheetname创建sheet
	 * 
	 * @param sheetname
	 * @return
	 */
	public ExcelHander initSheet(String sheetname) {
		workbook.createSheet(sheetname);
		return this;
	}

	/**
	 * 使用默认sheetname创建sheet
	 * 
	 * @return
	 */
	public ExcelHander initSheet() {
		workbook.createSheet();
		return this;
	}

	/**
	 * 根据后缀名创建Workbook
	 * 
	 * @param suffix 后缀(xlsx,xls)
	 * @return Workbook
	 */
	public ExcelHander initWorkbook(String suffix) {
		if (!Constants.EXCEL_SUFFIX_03.equals(suffix) && !Constants.EXCEL_SUFFIX_07.equals(suffix)) {
			throw new NoSuchExcelSuffixException();
		}
		if (Constants.EXCEL_SUFFIX_03.equals(suffix)) {
			workbook = new HSSFWorkbook();
		}
		if (Constants.EXCEL_SUFFIX_07.equals(suffix)) {
			workbook = new XSSFWorkbook();
		}
		return this;
	}
}

数据转换器

package com.dsanjun.poi.create;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.dsanjun.poi.bean.ExcelData;
import com.dsanjun.poi.bean.TitleCell;

/**
 * <pre>
 * 关于下载的数据转换工具:
 * 1、titleNameArr数组和fieldNameArr必须保证各个索引位置的值是对应关系
 * 2、fieldNameArr的元素在数据bean属性中都有,或是在数据map的key中都有
 * 3、此处任何关于titleNameArr和fieldNameArr的合法性校验,请按标准传入
 * </pre>
 * 
 * @author dyw
 * @date 2019年9月6日
 */
public class LoadConverter {

	/**
	 * 对象列表转ExcelData,注意titleNameArr和fieldNameArr元素是按照索引位置一一对应的
	 * 
	 * @param <E>
	 * @param titleNameArr 用户指定的Excel表头数组
	 * @param fieldNameArr Excel表头对应的实体类的属性名
	 * @param list         bean对象列表
	 * @return Excel表格数据对象(包含表头和数据)
	 */
	public static <E> ExcelData convertBeanListToExcelData(String[] titleNameArr, String[] fieldNameArr, List<E> list) {
		return new ExcelData().initTitleList(convertToTitleList(titleNameArr))
				.initContent(convertBeanListToContent(titleMapFile(titleNameArr, fieldNameArr), list));
	}

	/**
	 * 对象列表转ExcelData,注意titleNameArr和fieldNameArr元素是按照索引位置一一对应的
	 * 
	 * @param titleNameArr 用户指定的Excel表头数组
	 * @param fieldNameArr Excel表头对应的实体类的属性名
	 * @param list         map对象列表
	 * @return ExcelData数据对象(包含表头和数据)
	 */
	public static ExcelData convertMapListToExcelData(String[] titleNameArr, String[] fieldNameArr,
			List<Map<String, Object>> list) {
		return new ExcelData().initTitleList(convertToTitleList(titleNameArr))
				.initContent(convertMapListToContent(titleMapFile(titleNameArr, fieldNameArr), list));
	}

	/**
	 * 用户指定的Excel表头数组转换成TitleCell列表
	 * 
	 * @param titleNameArr 用户指定的Excel表头数组
	 * @return TitleCell对象列表
	 */
	public static List<TitleCell> convertToTitleList(String[] titleNameArr) {
		List<TitleCell> titleList = new ArrayList<TitleCell>();
		for (int i = 0; i < titleNameArr.length; i++) {
			titleList.add(TitleCell.getInstance(i, titleNameArr[i]));
		}
		return titleList;
	}

	/**
	 * 获取用户指定表头和属性字段(或map的key)的映射关系
	 * 
	 * @param titleNameArr 用户指定的Excel表头数组
	 * @param fieldNameArr Excel表头对应的实体类的属性名或Excel表头对应Map的key
	 * @return 表头和属性(或key)的映射关系
	 */
	private static Map<String, String> titleMapFile(String[] titleNameArr, String[] fieldNameArr) {
		Map<String, String> map = new HashMap<String, String>();
		for (int i = 0; i < titleNameArr.length; i++) {
			map.put(titleNameArr[i], fieldNameArr[i]);
		}
		return map;
	}

	/**
	 * List<E>--->List<Map<String, Object>>
	 * 
	 * @param <E>
	 * @param tfmap 用户自定义表头和实体属性字段的映射关系(titleName--->fieldName)
	 * @param list  实体数据列表
	 * @return 表头-->值映射集合列表
	 */
	private static <E> List<Map<String, Object>> convertBeanListToContent(Map<String, String> tfmap, List<E> list) {
		try {
			List<Map<String, Object>> datas = new ArrayList<Map<String, Object>>();
			for (E temp : list) {
				Map<String, Object> data = beanToMap(tfmap, temp);
				if (data != null) {
					datas.add(data);
				}
			}
			return datas;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * List<E>--->List<Map<String, Object>>
	 * 
	 * @param <E>
	 * @param map  用户自定义表头和实体属性字段的映射关系(titleName--->fieldName)
	 * @param list 实体数据列表
	 * @return 表头-->值映射集合列表
	 */
	private static List<Map<String, Object>> convertMapListToContent(Map<String, String> tfmap,
			List<Map<String, Object>> list) {
		try {
			List<Map<String, Object>> datas = new ArrayList<Map<String, Object>>();
			for (Map<String, Object> temp : list) {
				Map<String, Object> data = mapToMap(tfmap, temp);
				if (data != null) {
					datas.add(data);
				}
			}
			return datas;
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * T--->Map<String, Object>
	 * 
	 * @param <T>
	 * @param tfmap 用户自定义表头和实体属性字段的映射关系(titleName--->fieldName)
	 * @param map   待转换的Map
	 * @return Map集合的键为用户自定义表头字段
	 * @throws Exception
	 */
	private static Map<String, Object> mapToMap(Map<String, String> tfmap, Map<String, Object> map) throws Exception {
		Map<String, Object> data = new HashMap<String, Object>();
		Set<String> keySet = tfmap.keySet();
		for (String temp : keySet) {
			data.put(temp, map.get(tfmap.get(temp)));
		}
		return data;
	}

	/**
	 * T--->Map<String, Object>
	 * 
	 * @param <T>
	 * @param map 用户自定义表头和实体属性字段的映射关系(titleName--->fieldName)
	 * @param t   待转换的实体
	 * @return Map集合的键为用户自定义表头字段
	 * @throws Exception
	 */
	private static <T> Map<String, Object> beanToMap(Map<String, String> tfmap, T t) throws Exception {
		Map<String, Object> data = new HashMap<String, Object>();
		Set<String> keySet = tfmap.keySet();
		for (String key : keySet) {
			Class<?> clazz = t.getClass();
			String fileName = tfmap.get(key);
			Field field = clazz.getDeclaredField(fileName);// 此处没有进行判断,可能会有属性字段获取不到的异常
			field.setAccessible(true);
			data.put(key, field.get(t));
		}
		return data;
	}
}

5、对外工具(进行Excel模板或是数据导出)

package com.dsanjun.poi;

import java.io.OutputStream;
import java.util.List;
import java.util.Map;
import com.dsanjun.poi.bean.ExcelData;
import com.dsanjun.poi.create.ExcelCreater;
import com.dsanjun.poi.create.LoadConverter;

/**
 * 表单生成对外工具:模板创建,导出数据
 * 
 * @author dyw
 * @date 2019年9月6日
 */
public class POILoadExcelUtils {
	/**
	 * 指定表头创建Excel表单
	 * 
	 * @param suffix       Excel后缀
	 * @param titleNameArr Excel表头数组
	 * @param out          输出流
	 */
	public static void exportTemplate(String suffix, String[] titleNameArr, OutputStream out) {
		ExcelCreater.load(suffix, new ExcelData().initTitleList(LoadConverter.convertToTitleList(titleNameArr)), out);
	}

	/**
	 * 实体对象数据源导出Excel
	 * 
	 * @param <E>
	 * @param suffix       Excel后缀
	 * @param titleNameArr Excel表头数组
	 * @param fieldNameArr bean的属性数组
	 * @param list         bean数据源
	 * @param out          输出流
	 */
	public static <E> void exportExcelFromBeanList(String suffix, String[] titleNameArr, String[] fieldNameArr,
			List<E> list, OutputStream out) {
		ExcelCreater.load(suffix, LoadConverter.convertBeanListToExcelData(titleNameArr, fieldNameArr, list), out);
	}

	/**
	 * map集合数据源导出Excel
	 * 
	 * @param suffix       Excel后缀
	 * @param titleNameArr Excel表头数组
	 * @param fieldNameArr map的key数组
	 * @param list         map数据源
	 * @param out          输出流
	 */
	public static void exportExcelFromMapList(String suffix, String[] titleNameArr, String[] fieldNameArr,
			List<Map<String, Object>> list, OutputStream out) {
		ExcelCreater.load(suffix, LoadConverter.convertMapListToExcelData(titleNameArr, fieldNameArr, list), out);
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

豢龙先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值