使用Apache POI写的一个生成/解析 Excel的工具类

帅比萌擦擦* 提交于 2019-12-07 01:51:43

2016年10月24日15:47:51 更新,发布了最新版本,修改了一些BUG。另外在最后加上了调用的示例代码

package com.eya.util.office;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.List;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.usermodel.HSSFFont;
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.poifs.filesystem.POIFSFileSystem;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.util.CellRangeAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.eya.util.ProDateUtil;
import com.eya.util.reflects.ReflectUtils;

/**
 * Excel工具类
 * @create ll
 * @createDate 2016年4月14日 上午9:23:02
 * @update 
 * @updateDate
 */
public class PoiExcelUtils {

    /** 数字格式化 */
    private static NumberFormat format = NumberFormat.getInstance();
    /** 日志 */
    private static final Logger LOGGER = LoggerFactory.getLogger(PoiExcelUtils.class);
    /** 列默认宽度 */
    private static final int DEFAUL_COLUMN_WIDTH = 4000;

    /**
     * 1.创建 workbook
     * @return {@link HSSFWorkbook}
     * @Author : ll. create at 2016年4月14日 上午9:28:27
     */
    private HSSFWorkbook getHSSFWorkbook() {
        LOGGER.info("【创建 workbook】");
        return new HSSFWorkbook();
    }

    /**
     * 2.创建 sheet
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param sheetName sheet 名称
     * @return {@link HSSFSheet}
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private HSSFSheet getHSSFSheet(HSSFWorkbook hssfWorkbook, String sheetName) {
        LOGGER.info("【创建 sheet】sheetName : " + sheetName);
        return hssfWorkbook.createSheet(sheetName);
    }

    /**
     * 3.写入表头信息
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param hssfSheet {@link HSSFSheet}
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值
     * </p>
     * @param title 标题
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private void writeHeader(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers,
                             String title) {
        LOGGER.info("【写入表头信息】");

        // 头信息处理
        String[] newHeaders = headersHandler(headers);

        // 初始化标题和表头单元格样式
        HSSFCellStyle titleCellStyle = createTitleCellStyle(hssfWorkbook);
        // 标题栏
        HSSFRow titleRow = hssfSheet.createRow(0);
        titleRow.setHeight((short) 500);
        HSSFCell titleCell = titleRow.createCell(0);
        // 设置标题文本
        titleCell.setCellValue(new HSSFRichTextString(title));
        // 设置单元格样式
        titleCell.setCellStyle(titleCellStyle);

        // 处理单元格合并,四个参数分别是:起始行,终止行,起始行,终止列
        hssfSheet.addMergedRegion(new CellRangeAddress(0, 0, (short) 0,
            (short) (newHeaders.length - 1)));

        // 设置合并后的单元格的样式
        titleRow.createCell(newHeaders.length - 1).setCellStyle(titleCellStyle);

        // 表头
        HSSFRow headRow = hssfSheet.createRow(1);
        headRow.setHeight((short) 500);
        HSSFCell headCell = null;
        String[] headInfo = null;
        // 处理excel表头
        for (int i = 0, len = newHeaders.length; i < len; i++) {
            headInfo = newHeaders[i].split("@");
            headCell = headRow.createCell(i);
            headCell.setCellValue(headInfo[0]);
            headCell.setCellStyle(titleCellStyle);
            // 设置列宽度
            setColumnWidth(i, headInfo, hssfSheet);
        }
    }

    /**
     * 写入表头信息
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param hssfSheet {@link HSSFSheet}
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值
     * </p>
     * @param startIndex 起始行索引
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private void writeHeader(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers,
                             int startIndex) {
        LOGGER.info("【写入表头信息】");

        HSSFCellStyle headerCellStyle = createTitleCellStyle(hssfWorkbook);

        // 表头
        HSSFRow headRow = hssfSheet.createRow(startIndex);
        headRow.setHeight((short) 500);
        HSSFCell headCell = null;
        String[] headInfo = null;
        // 处理excel表头
        for (int i = 0, len = headers.length; i < len; i++) {
            headInfo = headers[i].split("@");
            headCell = headRow.createCell(i);
            headCell.setCellValue(headInfo[0]);
            headCell.setCellStyle(headerCellStyle);
            // 设置列宽度
            setColumnWidth(i, headInfo, hssfSheet);
        }
    }

    /**
     * 头信息校验和处理
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值
     * </p>
     * @return 校验后的头信息
     * @Author : ll. create at 2016年4月14日 上午9:24:48
     */
    private String[] headersHandler(String[] headers) {
        List<String> newHeaders = new ArrayList<String>();
        for (String string : headers) {
            if (StringUtils.isNotBlank(string)) {
                newHeaders.add(string);
            }
        }
        int size = newHeaders.size();

        return newHeaders.toArray(new String[size]);
    }

