【小家java】一个基于POI的Excel导入、导出工具处理类(支持xls,xlsx格式),另有SpringMVC的导入、导出案例讲解

December 17, 2023
测试
测试
测试
测试
41 分钟阅读

每篇一句

学识的渊博不是为了征服别人,而是为了看清自己的渺小。地位的显赫不是为了孤芳自赏,而是为了率众前行。力量的强悍不是为了欺压弱小,而是为了自由的呼吸。一个人有了能量,不是为了满足私欲,而是为了承担更多的使命

前言

表格的导入、导出可谓开发过程中经常会碰到的功能。然后这种模版化的东西并不需要每次都去编码一次,因此我就整理了一个Excel的万能处理类。能够实现兼容2003、2007的各种Excel格式的导入导出功能,使用起来也非常的方面,适用于所有业务场景,下面会有案例讲解

Excel导入、导出工具类源码:
/**
 * 操作Excel的处理器类(含导入和导出功能)
 *
 * @author fangshixiang
 * @description //
 * @date 2018/11/13 21:17
 */
public class ExcelHandler {

    private Workbook workbook;

    /**
     * 构造函数 调用者只需要传入excel的文件流,并告知Excel版本即可(使用得最多)
     *
     * @param is      the is
     * @param version the version
     * @throws IOException the io exception
     */
    public ExcelHandler(InputStream is, WorkbookVersion version) throws IOException {
        if (version == WorkbookVersion.XLS) {
            workbook = new HSSFWorkbook(is);
        } else {
            workbook = new XSSFWorkbook(is);
        }
    }

    /**
     * 需要导出的时候 调用这个构造函数  可以创建一个Excel文件 并且调用对应的方法
     *
     * @param version
     */
    public ExcelHandler(WorkbookVersion version) {
        if (version == WorkbookVersion.XLS) {
            workbook = new HSSFWorkbook();
        } else {
            workbook = new XSSFWorkbook();
        }
    }

    /**
     * 也支持调用者外部解析 然后把workbook直接传给我就行
     * <p>
     * 一般用于导出,外部建立好传进来就成
     *
     * @param workboook the workboook
     */
    public ExcelHandler(Workbook workboook) {
        this.workbook = workboook;
    }

    /**
     * excel的版本
     */
    public enum WorkbookVersion {
        XLS, XLSX
    }

    /**
     * 行类型  是否是表头
     */
    public enum RowType {
        HEADER, NORMER
    }

    //////////////////////////静态方法 start//////////////////////////

    /**
     * 根据后缀判断是否为 Excel 文件,后缀匹配xls和xlsx
     *
     * @param pathName the pathName
     * @return boolean boolean
     */
    public static boolean isExcel(String pathName) {
        if (pathName == null) {
            return false;
        }
        //return pathName.endsWith(".xls") || pathName.endsWith(".xlsx");
        return getExcelVersion(pathName) != null;
    }

    /**
     * 获取该文件的Excel版本
     *
     * @param pathName the path name
     * @return the excel version
     */
    public static WorkbookVersion getExcelVersion(String pathName) {
        if (isExcel2003(pathName)) {
            return WorkbookVersion.XLS;
        } else if (isExcel2007(pathName)) {
            return WorkbookVersion.XLSX;
        } else {
            return null;
        }
    }

    /**
     * 是否是xls格式的Excel文件
     *
     * @param pathName the file path
     * @return the boolean
     */
    public static boolean isExcel2003(String pathName) {
        return pathName.matches("^.+\\.(?i)(xls)$");
    }

    /**
     * 是否是xlsx格式的Excel文件
     *
     * @param pathName the file path
     * @return the boolean
     */
    public static boolean isExcel2007(String pathName) {
        return pathName.matches("^.+\\.(?i)(xlsx)$");
    }

    //////////////////////////静态方法 end//////////////////////////

    /**
     * 读取 Excel 第一页所有数据(第一个sheet,一般导入都只有一个sheet,所以这个最常用)
     *
     * @return list list
     */
    public List<List<String>> read() {
        return read(0, 0, getRowCount(0) - 1);
    }

