POI-Excel导出Excel模板、导出Excel数据
注意:
- 具体的包结构在这里就不说明了,读者可以自行安排包结构。
- 请使用POILoadExcelUtils对外工具类进行Excel模板导出或是Excel数据导出。
- 注意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);
}
}