    /**
     * 4.写入内容部分(默认从第三行开始写入)
     * 
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param hssfSheet {@link HSSFSheet}
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值
     * </p>
     * @param dataList 要导出的数据集合
     * @throws Exception 
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private void writeContent(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers,
                              List<?> dataList) throws Exception {
        writeContent(hssfWorkbook, hssfSheet, headers, dataList, 2);
    }

    /**
     * 4.写入内容部分
     * 
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param hssfSheet {@link HSSFSheet}
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值
     * </p>
     * @param dataList 要导出的数据集合
     * @param startIndex 起始行的索引
     * @throws Exception 
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private void writeContent(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers,
                              List<?> dataList, int startIndex) throws Exception {
        LOGGER.info("【写入Excel内容部分】");
        // 2015-8-13 增加,当没有数据的时候,把原来抛异常的方式修改成返回一个只有头信息,没有数据的空Excel
        if (CollectionUtils.isEmpty(dataList)) {
            LOGGER.warn("【没有内容数据】");
            return;
        }
        HSSFRow row = null;
        HSSFCell cell = null;
        // 单元格的值
        Object cellValue = null;
        // 数据写入行索引
        int rownum = startIndex;
        // 单元格样式
        HSSFCellStyle cellStyle = createContentCellStyle(hssfWorkbook);
        // 遍历集合,处理数据
        for (int j = 0, size = dataList.size(); j < size; j++) {
            row = hssfSheet.createRow(rownum);
            for (int i = 0, len = headers.length; i < len; i++) {
                cell = row.createCell(i);
                cellValue = ReflectUtils.getValueOfGetIncludeObjectFeild(dataList.get(j),
                    headers[i].split("@")[1]);
                cellValueHandler(cell, cellValue);
                cell.setCellStyle(cellStyle);
            }
            rownum++;
        }
    }

    /**
     * 设置列宽度
     * @param i 列的索引号
     * @param headInfo 表头信息,其中包含了用户需要设置的列宽
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private void setColumnWidth(int i, String[] headInfo, HSSFSheet hssfSheet) {
        if (headInfo.length < 3) {
            // 用户没有设置列宽,使用默认宽度
            hssfSheet.setColumnWidth(i, DEFAUL_COLUMN_WIDTH);
            return;
        }
        if (StringUtils.isBlank(headInfo[2])) {
            // 使用默认宽度
            hssfSheet.setColumnWidth(i, DEFAUL_COLUMN_WIDTH);
            return;
        }
        // 使用用户设置的列宽进行设置
        hssfSheet.setColumnWidth(i, Integer.parseInt(headInfo[2]));
    }

    /**
     * 单元格写值处理器
     * @param {{@link HSSFCell}
     * @param cellValue 单元格值
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private void cellValueHandler(HSSFCell cell, Object cellValue) {
        // 2015-8-13 修改,判断cellValue是否为空,否则在cellValue.toString()会出现空指针异常
        if (cellValue == null) {
            cell.setCellValue("");
            return;
        }
        if (cellValue instanceof String) {
            cell.setCellValue((String) cellValue);
        } else if (cellValue instanceof Boolean) {
            cell.setCellValue((Boolean) cellValue);
        } else if (cellValue instanceof Calendar) {
            cell.setCellValue((Calendar) cellValue);
        } else if (cellValue instanceof Double) {
            cell.setCellValue((Double) cellValue);
        } else if (cellValue instanceof Integer || cellValue instanceof Long
                   || cellValue instanceof Short || cellValue instanceof Float) {
            cell.setCellValue((Double.parseDouble(cellValue.toString())));
        } else if (cellValue instanceof HSSFRichTextString) {
            cell.setCellValue((HSSFRichTextString) cellValue);
        }
        cell.setCellValue(cellValue.toString());
    }

    /**
     * 创建标题和表头单元格样式
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @return {@link HSSFCellStyle}
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private HSSFCellStyle createTitleCellStyle(HSSFWorkbook hssfWorkbook) {
        LOGGER.info("【创建标题和表头单元格样式】");
        // 单元格的样式
        HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle();
        // 设置字体样式,改为变粗
        HSSFFont font = hssfWorkbook.createFont();
        font.setFontHeightInPoints((short) 13);
        font.setBoldweight(Font.BOLDWEIGHT_BOLD);
        cellStyle.setFont(font);
        // 单元格垂直居中
        cellStyle.setVerticalAlignment(HSSFCellStyle.ALIGN_CENTER_SELECTION);
        // 设置通用的单元格属性
        setCommonCellStyle(cellStyle);
        return cellStyle;
    }

    /**
     * 创建内容单元格样式
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @return {@link HSSFCellStyle}
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private HSSFCellStyle createContentCellStyle(HSSFWorkbook hssfWorkbook) {
        LOGGER.info("【创建内容单元格样式】");
        // 单元格的样式
        HSSFCellStyle cellStyle = hssfWorkbook.createCellStyle();
        // 设置字体样式,改为不变粗
        HSSFFont font = hssfWorkbook.createFont();
        font.setFontHeightInPoints((short) 11);
        cellStyle.setFont(font);
        // 设置单元格自动换行
        cellStyle.setWrapText(true);
        // 单元格垂直居中
        cellStyle.setVerticalAlignment(HSSFCellStyle.ALIGN_CENTER_SELECTION);
        //水平居中
        //        cellStyle.setAlignment(HSSFCellStyle.ALIGN_CENTER);
        // 设置通用的单元格属性
        setCommonCellStyle(cellStyle);
        return cellStyle;
    }

    /**
     * 设置通用的单元格属性
     * @param cellStyle 要设置属性的单元格
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private void setCommonCellStyle(HSSFCellStyle cellStyle) {
        // 居中
        cellStyle.setAlignment(CellStyle.ALIGN_CENTER);
        // 设置边框
        cellStyle.setBorderBottom(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderLeft(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderTop(HSSFCellStyle.BORDER_THIN);
        cellStyle.setBorderRight(HSSFCellStyle.BORDER_THIN);
    }

    /**
     * 将生成的Excel输出到指定目录
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param filePath 文件输出目录,包括文件名(.xls)
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    private void write2FilePath(HSSFWorkbook hssfWorkbook, String filePath) {
        LOGGER.info("【将生成的Excel输出到指定目录】filePath :" + filePath);
        FileOutputStream fileOut = null;
        try {
            fileOut = new FileOutputStream(filePath);
            hssfWorkbook.write(fileOut);
        } catch (Exception e) {
            LOGGER.error("【将生成的Excel输出到指定目录失败】", e);
            throw new RuntimeException("将生成的Excel输出到指定目录失败");
        } finally {
            IOUtils.closeQuietly(fileOut);
        }
    }

    /**
     * 生成Excel,存放到指定目录
     * @param sheetName sheet名称
     * @param title 标题
     * @param filePath 要导出的Excel存放的文件路径
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值,默认4000
     * </p>
     * @param dataList 要导出数据的集合
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static void createExcel2FilePath(String sheetName, String title, String filePath,
                                            String[] headers, List<?> dataList) throws Exception {
        if (ArrayUtils.isEmpty(headers)) {
            LOGGER.warn("【表头为空】");
            throw new RuntimeException("表头不能为空");
        }
        LOGGER.info("【生成Excel,并存放到指定文件夹目录下】sheetName : " + sheetName + " , title : " + title
                    + " , filePath : " + filePath + " , headers : " + Arrays.toString(headers));

        PoiExcelUtils poiExcelUtil = new PoiExcelUtils();
        // 1.创建 Workbook
        HSSFWorkbook hssfWorkbook = poiExcelUtil.getHSSFWorkbook();
        // 2.创建 Sheet
        HSSFSheet hssfSheet = poiExcelUtil.getHSSFSheet(hssfWorkbook, sheetName);
        // 3.写入 head
        poiExcelUtil.writeHeader(hssfWorkbook, hssfSheet, headers, title);
        // 4.写入内容
        poiExcelUtil.writeContent(hssfWorkbook, hssfSheet, headers, dataList);
        // 5.保存文件到filePath中
        poiExcelUtil.write2FilePath(hssfWorkbook, filePath);
    }

    /**
     * 生成Excel,存放到指定目录
     * @param sheetName sheet名称
     * @param title 标题
     * @param filePath 要导出的Excel存放的文件路径
     * @param mainDataFields 主表数据需要展示的字段集合
     * <p>
     * 如{"字段1@beanFieldName1","字段2@beanFieldName2",字段3@beanFieldName3"}
     * </p> 
     * @param mainData 主表数据
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值,默认4000
     * </p>
     * @param detailDataList 要导出数据的集合
     * @param needExportDate 是否需要显示“导出日期”
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static void createExcel2FilePath(String sheetName, String title, String filePath,
                                            String[] mainDataFields, Object mainData,
                                            String[] headers, List<?> detailDataList,
                                            final boolean needExportDate) throws Exception {
        if (ArrayUtils.isEmpty(headers)) {
            LOGGER.warn("【参数headers为空】");
            throw new IllegalArgumentException("headers");
        }
        if (ArrayUtils.isEmpty(mainDataFields)) {
            LOGGER.warn("【参数mainDataFields】");
            throw new IllegalArgumentException("mainDataFields");
        }
        if (mainData == null) {
            LOGGER.warn("【参数mainData】");
            throw new IllegalArgumentException("mainData");
        }
        LOGGER.info("【生成Excel,并存放到指定文件夹目录下】sheetName : " + sheetName + " , title : " + title
                    + " , filePath : " + filePath + " , headers : " + Arrays.toString(headers));

        PoiExcelUtils poiExcelUtil = new PoiExcelUtils();
        // 1.创建 Workbook
        HSSFWorkbook hssfWorkbook = poiExcelUtil.getHSSFWorkbook();
        // 2.创建 Sheet
        HSSFSheet hssfSheet = poiExcelUtil.getHSSFSheet(hssfWorkbook, sheetName);
        // 3.写标题
        headers = poiExcelUtil.writeTitle(hssfWorkbook, hssfSheet, headers, title);
        // 4.写主表(mainData)数据
        int usedRows = poiExcelUtil.writeMainData(hssfWorkbook, hssfSheet, headers.length,
            mainDataFields, mainData, 1, needExportDate);
        // 5.写入 head  这里默认将title写入到了第一行,所以header的起始行索引为usedRows + 1
        poiExcelUtil.writeHeader(hssfWorkbook, hssfSheet, headers, usedRows + 1);
        // 6.写从表(detailDataList)内容
        poiExcelUtil.writeContent(hssfWorkbook, hssfSheet, headers, detailDataList, usedRows + 2);
        // 7.保存文件到filePath中
        poiExcelUtil.write2FilePath(hssfWorkbook, filePath);
    }

    /**
     * 写标题
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param hssfSheet {@link HSSFSheet}
     * @param headers 表头
     * @param title 标题
     * @return 去除无效表头后的新表头集合
     * @Author : ll. create at 2016年5月23日 上午11:24:08
     */
    private String[] writeTitle(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers,
                                String title) {
        return writeTitle(hssfWorkbook, hssfSheet, headers, title, 0);
    }