    /**
     * 读取指定sheet 页所有数据
     *
     * @param sheetIx 指定 sheet 页,从 0 开始
     * @return list list
     */
    public List<List<String>> read(int sheetIx) {
        return read(sheetIx, 0, getRowCount(sheetIx) - 1);
    }

    /**
     * 读取指定sheet 页指定行数据
     *
     * @param sheetIx 指定 sheet 页,从 0 开始
     * @param start   指定开始行,从 0 开始
     * @param end     指定结束行,从 0 开始
     * @return list list
     */
    public List<List<String>> read(int sheetIx, int start, int end) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        List<List<String>> list = new ArrayList<>();

        if (end > getRowCount(sheetIx)) {
            end = getRowCount(sheetIx);
        }

        //int cols = sheet.getRow(0).getLastCellNum(); // 第一行总列数(第一行总列数决定了列的总数)

        //兼容操作:防止第一列没填,所以最多往下找10列 再没有就报错吧  找到就当作表头
        int cols = 0;
        //优化 为了表面有的人可能第一列空着 所以此处改为找第一个不为null的行为止(遍历10行吧)
        for (int i = 0; i < 10; i++) {
            Row row = sheet.getRow(i);
            if (row != null) {
                cols = row.getLastCellNum();
                break;
            }
        }
        if (cols == 0) {
            throw new RuntimeException("请把表格的前10行填充数据(表头)~");
        }

        for (int i = start; i <= end; i++) {
            List<String> rowList = new ArrayList<>();
            Row row = sheet.getRow(i);
            for (int j = 0; j < cols; j++) {
                if (row == null) {
                    rowList.add(null);
                    continue;
                }
                rowList.add(getCellValueToString(row.getCell(j)));
            }
            list.add(rowList);
        }

