Java之Excel导出工具类使用教程

前言:

本工具类经过PostMan和web页面严格测试可用,经过了多个版本迭代优化,可以直接使用,也方便大家根据自己的业务需求,修改定制自己的导出工具。
市面上有很多封装好的导出工具(如:阿里的easyExcel,GitHub上xxl-excel等),但如果直接引用依赖,扩展性和定制性比较差,所以博主通过apache.poi,自己实现一款Excel导出工具,方便定制使用。本工具类支持SpringMVC等主流的Java框架,支持RESTful接口,代码全部通过测试。

转载后PS:设置样式要具体在代码中去找一下,有注释,想配置的话,在项目中做相关构造一个实体类(建数据库)完成配置数据的存储,使用时具体在查询样式格式的配置。下面的都是默认的。

原来是没有说明依赖版本的,我用的POI依赖:(好似用这一个就行了)

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.13</version>
</dependency>

一.功能介绍:

  • 支持List实体类导出
  • 支持List列数不固定的数据导出
  • 支持多Sheet页导出
  • 支持导出文件名为URL编码,防止乱码
  • 支持文件名、sheet名特殊字符自动替换
  • 支持Excel2007以上版本
  • 支持有数据的文本框描边
  • 支持表头字体加大
  • 表头数据单元格内换行
  • 支持标题栏
  • 支持选择null空字段是否导出
  • 支持将日期格式数据转换为自定义格式的时间字符串
  • 支持单元格类型区分数值、字符串,单元格对齐方式不同对待
  • 支持将Excel导出到HttpServletResponse流中(用做对外提供接口)

二.导出工具类源码:

注: 此代码可直接在项目中使用。

import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.usermodel.*;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 导出Excel工具类
 *
 * @author 大脑补丁
 *
 */
public class ExportExcelUtil<T> {