    /**
     * 写标题
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param hssfSheet {@link HSSFSheet}
     * @param headers 表头
     * @param title 标题
     * @param titleRowIndex 标题行的索引
     * @return 去除无效表头后的新表头集合
     * @Author : ll. create at 2016年5月23日 上午11:24:08
     */
    private String[] writeTitle(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, String[] headers,
                                String title, int titleRowIndex) {
        // 头信息处理
        String[] newHeaders = headersHandler(headers);

        // 初始化标题和表头单元格样式
        HSSFCellStyle titleCellStyle = createTitleCellStyle(hssfWorkbook);
        // 标题栏
        HSSFRow titleRow = hssfSheet.createRow(titleRowIndex);
        titleRow.setHeight((short) 500);
        HSSFCell titleCell = titleRow.createCell(0);
        // 设置标题文本
        titleCell.setCellValue(new HSSFRichTextString(title));
        // 设置单元格样式
        titleCell.setCellStyle(titleCellStyle);

        // 处理单元格合并,四个参数分别是:起始行,终止行,起始列,终止列
        hssfSheet.addMergedRegion(new CellRangeAddress(titleRowIndex, titleRowIndex, (short) 0,
            (short) (newHeaders.length - 1)));

        // 设置合并后的单元格的样式
        titleRow.createCell(newHeaders.length - 1).setCellStyle(titleCellStyle);

        return newHeaders;
    }