        return list;
    }

    /**
     * 将数据写入到 Excel 默认第一页中,从第1行开始写入(导出可以使用)
     *
     * @param rowData 数据
     * @return boolean boolean
     */
    public boolean write(List<List<String>> rowData) {
        return write(0, rowData, 0);
    }

    /**
     * 将数据写入到 Excel 新创建的 Sheet 页(导出)
     *
     * @param rowData    数据
     * @param sheetName  长度为1-31,不能包含后面任一字符: :\ / ? * [ ]
     * @param isNewSheet the is new sheet
     * @return boolean boolean
     * @throws IOException the io exception
     */
    public boolean write(List<List<String>> rowData, String sheetName, boolean isNewSheet) {
        Sheet sheet = null;
        if (isNewSheet) {
            sheet = workbook.createSheet(sheetName);
        } else {
            sheet = workbook.createSheet();
        }
        int sheetIx = workbook.getSheetIndex(sheet);
        return write(sheetIx, rowData, 0);
    }

    /**
     * 将数据追加到sheet页最后
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowData  数据
     * @param isAppend 是否追加,true 追加,false 重置sheet再添加
     * @return boolean boolean
     */
    public boolean write(int sheetIx, List<List<String>> rowData, boolean isAppend) {
        if (isAppend) {
            return write(sheetIx, rowData, getRowCount(sheetIx));
        } else { // 清空再添加
            clearSheet(sheetIx);
            return write(sheetIx, rowData, 0);
        }
    }

    /**
     * 把该workBook写进resp,提供下载的请求头
     * <p>
     * 提示浏览器下载此文件
     *
     * @param response resp
     * @param fileName excel文件的名字
     * @return boolean
     */
    public boolean flushIntoResponseForDownload(HttpServletResponse response, String fileName) {
        fileName = fileName == null ? "test.xlsx" : fileName;
        try {
            response.setContentType("application/vnd.ms-excel");
            //response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8"));
            OutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return true;
    }

    /**
     * 将数据写入到 Excel 指定 Sheet 页指定开始行中,指定行后面数据向后移动
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowData  数据
     * @param startRow 指定开始行,从 0 开始
     * @return boolean boolean
     */
    public boolean write(int sheetIx, List<List<String>> rowData, int startRow) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        int dataSize = rowData.size();
        if (getRowCount(sheetIx) > 0) { // 如果小于等于0,则一行都不存在
            sheet.shiftRows(startRow, getRowCount(sheetIx), dataSize);
        }
        for (int i = 0; i < dataSize; i++) {
            Row row = sheet.createRow(i + startRow);
            for (int j = 0; j < rowData.get(i).size(); j++) {
                Cell cell = row.createCell(j);
                cell.setCellValue(rowData.get(i).get(j) + "");
            }
        }
        return true;
    }

    ///////////////////////////下为设置Excel的样式...////////////////////////////

    /**
     * 给一行设置样式(每个单元格都一样)
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex the row index
     * @param style    the style
     * @return boolean
     */
    public boolean setRowStyle(int sheetIx, int rowIndex, CellStyle style) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        Row row = sheet.getRow(rowIndex);
        int columnCount = row.getLastCellNum();
        for (int i = 0; i < columnCount; i++) {
            sheet.autoSizeColumn(i, true);// 设置列宽度自适应
            sheet.setColumnWidth(i, 4000);

            //拿到这个cell 设置一样的样式
            Cell cell = row.getCell(i);
            cell.setCellStyle(style);
        }
        return true;
    }

    /**
     * 设置cell 样式
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex the row index
     * @param colIndex 指定列,从 0 开始
     * @param style    the style
     * @return style style
     */
    public boolean setCellStyle(int sheetIx, int rowIndex, int colIndex, CellStyle style) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        // sheet.autoSizeColumn(colIndex, true);// 设置列宽度自适应
        sheet.setColumnWidth(colIndex, 4000);

        Cell cell = sheet.getRow(rowIndex).getCell(colIndex);
        cell.setCellStyle(style);

        return true;
    }

    /**
     * 建立一个样式(比如给标题给出内置特殊样式 type就传1即可)
     *
     * @param rowType 参考枚举@RowType
     * @return cell style
     */
    public CellStyle makeStyle(RowType rowType) {
        CellStyle style = workbook.createCellStyle();
        //内容居中
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);

        //针对时间格式 进行特殊处理一下
        DataFormat format = workbook.createDataFormat();
        style.setDataFormat(format.getFormat("@")); // // 内容样式 设置单元格内容格式是文本

        //设置边框样式
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);

        // 文字样式
        Font font = workbook.createFont();
        if (rowType == RowType.HEADER) {
            //颜色样式
            style.setFillForegroundColor(HSSFColor.HSSFColorPredefined.YELLOW.getIndex()); //前景颜色
            style.setFillBackgroundColor(HSSFColor.HSSFColorPredefined.YELLOW.getIndex());//背景色
            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);// 填充方式
            font.setBold(true); //标题文字加粗
            font.setFontHeight((short) 300);
            font.setColor(HSSFColor.HSSFColorPredefined.BROWN.getIndex());
        } else if (rowType == RowType.NORMER) {
            font.setFontHeight((short) 150);
        }
        style.setFont(font);
        return style;
    }

    /**
     * 合并单元格(这个功能很高级)
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param firstRow 开始行
     * @param lastRow  结束行
     * @param firstCol 开始列
     * @param lastCol  结束列
     */
    public void region(int sheetIx, int firstRow, int lastRow, int firstCol, int lastCol) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol));
    }

    /**
     * 指定行是否为空
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex 指定开始行,从 0 开始
     * @return true 不为空,false 不行为空
     */
    public boolean isRowNull(int sheetIx, int rowIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        return sheet.getRow(rowIndex) == null;
    }

    /**
     * 创建行,若行存在,则清空
     *
     * @param sheetIx  指定 sheet 页,从 0 开始
     * @param rowIndex the row index
     * @return boolean boolean
     */
    public boolean createRow(int sheetIx, int rowIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        sheet.createRow(rowIndex);
        return true;
    }

    /**
     * 指定单元格是否为空
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex 指定开始行,从 0 开始
     * @param colIndex 指定开始列,从 0 开始
     * @return true 行不为空,false 行为空
     */
    public boolean isCellNull(int sheetIx, int rowIndex, int colIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        if (!isRowNull(sheetIx, rowIndex)) {
            return false;
        }
        Row row = sheet.getRow(rowIndex);
        return row.getCell(colIndex) == null;
    }

    /**
     * 创建单元格
     *
     * @param sheetIx  指定 sheet 页,从 0 开始
     * @param rowIndex 指定行,从 0 开始
     * @param colIndex 指定创建列,从 0 开始
     * @return true 列为空,false 行不为空
     */
    public boolean createCell(int sheetIx, int rowIndex, int colIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        Row row = sheet.getRow(rowIndex);
        row.createCell(colIndex);
        return true;
    }

    /**
     * 返回sheet 中的行数
     *
     * @param sheetIx 指定 Sheet 页,从 0 开始
     * @return row count
     */
    public int getRowCount(int sheetIx) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        if (sheet.getPhysicalNumberOfRows() == 0) {
            return 0;
        }
        return sheet.getLastRowNum() + 1;

    }

    /**
     * 返回所在行的列数
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex 指定行,从0开始
     * @return 返回 -1 表示所在行为空
     */
    public int getColumnCount(int sheetIx, int rowIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        Row row = sheet.getRow(rowIndex);
        return row == null ? -1 : row.getLastCellNum();

    }

    /**
     * 设置row 和 column 位置的单元格值
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex 指定行,从0开始
     * @param colIndex 指定列,从0开始
     * @param value    值
     * @return value at
     */
    public boolean setValueAt(int sheetIx, int rowIndex, int colIndex, String value) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        sheet.getRow(rowIndex).getCell(colIndex).setCellValue(value);
        return true;
    }

    /**
     * 返回 row 和 column 位置的单元格值
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex 指定行,从0开始
     * @param colIndex 指定列,从0开始
     * @return value at
     */
    public String getValueAt(int sheetIx, int rowIndex, int colIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        return getCellValueToString(sheet.getRow(rowIndex).getCell(colIndex));
    }

    /**
     * 重置指定行的值
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowData  数据
     * @param rowIndex 指定行,从0开始
     * @return row value
     */
    public boolean setRowValue(int sheetIx, List<String> rowData, int rowIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        Row row = sheet.getRow(rowIndex);
        for (int i = 0; i < rowData.size(); i++) {
            row.getCell(i).setCellValue(rowData.get(i));
        }
        return true;
    }

    /**
     * 返回指定行的值的集合
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex 指定行,从0开始
     * @return row value
     */
    public List<String> getRowValue(int sheetIx, int rowIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        Row row = sheet.getRow(rowIndex);
        List<String> list = new ArrayList<>();
        if (row == null) {
            list.add(null);
        } else {
            for (int i = 0; i < row.getLastCellNum(); i++) {
                list.add(getCellValueToString(row.getCell(i)));
            }
        }
        return list;
    }

    /**
     * 返回列的值的集合
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex 指定行,从0开始
     * @param colIndex 指定列,从0开始
     * @return column value
     */
    public List<String> getColumnValue(int sheetIx, int rowIndex, int colIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        List<String> list = new ArrayList<>();
        for (int i = rowIndex; i < getRowCount(sheetIx); i++) {
            Row row = sheet.getRow(i);
            if (row == null) {
                list.add(null);
                continue;
            }
            list.add(getCellValueToString(sheet.getRow(i).getCell(colIndex)));
        }
        return list;
    }

    /**
     * 获取excel 中sheet 总页数
     *
     * @return sheet count
     */
    public int getSheetCount() {
        return workbook.getNumberOfSheets();
    }

    /**
     * 创建一个sheet
     */
    public void createSheet() {
        workbook.createSheet();
    }

    /**
     * 设置sheet名称,长度为1-31,不能包含后面任一字符: :\ / ? * [ ]
     *
     * @param sheetIx 指定 Sheet 页,从 0 开始,//
     * @param name    the name
     * @return sheet name
     */
    public boolean setSheetName(int sheetIx, String name) {
        workbook.setSheetName(sheetIx, name);
        return true;
    }

    /**
     * 获取 sheet名称
     *
     * @param sheetIx 指定 Sheet 页,从 0 开始
     * @return sheet name
     */
    public String getSheetName(int sheetIx) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        return sheet.getSheetName();
    }

    /**
     * 获取sheet的索引,从0开始
     *
     * @param name sheet 名称
     * @return -1表示该未找到名称对应的sheet
     */
    public int getSheetIndex(String name) {
        return workbook.getSheetIndex(name);
    }

    /**
     * 删除指定sheet
     *
     * @param sheetIx 指定 Sheet 页,从 0 开始
     * @return boolean boolean
     */
    public boolean removeSheetAt(int sheetIx) {
        workbook.removeSheetAt(sheetIx);
        return true;
    }

    /**
     * 删除指定sheet中行,改变该行之后行的索引
     *
     * @param sheetIx  指定 Sheet 页,从 0 开始
     * @param rowIndex 指定行,从0开始
     * @return boolean boolean
     */
    public boolean removeRow(int sheetIx, int rowIndex) {
        Sheet sheet = workbook.getSheetAt(sheetIx);
        sheet.shiftRows(rowIndex + 1, getRowCount(sheetIx), -1);
        Row row = sheet.getRow(getRowCount(sheetIx) - 1);
        sheet.removeRow(row);
        return true;
    }

    /**
     * 设置sheet 页的索引
     *
     * @param sheetname Sheet 名称
     * @param sheetIx   the sheet ix
     */
    public void setSheetOrder(String sheetname, int sheetIx) {
        workbook.setSheetOrder(sheetname, sheetIx);
    }

    /**
     * 清空指定sheet页(先删除后添加并指定sheetIx)
     *
     * @param sheetIx 指定 Sheet 页,从 0 开始
     * @return boolean boolean
     */
    public boolean clearSheet(int sheetIx) {
        String sheetname = getSheetName(sheetIx);
        removeSheetAt(sheetIx);
        workbook.createSheet(sheetname);
        setSheetOrder(sheetname, sheetIx);
        return true;
    }

    /**
     * 对外提供关闭流的方法(使用完后记得关流)
     */
    public void close() {
        try {
            workbook.close();
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("关流失败~", e);
        }
    }

    /**
     * 转换单元格的类型为String 默认的 <br>
     * 默认的数据类型:CELL_TYPE_BLANK(3), CELL_TYPE_BOOLEAN(4),
     * CELL_TYPE_ERROR(5),CELL_TYPE_FORMULA(2), CELL_TYPE_NUMERIC(0),
     * CELL_TYPE_STRING(1)
     *
     * @param cell the cell
     * @return cell value to string
     */
    private String getCellValueToString(Cell cell) {
        String strCell = "";
        if (cell == null) {
            return null;
        }
        switch (cell.getCellType()) {
            case Cell.CELL_TYPE_BOOLEAN:
                strCell = String.valueOf(cell.getBooleanCellValue());
                break;
            case Cell.CELL_TYPE_NUMERIC:
                // 如果数字过长且不是日期格式,则防止当数字过长时以科学计数法显示
                cell.setCellType(HSSFCell.CELL_TYPE_STRING);
                strCell = cell.toString();
                break;
            case Cell.CELL_TYPE_STRING:
                strCell = cell.getStringCellValue();
                break;
            default:
                break;
        }
        return strCell;
    }

    @Override
    public String toString() {
        return "共有 " + getSheetCount() + "个sheet 页!";
    }

    /**
     * 可以把指定的sheet等toString输出
     *
     * @param sheetIx the sheet ix
     * @return the string
     */
    public String toString(int sheetIx) {
        return "第 " + (sheetIx + 1) + "个sheet 页,名称: " + getSheetName(sheetIx) + ",共 " + getRowCount(sheetIx) + "行!";
    }

    /**
     * 把Workbook可以提供给外部访问
     *
     * @return Workbook
     */
    public Workbook getWorkbook() {
        return workbook;
    }

}