    /**
     * 导出多Sheet的Excel到HttpServletResponse流中
     *
     * @param fileName
     *            另存为文件名
     * @param sheetNames
     *            工作簿中的多张Sheet工作表的名称列表
     * @param titleName
     *            表格的标题名称(没有标题,则传null)
     * @param headers
     *            表头列表
     * @param dataLists
     *            要导出的数据源
     * @param response
     *            Http响应
     * @param pattern
     *            时间类型数据的格式,默认UTC格式
     * @param isExportNullField
     *            空字段是否导出(true:导出,false:不导出)
     * @see   :导出Excel格式 表头内容居中,字体略大于正文,颜色深灰色。正文文本类型对齐方式居左,数字类型对齐方式居右。仅有数据* 的单元格,有边框环绕,实体类的属性顺序即为表头顺序
     */
    public static <T> void exportExcel(String fileName, List<String> sheetNames, String titleName, List<String> headers,
                                       List<List<T>> dataLists, HttpServletResponse response, String pattern, boolean isExportNullField) {
        XSSFWorkbook wb = exportAllExcel(sheetNames, titleName, headers, dataLists, pattern, isExportNullField);
        setResponseHeader(response, replaceSpecStr(fileName));
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            wb.write(out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.flush();
                out.close();
                wb.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 导出多Sheet动态列的Excel到HttpServletResponse流中
     *
     * @param fileName
     *            另存为文件名
     * @param sheetNames
     *            工作簿中的多张Sheet工作表的名称列表
     * @param titleName
     *            表格的标题名称(没有标题,则传null)
     * @param headers
     *            表头列表
     * @param dataLists
     *            要导出的数据源
     * @param response
     *            Http响应
     * @param pattern
     *            时间类型数据的格式,默认UTC格式
     * @param isExportNullField
     *            空字段是否导出(true:导出,false:不导出)
     */
    public static void exportDynamicExcel(String fileName, List<String> sheetNames, String titleName,
                                          List<String> headers, List<List<Map<String, Object>>> dataLists, HttpServletResponse response,
                                          String pattern, boolean isExportNullField) {
        XSSFWorkbook wb = exportDynamicExcelImpl(sheetNames, titleName, headers, dataLists, pattern, isExportNullField);
        setResponseHeader(response, replaceSpecStr(fileName));
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            wb.write(out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.flush();
                out.close();
                wb.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 设置响应的类型、编码和文件名称
     *
     * @param response
     * @param fileName
     */
    public static void setResponseHeader(HttpServletResponse response, String fileName) {
        try {
            response.reset();
            response.setContentType("application/msexcel");// 设置生成的文件类型
            response.setCharacterEncoding("UTF-8");// 设置文件头编码方式和文件名
            // 在浏览器中测试生效,postman中文件名为response,无法修改
            response.setHeader("Content-disposition", "attachment;filename="
                    .concat(String.valueOf(URLEncoder.encode(replaceSpecStr(fileName) + ".xlsx", "UTF-8"))));
            // 此设置,可保证web端可以取到文件名
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 设置响应的类型、编码和文件名称
     *
     * @param response
     * @param fileName
     */
    public static void setResponseHeader(HttpServletResponse response, String fileName, boolean urlEncode) {
        try {
            String downloadName = urlEncode == true
                    ? String.valueOf(URLEncoder.encode(replaceSpecStr(fileName) + ".xlsx", "UTF-8"))
                    : String.valueOf(replaceSpecStr(fileName) + ".xlsx");
            response.reset();
            response.setContentType("application/msexcel");// 设置生成的文件类型
            response.setCharacterEncoding("UTF-8");// 设置文件头编码方式和文件名
            // 在浏览器中测试生效,postman中文件名为response,无法修改
            response.setHeader("Content-Disposition", "attachment;filename=".concat(downloadName));
            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 多Sheet导出实现
     *
     * @param sheetNames
     * @param titleName
     * @param headers
     * @param dataLists
     * @param pattern
     * @param isExportNullField
     * @return
     */
    private static <T> XSSFWorkbook exportAllExcel(List<String> sheetNames, String titleName, List<String> headers,
                                                   List<List<T>> dataLists, String pattern, boolean isExportNullField) {
        // 创建一个工作薄
        XSSFWorkbook workbook = new XSSFWorkbook();
        for (int i = 0; i < dataLists.size(); i++) {
            // 创建一个工作表
            XSSFSheet sheet = workbook.createSheet(replaceSpecStr(sheetNames.get(i)));
            // 设置单元格列宽度为16个字节--------------------------dxl-------------
            sheet.setDefaultColumnWidth((short) 16);
            // 创建表头样式
            XSSFCellStyle headersStyle = workbook.createCellStyle();
            headersStyle.setBorderTop(BorderStyle.THIN);
            headersStyle.setBorderBottom(BorderStyle.THIN);
            headersStyle.setBorderLeft(BorderStyle.THIN);
            headersStyle.setBorderRight(BorderStyle.THIN);
            // 表头内容对齐方式:居中
            headersStyle.setAlignment(HorizontalAlignment.CENTER);
            XSSFFont headersFont = workbook.createFont();
            // 设置字体格式
            headersFont.setColor(new XSSFColor(java.awt.Color.DARK_GRAY));
            headersFont.setFontHeightInPoints((short) 14);
            // 表头样式应用生效
            headersStyle.setFont(headersFont);
            XSSFCellStyle dataSetStyle = workbook.createCellStyle();
            // 正文单元格边框样式
            dataSetStyle.setBorderBottom(BorderStyle.THIN);
            dataSetStyle.setBorderRight(BorderStyle.THIN);
            dataSetStyle.setBorderLeft(BorderStyle.THIN);
            // 数据内容对齐方式:居左
            // dataSetStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
            XSSFFont dataSetFont = workbook.createFont();
            // 正文字体颜色
            dataSetFont.setColor(new XSSFColor(java.awt.Color.BLACK));
            // 为正文设置样式
            dataSetStyle.setFont(dataSetFont);
            if (titleName != null && titleName != "") {
                XSSFCellStyle titleStyle = workbook.createCellStyle();
                // 将首行合并居中作为标题栏
                sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, headers.size() - 1));
                XSSFFont titleFont = workbook.createFont();
                // 设置标题字体大小
                titleFont.setFontHeightInPoints((short) 20);
                // 设置标题字体样式
                titleStyle.setFont(titleFont);
                // 创建标题行并设置样式
                XSSFRow titleRow = sheet.createRow(0);
                XSSFCell titleCell = titleRow.createCell(0);
                titleCell.setCellStyle(titleStyle);
                titleCell.setCellValue(titleName);
            }
            int index = titleName == null || titleName.equals("") ? 0 : 1;
            // 创建表头并设置样式
            XSSFRow row = sheet.createRow(index);
            for (short j = 0; j < headers.size(); j++) {
                XSSFCell cell = row.createCell(j);
                cell.setCellStyle(headersStyle);
                XSSFRichTextString text = new XSSFRichTextString(headers.get(j));
                cell.setCellValue(text);
            }
            // 导出正文数据,并设置其样式
            Iterator<?> it = dataLists.get(i).iterator();
            while (it.hasNext()) {
                index++;
                row = sheet.createRow(index);
                Object entity = it.next();
                // 利用反射,根据实体类属性的先后顺序,动态调用其getXxx()方法,得到属性值
                Field[] fields = entity.getClass().getDeclaredFields();
                for (short k = 0; k < fields.length; k++) {
                    XSSFCell cell = row.createCell(k);
                    Field field = fields[k];
                    String fieldName = field.getName();
                    String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                    try {
                        @SuppressWarnings("rawtypes")
                        Class entityClass = entity.getClass();
                        @SuppressWarnings("unchecked")
                        Method getMethod = entityClass.getMethod(getMethodName, new Class[] {});
                        Object value = getMethod.invoke(entity, new Object[] {});
                        String textValue = null;
                        // 如果是时间类型,格式化
                        if (value instanceof Date) {
                            Date date = (Date) value;
                            pattern = pattern == null || pattern.equals("") ? "yyyy-MM-dd'T'HH:mm:ss'Z'" : pattern;
                            SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                            textValue = sdf.format(date);
                        } else {
                            // 若字段为空且允许导出空字段,则将null导出为""
                            textValue = value == null && isExportNullField ? "" : value.toString();
                        }
                        if (!textValue.equals("")) {
                            // 有数据时边框环绕
                            cell.setCellStyle(dataSetStyle);
                            // 正则判断是否为数值
                            Pattern p = Pattern.compile("^\\d+(\\.\\d+)?$");
                            Matcher matcher = p.matcher(textValue);
                            if (matcher.matches()) {
                                // 是数字当作double处理,整型也不会补充小数点
                                cell.setCellValue(Double.parseDouble(textValue));
                            } else {
                                // 不是数字类型作为文本输出
                                cell.setCellValue(textValue);
                            }
                        }
                    } catch (SecurityException e) {
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (IllegalArgumentException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return workbook;
    }

    /**
     * 多Sheet导出动态列到Excel实现
     *
     * @param sheetNames
     * @param titleName
     * @param headers
     * @param dataLists
     * @param pattern
     *            时间格式
     * @param isExportNullField
     *            是否导出空字段
     * @return
     */
    private static XSSFWorkbook exportDynamicExcelImpl(List<String> sheetNames, String titleName, List<String> headers,
                                                       List<List<Map<String, Object>>> dataLists, String pattern, boolean isExportNullField) {
        // 创建一个工作薄
        XSSFWorkbook workbook = new XSSFWorkbook();
        for (int i = 0; i < dataLists.size(); i++) {
            // 创建一个工作表
            XSSFSheet sheet = workbook.createSheet(replaceSpecStr(sheetNames.get(i)));
            // 设置单元格列宽度为16个字节
            sheet.setDefaultColumnWidth((short) 16);
            // 创建表头样式
            XSSFCellStyle headersStyle = workbook.createCellStyle();
            headersStyle.setBorderTop(BorderStyle.THIN);
            headersStyle.setBorderBottom(BorderStyle.THIN);
            headersStyle.setBorderLeft(BorderStyle.THIN);
            headersStyle.setBorderRight(BorderStyle.THIN);
            // 表头内容对齐方式:居中
            headersStyle.setAlignment(HorizontalAlignment.CENTER);
            XSSFFont headersFont = workbook.createFont();
            // 设置字体格式
            headersFont.setColor(new XSSFColor(java.awt.Color.DARK_GRAY));
            headersFont.setFontHeightInPoints((short) 12);
            // 表头样式应用生效
            headersStyle.setFont(headersFont);
            // 设置单元格内内容换行
            headersStyle.setWrapText(true);
            XSSFCellStyle dataSetStyle = workbook.createCellStyle();
            // 正文单元格边框样式
            dataSetStyle.setBorderBottom(BorderStyle.THIN);
            dataSetStyle.setBorderRight(BorderStyle.THIN);
            dataSetStyle.setBorderLeft(BorderStyle.THIN);
            // 数据内容对齐方式:居左
            // dataSetStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
            XSSFFont dataSetFont = workbook.createFont();
            // 正文字体颜色
//            dataSetFont.setColor(new XSSFColor(java.awt.Color.BLACK));
            dataSetFont.setColor(new XSSFColor(Color.blue));
            // 为正文设置样式
            dataSetStyle.setFont(dataSetFont);
            if (titleName != null && titleName != "") {
                XSSFCellStyle titleStyle = workbook.createCellStyle();
                // 将首行合并居中作为标题栏
                sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, headers.size() - 1));
                XSSFFont titleFont = workbook.createFont();
                // 设置标题字体大小
                titleFont.setFontHeightInPoints((short) 20);
                // 设置标题字体样式
                titleStyle.setFont(titleFont);
                // 创建标题行并设置样式
                XSSFRow titleRow = sheet.createRow(0);
                XSSFCell titleCell = titleRow.createCell(0);
                titleCell.setCellStyle(titleStyle);
                titleCell.setCellValue(titleName);
            }
            int index = titleName == null || titleName.equals("") ? 0 : 1;
            // 创建表头并设置样式
            XSSFRow row = sheet.createRow(index);
            for (short j = 0; j < headers.size(); j++) {
                XSSFCell cell = row.createCell(j);
                cell.setCellStyle(headersStyle);
                XSSFRichTextString text = new XSSFRichTextString(headers.get(j));
                cell.setCellValue(text);
            }
            // 导出正文数据,并设置其样式
            ListIterator<Map<String, Object>> it = dataLists.get(i).listIterator();
            while (it.hasNext()) {
                try {
                    index++;
                    row = sheet.createRow(index);
                    Map<String, Object> map = it.next();
                    headers = new ArrayList<String>(map.keySet());
                    List<Object> values = new ArrayList<Object>(map.values());
                    for (int k = 0; k < map.keySet().size(); k++) {
                        try {
                            XSSFCell cell = row.createCell(k);
                            String textValue = null;
                            Object value = values.get(k);
                            // 如果是时间类型,格式化
                            if (value instanceof Date) {
                                Date date = (Date) value;
                                pattern = pattern == null || pattern.equals("") ? "yyyy-MM-dd'T'HH:mm:ss'Z'" : pattern;
                                SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                                textValue = sdf.format(date);
                            } else {
                                // 若字段为空且允许导出空字段,则将null导出为""
                                textValue = value == null && isExportNullField ? "" : value.toString();
                            }
                            if (!textValue.equals("")) {
                                // 有数据时边框环绕
                                cell.setCellStyle(dataSetStyle);
                                // 正则判断是否为数值
                                Pattern p = Pattern.compile("^\\d+(\\.\\d+)?$");
                                Matcher matcher = p.matcher(textValue);
                                if (matcher.matches()) {
                                    // 是数字当作double处理,整型也不会补充小数点
                                    cell.setCellValue(Double.parseDouble(textValue));
                                } else {
                                    // 不是数字类型作为文本输出
                                    cell.setCellValue(textValue);
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return workbook;

    }

    /**
     * 导出Excel到HttpServletResponse流中
     *
     * @param fileName
     *            另存为文件名
     * @param sheetName
     *            工作簿中的一张工作表的名称
     * @param titleName
     *            表格的标题名称(无需创建,则传null)
     * @param headers
     *            表头列表
     * @param dataList
     *            要导出的数据源
     * @param response
     *            Http响应
     * @param pattern
     *            时间类型数据的格式,默认UTC格式
     * @param isExportNullField
     *            空字段是否导出(true:导出,false:不导出)
     */
    @Deprecated
    public static void exportOneSheetExcel(String fileName, String sheetName, String titleName, List<String> headers,
                                           Collection<Collection<? extends Object>> dataList, HttpServletResponse response, String pattern,
                                           boolean isExportNullField) {
        XSSFWorkbook wb = exportExcelToWorkbook(sheetName, titleName, headers, dataList, pattern, isExportNullField);
        setResponseHeader(response, replaceSpecStr(fileName));
        ServletOutputStream out = null;
        try {
            out = response.getOutputStream();
            wb.write(out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                out.flush();
                out.close();
                wb.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 导出核心实现
     *
     * @param sheetName
     * @param titleName
     * @param headers
     * @param dataList
     * @param pattern
     * @param isExportNullField
     * @return XSSFWorkbook
     */
    @Deprecated
    private static XSSFWorkbook exportExcelToWorkbook(String sheetName, String titleName, List<String> headers,
                                                      Collection<?> dataList, String pattern, boolean isExportNullField) {
        // 创建一个工作薄
        XSSFWorkbook workbook = new XSSFWorkbook();
        // 创建一个工作表
        XSSFSheet sheet = workbook.createSheet(replaceSpecStr(sheetName));
        // 设置单元格列宽度为16个字节
        sheet.setDefaultColumnWidth((short) 16);
        // 创建表头样式
        XSSFCellStyle headersStyle = workbook.createCellStyle();
        headersStyle.setBorderTop(BorderStyle.THIN);
        headersStyle.setBorderBottom(BorderStyle.THIN);
        headersStyle.setBorderLeft(BorderStyle.THIN);
        headersStyle.setBorderRight(BorderStyle.THIN);
        // 表头内容对齐方式:居中
        headersStyle.setAlignment(HorizontalAlignment.CENTER);
        XSSFFont headersFont = workbook.createFont();
        // 设置字体格式
        headersFont.setColor(new XSSFColor(java.awt.Color.DARK_GRAY));
        headersFont.setFontHeightInPoints((short) 14);
        // 表头样式应用生效
        headersStyle.setFont(headersFont);
        XSSFCellStyle dataSetStyle = workbook.createCellStyle();
        // 正文单元格边框样式
        dataSetStyle.setBorderBottom(BorderStyle.THIN);
        dataSetStyle.setBorderRight(BorderStyle.THIN);
        dataSetStyle.setBorderLeft(BorderStyle.THIN);
        // 数据内容对齐方式:居左
        // dataSetStyle.setAlignment(HorizontalAlignment.CENTER_SELECTION);
        XSSFFont dataSetFont = workbook.createFont();
        // 正文字体颜色
        dataSetFont.setColor(new XSSFColor(java.awt.Color.BLACK));
        // 为正文设置样式
        dataSetStyle.setFont(dataSetFont);
        if (titleName != null && titleName != "") {
            XSSFCellStyle titleStyle = workbook.createCellStyle();
            // 将首行合并居中作为标题栏
            sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, headers.size() - 1));
            XSSFFont titleFont = workbook.createFont();
            // 设置标题字体大小
            titleFont.setFontHeightInPoints((short) 20);
            // 设置标题字体样式
            titleStyle.setFont(titleFont);
            // 创建标题行并设置样式
            XSSFRow titleRow = sheet.createRow(0);
            XSSFCell titleCell = titleRow.createCell(0);
            titleCell.setCellStyle(titleStyle);
            titleCell.setCellValue(titleName);
        }
        int index = titleName == null || titleName.equals("") ? 0 : 1;
        // 创建表头并设置样式
        XSSFRow row = sheet.createRow(index);
        for (short i = 0; i < headers.size(); i++) {
            XSSFCell cell = row.createCell(i);
            cell.setCellStyle(headersStyle);
            XSSFRichTextString text = new XSSFRichTextString(headers.get(i));
            cell.setCellValue(text);
        }
        // 导出正文数据,并设置其样式
        Iterator<?> it = dataList.iterator();
        while (it.hasNext()) {
            index++;
            row = sheet.createRow(index);
            Object entity = it.next();
            // 利用反射,根据实体类属性的先后顺序,动态调用其getXxx()方法,得到属性值
            Field[] fields = entity.getClass().getDeclaredFields();
            for (short i = 0; i < fields.length; i++) {
                XSSFCell cell = row.createCell(i);
                Field field = fields[i];
                String fieldName = field.getName();
                String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                try {
                    @SuppressWarnings("rawtypes")
                    Class entityClass = entity.getClass();
                    @SuppressWarnings("unchecked")
                    Method getMethod = entityClass.getMethod(getMethodName, new Class[] {});
                    Object value = getMethod.invoke(entity, new Object[] {});
                    String textValue = null;
                    // 如果是时间类型,格式化
                    if (value instanceof Date) {
                        Date date = (Date) value;
                        pattern = pattern == null || pattern.equals("") ? "yyyy-MM-dd'T'HH:mm:ss'Z'" : pattern;
                        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
                        textValue = sdf.format(date);
                    } else {
                        // 若字段为空且允许导出空字段,则将null导出为""
                        textValue = value == null && isExportNullField ? "" : value.toString();
                    }
                    if (!textValue.equals("")) {
                        // 有数据时边框环绕
                        cell.setCellStyle(dataSetStyle);
                        // 正则判断是否为数值
                        Pattern p = Pattern.compile("^\\d+(\\.\\d+)?$");
                        Matcher matcher = p.matcher(textValue);
                        if (matcher.matches()) {
                            // 是数字当作double处理,整型也不会补充小数点
                            cell.setCellValue(Double.parseDouble(textValue));
                        } else {
                            // 不是数字类型作为文本输出
                            cell.setCellValue(textValue);
                        }
                    }
                } catch (SecurityException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }
        return workbook;
    }

    /**
     * 正则替换所有特殊字符
     *
     * @param orgStr
     * @return
     */
    public static String replaceSpecStr(String orgStr) {
        if (null != orgStr && !"".equals(orgStr.trim())) {
            String regEx = "[\\\\|:/\"<>?*\\[\\] ]";
            Pattern p = Pattern.compile(regEx);
            Matcher m = p.matcher(orgStr);
            return m.replaceAll("_");
        }
        return null;
    }

}

三.数据源数据结构解释:

1.导出方法参数数据源:List<List<T>> dataLists

第一层List:多个sheet页。
第二层List:一个Sheet页下的多条数据。
T:实体类,对应一个Sheet页下的一行数据。

2.导出方法参数数据源:List<List<Map<String, Object>>> dataLists

第一层List:多个Sheet页数据。
第二层List:一个Sheet页下的多条数据
Map<String, Object>:一个Sheet页下的一行数据,其中key:表头,value:对应单元格的值。

四.功能和使用方法:

1.导出实体类方式(没有测试,还是原来的,因为数据来源没有,也不好造)

使用场景: 适合Excel列的名称顺序和列数是固定的业务场景。

注意事项: 实体类的属性声明的顺序,即为Excel导出后列的顺序,想调整列的顺序,需调整实体类属性声明的顺序即可。

导出方法:

/**
	 * 导出多Sheet的Excel到HttpServletResponse流中
	 *
	 * @param fileName
	 *            另存为文件名
	 * @param sheetName
	 *            工作簿中的多张Sheet工作表的名称列表
	 * @param titleName
	 *            表格的标题名称(没有标题,则传null)
	 * @param headers
	 *            表头列表
	 * @param dataList
	 *            要导出的数据源
	 * @param HttpServletResponse
	 *            Http响应
	 * @param pattern
	 *            时间类型数据的格式,默认UTC格式
	 * @param isExportNullField
	 *            空字段是否导出(true:导出,false:不导出)
	 */
	public static <T> void exportExcel(String fileName, List<String> sheetNames, String titleName, List<String> headers,
			List<List<T>> dataLists, HttpServletResponse response, String pattern, boolean isExportNullField){……}
  • 使用示例:
  • 实体类示例:
package com.entity.dto;
import java.io.Serializable;

/**

数据转Excel对象 注:属性名的顺序和Excel列顺序必须相同
*/
@SuppressWarnings(“serial”)
public class EventDTO implements Serializable {
// 列字段1
private String name;
// 列字段2
private String code;

public String getName() {
return name;
}

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

public String getCode() {
return code;
}

public void setCode(String code) {
this.code = code;
}
}

 

注: 文件名和sheet名:注意不要含有Excel不支持的特殊字符。

使用示例:
在SpringMVC的RESTful接口中,控制器中调用示例

@GetMapping(value = "/myevent/export/{code}")
	public void exportEvent(HttpServletResponse response, @PathVariable("code") String code) {
		List<List<EventDTO>> dataLists = eventService.exportEvent(stationCode);
		if (dataLists != null && dataLists.size() > 0) {
			try {
				List<String> sheetNames = new ArrayList<String>(
						Arrays.asList("sheet页1, "sheet页2", "sheet页3"));
				List<String> headers = new ArrayList<String>(
						Arrays.asList("类型", "型号", "编号", "参数", "描述", "级别"));
				String excelName = "你的Excel名称";
				ExportExcelUtil.exportExcel(excelName, sheetNames, null, headers, dataLists, response, null, true);
			} catch (Exception e) {
				log.info("导出Excel出错", e);
			}
		}
	}

2.导出Map对象的方式(又测试了一下)

使用场景: 适合Excel列的名称和顺序和列数是不固定的,如每次导出的列数可能不一致的场景。

注意事项: Excel导出后列的顺序,为Map中的键值对加入的顺序,要想导出后列的顺序固定,可将Map实例化为LinkedHashMap即可使导出后的列顺序不会改变。

例: 如下方式缓存导出数据,导出后的“名称”列,会在“类型”列的左侧。

Map<String, Object> tempMap = new LinkedHashMap<String, Object>();
    tempMap.put("名称", device.getName());
	tempMap.put("类型", device.getDeviceType());

导出方法:

/**
	 * 导出多Sheet动态列的Excel到HttpServletResponse流中
	 *
	 * @param fileName
	 *            另存为文件名
	 * @param sheetName
	 *            工作簿中的多张Sheet工作表的名称列表
	 * @param titleName
	 *            表格的标题名称(没有标题,则传null)
	 * @param headers
	 *            表头列表
	 * @param dataList
	 *            要导出的数据源
	 * @param HttpServletResponse
	 *            Http响应
	 * @param pattern
	 *            时间类型数据的格式,默认UTC格式
	 * @param isExportNullField
	 *            空字段是否导出(true:导出,false:不导出)
	 */
	public static void exportDynamicExcel(String fileName, List<String> sheetNames, String titleName,
			List<String> headers, List<List<Map<String, Object>>> dataLists, HttpServletResponse response,
			String pattern, boolean isExportNullField) {……}

使用示例:(我自己测试的,因为原来的数据来源没有)
在SpringMVC的RESTful接口中,控制器中调用示例:

package com.dxl.system.controller.poi;

import io.swagger.annotations.Api;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * <b> 测试
 * </b><br><br><i>Description</i> :
 * <br><br>Date: 2020/1/4 ${time}    <br>Author : dxl
 */
@RestController
@Api(value = "excel",tags = {"excel--接口"})
public class TestpoiController {
    @PostMapping(value = "/history/export")
    public void exportHistory(HttpServletResponse response) {

        List<List<Map<String, Object>>> datalists = new ArrayList<>();
        for(int i = 0; i< 2; i++){//注意这个个数要与接口参数中sheet的个数一致
            List<Map<String, Object>> datalist = new ArrayList<>();
            for(int j = 0; j< 10; j++){
                Map<String, Object> map =  new LinkedHashMap<>();
                map.put("aaa","hhh"+j);
                map.put("bbb","开朗"+j);
                map.put("ccc","kkk"+j);
                datalist.add(map);
            }
           datalists.add(datalist);
        }

        if (!datalists.isEmpty()) {
            try {
                List<String> headers = new ArrayList<>();
                headers.add("1111111");
                headers.add("2222222");
                headers.add("3333333");
                String fileName ="mydataexcel";
                ExportExcelUtil.exportDynamicExcel(fileName, Arrays.asList("我的sheet1","我的sheet2"), "head0000", headers, datalists, response,
                        null, true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

五.导出效果测试:

1.PostMan测试:

2.网页测试:

3.导出效果图:

看下导出的效果吧,边框、表头、对齐方式、字体大小、单元格数据换行、时间字符串格式转换等。效果满意的话点个赞吧!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值