    /**
     * 写主表(mainData)数据
     * @param hssfWorkbook {@link HSSFWorkbook}
     * @param hssfSheet {@link HSSFSheet}
     * @param columnSize 列数
     * @param mainDataFields 主表数据需要展示的字段集合
     * @param mainData 主表数据对象
     * @param startIndex 起始行索引
     * @param needExportDate 是否需要输出“导出日期”
     * @return 主表数据使用了多少行
     * @throws Exception 
     * @Author : ll. create at 2016年5月23日 上午10:24:58
     */
    private int writeMainData(HSSFWorkbook hssfWorkbook, HSSFSheet hssfSheet, int columnSize,
                              String[] mainDataFields, Object mainData, int startIndex,
                              boolean needExportDate) throws Exception {
        LOGGER.info("【写主表(mainData)数据】columnSize = {} , mainDataFields = {} , mainData = {}",
            columnSize, Arrays.toString(mainDataFields), mainData);

        // 1.计算主表数据需要写多少行,每行写多少个单元格,每行写多少个字段
        int fieldsSize = mainDataFields.length;
        // 导出日期是否需要独立一行显示
        boolean exportDateSingleRow = fieldsSize * 2 % columnSize == 0;

        // 主表属性需要的行数
        int needRows = exportDateSingleRow ? fieldsSize * 2 / columnSize : fieldsSize * 2
                                                                           / columnSize + 1;
        if (needExportDate && exportDateSingleRow) {
            needRows += 1;
        }
        // 主表属性显示时,每行显示的主表属性量
        int filedSizeInOneRow = fieldsSize * 2 < columnSize ? fieldsSize : columnSize / 2;

        // 列数是否为偶数
        final boolean isEvenColumn = columnSize % 2 == 0;

        //        // 每个字段需要2个单元格进行展示 --> fieldName : value
        //        int fieldsSize = mainDataFields.length;
        //        int needCellSize = needExportDate ? (fieldsSize + 1) * 2 : fieldsSize * 2;
        //        // 转换列数为偶数
        //        final boolean isEvenColumn = columnSize % 2 == 0;
        //        int availableColumns = isEvenColumn ? columnSize : columnSize - 1;
        //        // 计算写主表数据需要多少行
        //        int needRows = needCellSize % availableColumns == 0 ? needCellSize / availableColumns
        //            : needCellSize / availableColumns + 1;
        //        // 每行显示的字段数
        //        int fieldsSizeAddExportDateCell = needExportDate ? fieldsSize + 1 : fieldsSize;
        //        int filedSizeInOneRow = fieldsSizeAddExportDateCell % needRows == 0 ? fieldsSizeAddExportDateCell
        //                                                                             / needRows
        //            : fieldsSizeAddExportDateCell / needRows + 1;

        // 2.开始写主表数据
        HSSFRow row = null;
        HSSFCell cell4FiledName = null;
        HSSFCell cell4Value = null;

        // 数据写入行索引
        int rownum = startIndex;
        // 单元格样式
        HSSFCellStyle cellStyle = createContentCellStyle(hssfWorkbook);
        // 每一行的单元格的索引
        int cellIndex = 0;
        // 主表字段的数组索引
        int fieldIndex = 0;
        for (int i = 0; i < needRows; i++) {
            row = hssfSheet.createRow(rownum);
            for (int j = 0; j < filedSizeInOneRow; j++) {
                if (fieldIndex == fieldsSize) {
                    break;
                }
                // 取出对应索引的主表字段,然后切割成字符串数组
                String[] fieldsArray = mainDataFields[fieldIndex].split("@");
                fieldIndex++;
                // 每个字段对应的单元格的索引
                cellIndex = j * 2;
                // 字段描述的单元格
                cell4FiledName = row.createCell(cellIndex);
                cellValueHandler(cell4FiledName, fieldsArray[0]);
                cell4FiledName.setCellStyle(cellStyle);
                // 字段值的单元格
                cell4Value = row.createCell(cellIndex + 1);
                cellValueHandler(cell4Value,
                    ReflectUtils.getValueOfGetIncludeObjectFeild(mainData, fieldsArray[1]));
                cell4Value.setCellStyle(cellStyle);

                // 如果当前行还可以继续写数据,则将导出日期写在该行
                if (fieldIndex == fieldsSize && needExportDate && filedSizeInOneRow != j + 1) {
                    writeExportDate(hssfWorkbook, row, cellIndex + 2);
                    needExportDate = false;
                    hssfSheet.addMergedRegion(new CellRangeAddress(rownum, rownum,
                        (short) cellIndex + 3, (short) (columnSize - 1)));
                    // 设置合并后的单元格的样式
                    setMergedCellStyle(row, cellIndex + 3, columnSize - 1, cellStyle);
                }

                // 如果最后一个有值的单元格后还有空白单元格,将他们合并
                if ((j == filedSizeInOneRow - 1 && !isEvenColumn) || fieldIndex == fieldsSize) {
                    int startCellIndex = needExportDate ? (short) cellIndex + 1
                        : (short) cellIndex + 3;
                    // 处理单元格合并,四个参数分别是:起始行,终止行,起始列,终止列
                    hssfSheet.addMergedRegion(new CellRangeAddress(rownum, rownum, startCellIndex,
                        (short) (columnSize - 1)));
                    // 设置合并后的单元格的样式
                    setMergedCellStyle(row, startCellIndex, columnSize - 1, cellStyle);
                }
            }

            // 导出日期独自占用一行
            if (needExportDate && fieldIndex == fieldsSize) {
                int exportDateRowNum = rownum + 1;
                row = hssfSheet.createRow(exportDateRowNum);
                writeExportDate(hssfWorkbook, row, 0);
                hssfSheet.addMergedRegion(new CellRangeAddress(exportDateRowNum, exportDateRowNum,
                    1, (short) (columnSize - 1)));
                // 设置合并后的单元格的样式
                setMergedCellStyle(row, 1, columnSize - 1, cellStyle);
                // 生成一次导出日期之后,改变标识
                needExportDate = false;
                break;
            }

            rownum++;
        }
        return needRows;
    }