依赖的jar为:

<!-- POI -->
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi</artifactId>
            <version>3.17</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.poi/poi-ooxml -->
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>3.17</version>
        </dependency>
为何不使用POI4.0?

2018年09月 Apache POI 4.0.0 发布了。此版本特点是一些新功能和众多 bug 修复

  • 删除了对 Java 6 和 7 的支持,使 Java 8 成为支持的最低版本
  • 需要新的 OOXML schema(1.4),因为不兼容的 XMLBeans 加载不再通过 POIXMLTypeLoader

按照惯例,这种大版本出来之后,都会很快的出几个修复版本,所以等一段时间再更新吧(要是大家都这么想,都不更新,发现不了bug,那就尴尬了?)

注意: POI4.0版本,向下不兼容,类都有变化。 POI4.0版本,向下不兼容,类都有变化。 POI4.0版本,向下不兼容,类都有变化。

HSSFWorkbook:是操作Excel2003以前(包括2003)的版本,扩展名是.xls XSSFWorkbook:是操作Excel2007的版本,扩展名是.xlsx

使用案例

导入Excel(建议POST请求,可以有JSON返回值):

    @ApiOperation("测试导入")
    @PostMapping("/{id}/import")
    Object testImport(@PathVariable Integer id,
                      @RequestParam MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        if (!ExcelHandler.isExcel(fileName)) {
            throw new RuntimeException("导入只支持Excel表格~");
        }

        InputStream is = file.getInputStream();
        //把流交给Excel工具类进行解析
        ExcelHandler excelHandler = new ExcelHandler(is, ExcelHandler.getExcelVersion(fileName));
        //excel表格数据  解析成了List的数据结构 非常友好了
        List<List<String>> read = excelHandler.read();
        //关流
        excelHandler.close();
        return read;
    }