    /**
     * 设置合并后的单元格的样式
     * @param row {@link HSSFRow}
     * @param beginCellIdnex 合并开始的单元格
     * @param endCellIndex 合并结束的单元格
     * @param cellStyle {@link HSSFCellStyle}
     * @Author : ll. create at 2016年5月23日 下午5:32:12
     */
    private void setMergedCellStyle(HSSFRow row, int beginCellIdnex, int endCellIndex,
                                    HSSFCellStyle cellStyle) {
        for (int i = beginCellIdnex + 1; i <= endCellIndex; i++) {
            row.createCell(i).setCellStyle(cellStyle);
        }
    }

    /**
     * 写入导出日期
     * @param row {@link HSSFRow}
     * @param cellIndex 列索引
     * @Author : ll. create at 2016年5月23日 下午3:13:41
     */
    private void writeExportDate(HSSFWorkbook hssfWorkbook, HSSFRow row, int cellIndex) {
        // 单元格样式
        HSSFCellStyle cellStyle = createContentCellStyle(hssfWorkbook);
        // 导出日期
        HSSFCell cell4ExortDate = row.createCell(cellIndex);
        cellValueHandler(cell4ExortDate, "导出日期");
        cell4ExortDate.setCellStyle(cellStyle);
        // 导出日期的值
        HSSFCell cell4ExportDateValue = row.createCell(cellIndex + 1);
        cellValueHandler(cell4ExportDateValue,
            ProDateUtil.getCurrentDate(ProDateUtil.DATE_TIME_FORMAT));
        cell4ExportDateValue.setCellStyle(cellStyle);
    }