结果如下:

在这里插入图片描述
在这里插入图片描述

导出Excel(get请求,并且有对应的响应头,需要注意):

    @ApiOperation("测试导出")
    @GetMapping("/{id}/export")
    void testExport(@PathVariable Integer id,
                    HttpServletResponse response) {
        List<List<String>> data = new ArrayList<>();
        data.add(new ArrayList<String>() {{
            add("fang");
            add("shi");
            add("xiang");
        }});
        data.add(new ArrayList<String>() {{
            add("fang22");
            add("shi22");
            add("xiang22");
        }});

        ExcelHandler excelHandler = new ExcelHandler(ExcelHandler.WorkbookVersion.XLSX);
        //给创建一个sheet 并且吧数据写进去  创建一个新的sheet
        excelHandler.write(data, "sheet名称", true);
        //定制一些样式  一般只需要维护表头即可
        excelHandler.setRowStyle(0, 0, excelHandler.makeStyle(ExcelHandler.RowType.HEADER));
        //写入数据后 把数据再写到response即可实现导出了
        excelHandler.flushIntoResponseForDownload(response, "测试导出.xlsx");
        //关流
        excelHandler.close();
    }

Excel正常导出如下:

在这里插入图片描述
在这里插入图片描述

Tips(需要注意的是): 响应头为:

Content-Disposition: attachment;filename=%E6%B5%8B%E8%AF%95%E5%AF%BC%E5%87%BA.xlsx
Content-Type: application/vnd.ms-excel
Date: Wed, 14 Nov 2018 07:09:05 GMT
Transfer-Encoding: chunked

显然不再是application/json了。所以需要注意:如果你在控制台发现了这种异常(但不会影响导出Excel):

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation
	at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:306) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:180) ~[spring-webmvc-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:82) ~[spring-web-5.1.2.RELEASE.jar:5.1.2.RELEASE]
	,,,

原因就是你的MVC方法是@ResponseBody返回的,解析器使用不当导致。处理办法为:

  1. 返回值改为void(推荐)
  2. 去掉 produces = "text/html; charset=UTF-8"这段代码或者设置produces=application/json;charset=UTF-8
最后

此工具方法使用起来非常方便,与业务无关,希望能帮助到大家

继续阅读

更多来自我们博客的帖子

如何安装 BuddyPress
由 测试 December 17, 2023
经过差不多一年的开发,BuddyPress 这个基于 WordPress Mu 的 SNS 插件正式版终于发布了。BuddyPress...
阅读更多
Filter如何工作
由 测试 December 17, 2023
在 web.xml...
阅读更多
如何理解CGAffineTransform
由 测试 December 17, 2023
CGAffineTransform A structure for holding an affine transformation matrix. ...
阅读更多