    /**
     * 生成Excel的WorkBook,用于导出Excel
     * @param sheetName sheet名称
     * @param title 标题
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值,默认4000
     * </p>
     * @param dataList 要导出数据的集合
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static HSSFWorkbook createExcel2Export(String sheetName, String title, String[] headers,
                                                  List<?> dataList) throws Exception {

        if (ArrayUtils.isEmpty(headers)) {
            LOGGER.warn("【表头为空】");
            throw new RuntimeException("表头不能为空");
        }
        LOGGER.info("【生成Excel的WorkBook,用于导出Excel】sheetName : " + sheetName + " , title : " + title
                    + "  , headers : " + Arrays.toString(headers));
        PoiExcelUtils poiExcelUtil = new PoiExcelUtils();
        // 1.创建 Workbook
        HSSFWorkbook hssfWorkbook = poiExcelUtil.getHSSFWorkbook();
        // 2.创建 Sheet
        HSSFSheet hssfSheet = poiExcelUtil.getHSSFSheet(hssfWorkbook, sheetName);
        // 3.写入 head
        poiExcelUtil.writeHeader(hssfWorkbook, hssfSheet, headers, title);
        // 4.写入内容
        poiExcelUtil.writeContent(hssfWorkbook, hssfSheet, headers, dataList);

        return hssfWorkbook;
    }

    /**
     * 生成Excel的WorkBook,用于导出Excel
     * @param sheetName sheet名称
     * @param title 标题
     * @param mainDataFields 主表数据需要展示的字段集合
     * <p>
     * 如{"字段1@beanFieldName1","字段2@beanFieldName2",字段3@beanFieldName3"}
     * </p> 
     * @param mainData 主表数据
     * @param headers 列标题,数组形式
     * <p>
     * 如{"列标题1@beanFieldName1@columnWidth","列标题2@beanFieldName2@columnWidth","列标题3@beanFieldName3@columnWidth"}
     * </p>
     * <p>
     * 其中参数@columnWidth可选,columnWidth为整型数值,默认4000
     * </p>
     * @param detailDataList 要导出数据的集合
     * @param needExportDate 是否需要“导出日期”
     * @return {@link HSSFWorkbook}
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static HSSFWorkbook createExcel2Export(String sheetName, String title,
                                                  String[] mainDataFields, Object mainData,
                                                  String[] headers, List<?> detailDataList,
                                                  boolean needExportDate) throws Exception {
        if (ArrayUtils.isEmpty(headers)) {
            LOGGER.warn("【参数headers为空】");
            throw new IllegalArgumentException("headers");
        }
        if (ArrayUtils.isEmpty(mainDataFields)) {
            LOGGER.warn("【参数mainDataFields】");
            throw new IllegalArgumentException("mainDataFields");
        }
        if (mainData == null) {
            LOGGER.warn("【参数mainData】");
            throw new IllegalArgumentException("mainData");
        }
        LOGGER.info("【生成Excel,用于导出】sheetName : " + sheetName + " , title : " + title
                    + " , headers : " + Arrays.toString(headers) + " , mainDataFields = "
                    + Arrays.toString(mainDataFields));

        PoiExcelUtils poiExcelUtil = new PoiExcelUtils();
        // 1.创建 Workbook
        HSSFWorkbook hssfWorkbook = poiExcelUtil.getHSSFWorkbook();
        // 2.创建 Sheet
        HSSFSheet hssfSheet = poiExcelUtil.getHSSFSheet(hssfWorkbook, sheetName);
        // 3.写标题
        headers = poiExcelUtil.writeTitle(hssfWorkbook, hssfSheet, headers, title);
        // 4.写主表(mainData)数据
        int usedRows = poiExcelUtil.writeMainData(hssfWorkbook, hssfSheet, headers.length,
            mainDataFields, mainData, 1, needExportDate);
        // 5.写入 head  这里默认将title写入到了第一行,然后需要header和主表详情间隔一行
        poiExcelUtil.writeHeader(hssfWorkbook, hssfSheet, headers, usedRows + 2);
        // 6.写从表(detailDataList)内容
        poiExcelUtil.writeContent(hssfWorkbook, hssfSheet, headers, detailDataList, usedRows + 3);

        return hssfWorkbook;
    }

    /**
     * 根据文件路径读取excel文件,默认读取第0个sheet
     * @param excelPath excel的路径
     * @param skipRows 需要跳过的行数
     * @param columnCount 列数量
     * @return List<String[]> 集合中每一个元素是一个数组,按单元格索引存储每个单元格的值,一个元素可以封装成一个需要的java bean
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static List<String[]> readExcel(String excelPath, int skipRows, int columnCount)
                                                                                           throws Exception {
        return readExcel(excelPath, skipRows, columnCount, 0, null);
    }

    /**
     * 根据文件路径读取excel文件的指定sheet
     * @param excelPath excel的路径
     * @param skipRows 需要跳过的行数
     * @param columnCount 列数量
     * @param sheetNo 要读取的sheet的索引,从0开始
     * @return List<String[]> 集合中每一个元素是一个数组,按单元格索引存储每个单元格的值,一个元素可以封装成一个需要的java bean
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static List<String[]> readExcel(String excelPath, int skipRows, int columnCount,
                                           int sheetNo) throws Exception {
        return readExcel(excelPath, skipRows, columnCount, sheetNo, null);
    }

    /**
     * 根据文件路径读取excel文件的指定sheet,并封装空值单位各的坐标,默认读取第0个sheet
     * @param excelPath excel的路径
     * @param skipRows 需要跳过的行数
     * @param columnCount 列数量
     * @param noneCellValuePositionList 存储空值的单元格的坐标,每个坐标以x-y的形式拼接,如2-5表示第二行第五列
     * @return List<String[]> 集合中每一个元素是一个数组,按单元格索引存储每个单元格的值,一个元素可以封装成一个需要的java bean
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static List<String[]> readExcel(String excelPath, int skipRows, int columnCount,
                                           List<String> noneCellValuePositionList) throws Exception {
        return readExcel(excelPath, skipRows, columnCount, 0, noneCellValuePositionList);
    }

    /**
     * 根据文件路径读取excel文件的指定sheet,并封装空值单位各的坐标,默认读取第0个sheet
     * @param excelPath excel的路径
     * @param skipRows 需要跳过的行数
     * @param columnCount 列数量
     * @param columnNumberForSkipValueValidateSet 不需要做空值验证的列的索引集合
     * @param noneCellValuePositionList 存储空值的单元格的坐标,每个坐标以x-y的形式拼接,如2-5表示第二行第五列
     * @return List<String[]> 集合中每一个元素是一个数组,按单元格索引存储每个单元格的值,一个元素可以封装成一个需要的java bean
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static List<String[]> readExcel(String excelPath, int skipRows, int columnCount,
                                           Set<Integer> columnNumberForSkipValueValidateSet,
                                           List<String> noneCellValuePositionList) throws Exception {
        return readExcel(excelPath, skipRows, columnCount, 0, columnNumberForSkipValueValidateSet,
            noneCellValuePositionList);
    }

    /**
     * 根据文件路径读取excel文件的指定sheet,并封装空值单位各的坐标
     * @param excelPath excel的路径
     * @param skipRows 需要跳过的行数
     * @param columnCount 列数量
     * @param sheetNo 要读取的sheet的索引,从0开始
     * @param noneCellValuePositionList 存储空值的单元格的坐标,每个坐标以x-y的形式拼接,如2-5表示第二行第五列
     * @return List<String[]> 集合中每一个元素是一个数组,按单元格索引存储每个单元格的值,一个元素可以封装成一个需要的java bean
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static List<String[]> readExcel(String excelPath, int skipRows, int columnCount,
                                           int sheetNo, List<String> noneCellValuePositionList)
                                                                                               throws Exception {
        return readExcel(excelPath, skipRows, columnCount, sheetNo, null, noneCellValuePositionList);
    }

    /**
     * 根据文件路径读取excel文件的指定sheet,并封装空值单位各的坐标
     * @param excelPath excel的路径
     * @param skipRows 需要跳过的行数
     * @param columnCount 列数量
     * @param sheetNo 要读取的sheet的索引,从0开始
     * @param columnNumberForSkipValueValidateSet 不需要做空值验证的列的索引集合
     * @param noneCellValuePositionList 存储空值的单元格的坐标,每个坐标以x-y的形式拼接,如2-5表示第二行第五列
     * @return List<String[]> 集合中每一个元素是一个数组,按单元格索引存储每个单元格的值,一个元素可以封装成一个需要的java bean
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:28:39
     */
    public static List<String[]> readExcel(String excelPath, int skipRows, int columnCount,
                                           int sheetNo,
                                           Set<Integer> columnNumberForSkipValueValidateSet,
                                           List<String> noneCellValuePositionList) throws Exception {
        LOGGER
            .info(
                "【读取Excel】excelPath = {} , skipRows = {} , columnCount = {} , columnNumberForSkipValueValidateSet = {}",
                excelPath, skipRows, columnCount, columnNumberForSkipValueValidateSet);

        if (StringUtils.isBlank(excelPath)) {
            LOGGER.warn("【参数excelPath为空】");
            return new ArrayList<String[]>();
        }

        FileInputStream is = new FileInputStream(new File(excelPath));
        POIFSFileSystem fs = new POIFSFileSystem(is);
        HSSFWorkbook wb = new HSSFWorkbook(fs);
        List<String[]> list = new ArrayList<String[]>();
        HSSFSheet sheet = wb.getSheetAt(sheetNo);
        // 得到总共的行数
        int rowNum = sheet.getPhysicalNumberOfRows();
        try {
            for (int i = skipRows; i < rowNum; i++) {
                String[] vals = new String[columnCount];
                HSSFRow row = sheet.getRow(i);
                if (null == row) {
                    continue;
                }
                for (int j = 0; j < columnCount; j++) {
                    HSSFCell cell = row.getCell(j);
                    String val = getStringCellValue(cell);

                    // 没有需要跳过校验的列索引
                    if (CollectionUtils.isEmpty(columnNumberForSkipValueValidateSet)) {
                        if (noneCellValuePositionList != null && StringUtils.isBlank(val)) {
                            // 封装空值单元格的坐标
                            noneCellValuePositionList.add((i + 1) + "-" + j);
                        }
                    } else {
                        // 如果需要校验空值的单元格、当前列索引不在需要跳过校验的索引集合中
                        if (noneCellValuePositionList != null && StringUtils.isBlank(val)
                            && !columnNumberForSkipValueValidateSet.contains(j)) {
                            // 封装空值单元格的坐标
                            noneCellValuePositionList.add((i + 1) + "-" + j);
                        }
                    }

                    vals[j] = val;
                }
                list.add(vals);
            }
        } catch (Exception e) {
            LOGGER.error("【Excel解析失败】", e);
            throw new RuntimeException("Excel解析失败");
        } finally {
            wb.close();
        }
        return list;
    }

    /**
     * 获取单元格数据内容为字符串类型的数据
     * @param cell Excel单元格{@link HSSFCell}
     * @return 单元格数据内容(可能是布尔类型等,强制转换成String)
     * @Author : ll. create at 2016年4月14日 上午9:53:07
     */
    private static String getStringCellValue(HSSFCell cell) {
        if (cell == null) {
            return "";
        }
        String strCell = "";
        switch (cell.getCellType()) {
            case HSSFCell.CELL_TYPE_STRING:
                strCell = cell.getStringCellValue();
                break;
            case HSSFCell.CELL_TYPE_NUMERIC:
                strCell = String.valueOf(format.format(cell.getNumericCellValue()))
                    .replace(",", "");
                break;
            case HSSFCell.CELL_TYPE_BOOLEAN:
                strCell = String.valueOf(cell.getBooleanCellValue());
                break;
            case HSSFCell.CELL_TYPE_BLANK:
                strCell = "";
                break;
            default:
                strCell = "";
                break;
        }
        if (StringUtils.isBlank(strCell)) {
            return "";
        }

        return strCell;
    }

}

 

2016年10月24日15:49:33更新:补充了反射工具类ReflectUtils.java

 

package com.eya.util.reflects;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.apache.commons.lang3.StringUtils;

import com.eya.util.ProString;

/**
 * 反射工具类
 * @create ll
 * @createDate 2016年4月14日 上午9:17:51
 * @update 
 * @updateDate
 */
public class ReflectUtils {

    /**
     * 通过字段名从对象或对象的父类中得到字段的值
     * @param object 对象实例
     * @param fieldName 字段名
     * @return 字段对应的值
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:18:19
     */
    public static Object getValue(Object object, String fieldName) throws Exception {
        if (object == null) {
            return null;
        }
        if (StringUtils.isBlank(fieldName)) {
            return null;
        }
        Field field = null;
        Class<?> clazz = object.getClass();
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);
                return field.get(object);
            } catch (Exception e) {
                //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。  
                //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了  
            }
        }

        return null;
    }

    /**
     * 通过字段名从对象或对象的父类中得到字段的值(调用字典的get方法)
     * @param object 对象实例
     * @param fieldName 字段名
     * @return 字段对应的值
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:18:19
     */
    public static Object getValueOfGet(Object object, String fieldName) throws Exception {
        if (object == null) {
            return null;
        }
        if (StringUtils.isBlank(fieldName)) {
            return null;
        }
        Field field = null;
        Class<?> clazz = object.getClass();
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);

                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                //获得get方法  
                Method getMethod = pd.getReadMethod();
                //执行get方法返回一个Object
                return getMethod.invoke(object);
            } catch (Exception e) {
                //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。  
                //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了  
            }
        }

        return null;
    }

    /**
     * 通过字段名从对象或对象的父类中得到字段的值(调用字典的get方法,可以取出复杂的对象的值)
     * @param object 对象实例
     * @param fieldName 字段名
     * @return 字段对应的值
     * @throws Exception
     * @Author : ll. create at 2016年4月14日 上午9:18:19
     */
    public static Object getValueOfGetIncludeObjectFeild(Object object, String fieldName)
                                                                                         throws Exception {

        if (object == null) {
            return null;
        }
        if (StringUtils.isBlank(fieldName)) {
            return null;
        }
        Field field = null;
        Class<?> clazz = object.getClass();
        for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
            try {
                if (fieldName.contains(".")) {
                    // 如:operatorUser.name、operatorUser.org.name,递归调用
                    String[] splitFiledName = fieldName.split("\\.");
                    return getValueOfGetIncludeObjectFeild(
                        getValueOfGetIncludeObjectFeild(object, splitFiledName[0]),
                        splitFiledName[1]);
                }
                field = clazz.getDeclaredField(fieldName);
                field.setAccessible(true);

                PropertyDescriptor pd = new PropertyDescriptor(field.getName(), clazz);
                //获得get方法  
                Method getMethod = pd.getReadMethod();
                //执行get方法返回一个Object
                return getMethod.invoke(object);
            } catch (Exception e) {
                //这里甚么都不要做!并且这里的异常必须这样写,不能抛出去。  
                //如果这里的异常打印或者往外抛,则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了  
            }
        }

        return null;
    }

}

 

2016年10月27日09:12:27 更新

调用代码,分为两种,一种是主从表形式,如一个采购订单,有订单的主信息,如采购人,采购时间等,从表信息是采购的商品明细信息。另一种是简单的表格数据,如导出系统所有的用户信息等。

示例一:主从表形式(service的实现)

/**
 * 生成用于导出Excel的数据
 * @param id 到货单ID
 * @return {@link HSSFWorkbook}
 * @Author : ll. create at 2016年10月24日 下午2:02:40
 */
public HSSFWorkbook exportExcel(String id) {
	logger.info("【生成需要导出的到货单Excel表格数据】id = {}" + id);
	if (ProString.isBlank(id)) {
		logger.warn("【参数id为空】");
		throw new BusinessException(LangResource.get(
			ErrorEnum.COMMON_NULL_ARGUMENT.getDescCode(), "id"));
	}
	// 查询主表数据
	ArrivalOrderView arrivalOrderView = this.detail(id);
	// 查询从表数据
	List<ArrivalOrderDetailView> detailList = arrivalOrderDetailService.selectList((id);
	
	// 配置主表数据需要显示的字段
	String[] mainDataFields = { "到货单号@id", "采购单号@billNum", "供应商@orgIdExportValue",
							   "状态@statusValue", "仓库@depotIdValue", "经手人@userIdOperatorValue",
							   "到货日期@arriveDateValue", "联系人@contacts", "联系电话@contactPhone",
							   "审核人@checkByValue", "审核日期@checkDateValue", "创建人@createByValue",
							   "创建日期@createDateValue", "备注@remark" };
	// 配置明细表需要显示的字段
	String[] headers = { "产品代码@reagentCode", "产品名称@reagentName@6000", "生产厂家@brandName",
						"规格@standard", "注册证号@licenseNumber@5000",
						"注册证有效起始日期@licenseBeginDateValue@6000",
						"注册证失效日期@licenseEndDateValue@6000", "生产批号@storeBatchNumber",
						"生产日期@productionDateValue", "失效日期@effectiveEndDateValue", "数量@qty",
						"单位@unitName", "合格标志@qualifiedMarkValue", "不合格原因@invalidReason@8000" };

	try {
		return PoiExcelUtils.createExcel2Export("到货单明细信息", "到货单明细信息", mainDataFields,
			arrivalOrderView, headers, detailList, true);
	} catch (Exception e) {
		logger.error("【生成Excel表格数据失败】", e);
		throw new RuntimeException("生成Excel表格数据失败");
	}
}

导出的效果

示例二:简单的表格数据(service的实现)

/**
 * 生成需要导出的Excel表格数据
 * @param id 需要导出的明细数据
 * @return {@link HSSFWorkbook}
 * @Author : ll. create at 2016年6月30日 下午12:00:39
 */
public HSSFWorkbook exportExcel(List<PurchOrderDetailQueryView> purchOrderDetailQueryViewList) {
	logger.info("【生成需要导出的Excel表格数据】purchOrderDetailQueryViewList = {}",
		purchOrderDetailQueryViewList);

	String[] headers = { "采购日期@purchDate@8000", "采购单号@purchNum@8000", "试剂代码@reagentCode",
						"试剂名称@reagentName@13000", "生产厂家@brand", "规格@standard@7000",
						"供应商@orgIdProvider", "数量@qty", "单位@unitName", "单价@price",
						"主单位数量@qtyOfMainUnit", "主单位@mainUnitName", "金额@amt" };

	try {
		return PoiExcelUtils.createExcel2Export("采购明细", "采购明细", headers,
			purchOrderDetailQueryViewList);
	} catch (Exception e) {
		logger.error("【生成Excel表格数据失败】", e);
		throw new RuntimeException("生成Excel表格数据失败", e);
	}
}

导出的效果

这里再提供一下Controller的实现,只提供一个就可以,因为都是类似的。

/**
 * 导出到货单Excel
 * @param request {@link HttpServletRequest}
 * @param response {@link HttpServletResponse}
 * @param id 到货单的id
 * @Author : ll. create at 2016年6月1日 下午4:48:44
 */
@RequestMapping(value = "exportExcel.do", method = RequestMethod.GET)
public void exportExcel(HttpServletRequest request, HttpServletResponse response,
						@RequestParam(value = "id", required = true) String id) {
	logger.info("【导出到货单Excel】id = {}", id);
	init(request);
	try {
		HSSFWorkbook hssfWorkbook = arrivalOrderService.exportExcel(id);
		writeWorkbook(response, hssfWorkbook);
	} catch (Exception e) {
		logger.error("【导出到货单Excel失败】", e);
		throw new ForwardErrorPageException("导出到货单Excel失败");
	}
}

/**
 * 导出Excel数据表格
 * @param response {@link HttpServletResponse}
 * @param workbook {@link HSSFWorkbook}
 * @Author : ll. create at 2016年5月21日 上午11:12:18
 */
protected void writeWorkbook(HttpServletResponse response, HSSFWorkbook workbook) {
	response.reset();
	response.setCharacterEncoding("utf-8");
	response.setContentType("multipart/form-data");
	String fileName = System.currentTimeMillis() + ".xls";
	response.setHeader("Content-Disposition", "attachment;fileName=" + fileName);
	OutputStream out = null;
	try {
		out = response.getOutputStream();
		workbook.write(out);
		workbook.close();
	} catch (Exception e) {
		logger.error("【导出失败】", e);
	} finally {
		// 使用的是org.apache.commons.io.IOUtils
		IOUtils.closeQuietly(out);
	}
}

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!