SpringBoot基于easyPoi框架的导出excel工具,用了之后,感觉easy-excel不香了

本文基于easyPoi框架封装了Excel导出工具类,介绍了使用到的技术框架及相关源码。展示了不同参数的导出方法效果,还针对导入导出时的字典码转换、数字列处理等问题给出解决方案,提供了锁定列、校验数字等方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于easyPoi框架导出excel工具类

使用到的技术框架
  1. SpringBoot、
  2. easyPoi

相信大家平时业务上肯定都会遇到将表单数据导出excel的情况,这个工具主要是在easyPoi框架的基础上封装了一个工具类,并加上了一些使用的操作表格的方法,可以方便的导出excel。

这里的方法,只是用于导出格式较为简单地excel文件,复杂格式的还是要手写poi,一个单元格的写。

看源码:

ExcelUtil.java
/**
 * Excel工具方法
 *
 * @author: 一位大帅哥(a very handsome man)
 * @date: 2023/2/21:10:30
 * @description: TODO
 */
@Slf4j
public class ExcelUtil {


    /**
     * 设置Excel工作表中某个单元格的值
     *
     * @param workbook  excel文件
     * @param sheetNum  工作表号
     * @param rowNum    行号
     * @param cellNum   列号
     * @param cellValue 单元格的值
     */
    public static void setCellValue(Workbook workbook,
                                    int sheetNum,
                                    int rowNum,
                                    int cellNum,
                                    Object cellValue) {

        // 获取sheet
        Sheet sheet = workbook.getSheetAt(sheetNum);
        // 获取工作表中的某一行
        Row row = sheet.getRow(rowNum);
        // 在这行创建单元格
        Cell cell = row.getCell(cellNum);
        // 创建一个格式
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setDataFormat((short) BuiltinFormats.getBuiltinFormat("TEXT"));
        // 设置这个单元格的格式
        cell.setCellStyle(cellStyle);

        // 如果单元格的值是字符串
        if (cellValue instanceof String) {
            cell.setCellValue((String) cellValue);

            // 如果单元格的值是数字double
        } else if (cellValue instanceof Double) {
            cell.setCellValue((Double) cellValue);

            // 如果单元格的值是数字日期
        } else if (cellValue instanceof Date) {
            cell.setCellValue((Date) cellValue);

            // 如果单元格的值是富文本
        } else if (cellValue instanceof RichTextString) {
            cell.setCellValue((RichTextString) cellValue);
        }
    }

    /**
     * XSSF
     * excel添加下拉数据校验
     *
     * @param workbook   哪个 sheet 页添加校验
     * @param dataSource 数据源数组
     * @param col        第几列校验(0开始)
     */
    public static void createXssfOfSelected(Workbook workbook, String[] dataSource, int col) {
        Sheet sheet = workbook.getSheetAt(0);
        CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 65535, col, col);
        DataValidationHelper helper = sheet.getDataValidationHelper();
        DataValidationConstraint constraint = helper.createExplicitListConstraint(dataSource);
        DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
        //处理Excel兼容性问题
        if (dataValidation instanceof XSSFDataValidation) {
            dataValidation.setSuppressDropDownArrow(true);
            dataValidation.setShowErrorBox(true);
        } else {
            dataValidation.setSuppressDropDownArrow(false);
        }
        dataValidation.setEmptyCellAllowed(true);
        dataValidation.setShowPromptBox(true);
        dataValidation.createPromptBox("提示", "只能选择下拉框里面的数据!");
        sheet.addValidationData(dataValidation);
    }

    /**
     * 为excel文件某一列设置数字,小数整数都可以校验
     *
     * @param workbook 文件
     * @param startCol 第几列校验(0开始)
     * @param endCol   第几列校验(0开始)
     */
    public static void createXssfOfDecimal(Workbook workbook, int startCol, int endCol) {

        Sheet sheet = workbook.getSheetAt(0);
        CellRangeAddressList cell = new CellRangeAddressList(1, 65535, startCol, endCol);
        DataValidationHelper helper = sheet.getDataValidationHelper();
        // 创建一个大于等于0的数值约束
        DataValidationConstraint constraint = helper.createDecimalConstraint(DataValidationConstraint.OperatorType.GREATER_OR_EQUAL, "0.0", null);
        DataValidation validation = helper.createValidation(constraint, cell);
        //处理Excel兼容性问题
        if (validation instanceof XSSFDataValidation) {
            validation.setSuppressDropDownArrow(true);
            validation.setShowErrorBox(true);
        } else {
            validation.setSuppressDropDownArrow(false);
        }
        // 允许空值
        validation.setEmptyCellAllowed(true);
        validation.setShowErrorBox(true);
        validation.createErrorBox("提示", "该列只能是纯数字或小数!");
        sheet.addValidationData(validation);
    }

    /**
     * 为excel文件某一列设置数字整数校验
     *
     * @param workbook 文件
     * @param startCol 第几列校验(0开始)
     * @param endCol   第几列校验(0开始)
     */
    public static void createXssfOfInteger(Workbook workbook, int startCol, int endCol) {

        Sheet sheet = workbook.getSheetAt(0);
        CellRangeAddressList cell = new CellRangeAddressList(1, 65535, startCol, endCol);
        DataValidationHelper helper = sheet.getDataValidationHelper();
        // 创建一个大于等于0的数值约束
        DataValidationConstraint constraint = helper.createIntegerConstraint(DataValidationConstraint.OperatorType.GREATER_OR_EQUAL, "0", null);
        DataValidation validation = helper.createValidation(constraint, cell);
        //处理Excel兼容性问题
        if (validation instanceof XSSFDataValidation) {
            validation.setSuppressDropDownArrow(true);
            validation.setShowErrorBox(true);
        } else {
            validation.setSuppressDropDownArrow(false);
        }
        // 允许空值
        validation.setEmptyCellAllowed(true);
        validation.setShowErrorBox(true);
        validation.createErrorBox("提示", "该列只能是纯数字且不可为小数和负数!");
        sheet.addValidationData(validation);
    }

    /**
     * 获取Workbook。
     * 带序号, 默认ExcelExportMyStyler格式
     *
     * @param exportClass 要导出的类
     * @param exportList  要导出类集合
     * @param response    响应流
     */
    public static Workbook getWorkbook(Class exportClass,
                                       Collection exportList,
                                       HttpServletResponse response) throws UnsupportedEncodingException {

        ExportParams params = new ExportParams();
        params.setAddIndex(true);
        params.setStyle(ExcelExportMyStyler.class);
        FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
        log.info("获取Workbook");
        return CustomExcelExportUtils.exportExcel(params, exportClass, exportList);

    }

    /**
     * 获取Workbook。
     * 带序号, 默认ExcelExportMyStyler格式
     *
     * @param exportClass 要导出的类
     * @param exportList  要导出类集合
     * @param sheetName   工作表名称
     * @param response    响应流
     */
    public static Workbook getWorkbook(Class exportClass,
                                       Collection exportList,
                                       String sheetName,
                                       HttpServletResponse response) throws UnsupportedEncodingException {

        ExportParams params = new ExportParams();
        params.setAddIndex(true);
        params.setStyle(ExcelExportMyStyler.class);
        params.setSheetName(sheetName);
        FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
        log.info("获取Workbook");
        return CustomExcelExportUtils.exportExcel(params, exportClass, exportList);

    }

    /**
     * 获取Workbook。
     * 不带序号, 默认ExcelExportMyStyler格式
     *
     * @param exportClass 要导出的类
     * @param exportList  要导出类集合
     * @param response    响应流
     */
    public static Workbook getWorkbookNoNum(Class exportClass,
                                            Collection exportList,
                                            HttpServletResponse response) throws UnsupportedEncodingException {

        ExportParams params = new ExportParams();
        // params.setAddIndex(true);
        params.setStyle(ExcelExportMyStyler.class);
        FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
        log.info("获取Workbook");
        return CustomExcelExportUtils.exportExcel(params, exportClass, exportList);

    }

    /**
     * 获取Workbook。
     * 不带序号, 默认ExcelExportMyStyler格式
     *
     * @param exportClass 要导出的类
     * @param exportList  要导出类集合
     * @param sheetName   工作表名称
     * @param response    响应流
     */
    public static Workbook getWorkbookNoNum(Class exportClass,
                                            Collection exportList,
                                            String sheetName,
                                            HttpServletResponse response) throws UnsupportedEncodingException {

        ExportParams params = new ExportParams();
        // params.setAddIndex(true);
        params.setStyle(ExcelExportMyStyler.class);
        params.setSheetName(sheetName);
        FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
        log.info("获取Workbook");
        return CustomExcelExportUtils.exportExcel(params, exportClass, exportList);

    }


    /**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     *
     * @param exportClass 要导出的类
     * @param exportList  要导出类集合
     * @param response    响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        try {
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            outputStream = response.getOutputStream();
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            CustomExcelExportUtils.exportExcel(params, exportClass, exportList).write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用方法导出!");
        } catch (Exception e) {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

    /**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     *
     * @param exportClass 要导出的类
     * @param exportList  要导出类集合
     * @param sheetName   导出工作表名
     * @param titleName   标题名称
     * @param response    响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          String sheetName,
                                          String titleName,
                                          HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        try {
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            params.setSheetName(sheetName);
            params.setTitle(titleName);
            outputStream = response.getOutputStream();
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            CustomExcelExportUtils.exportExcel(params, exportClass, exportList).write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用方法导出!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

    /**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     * 支持校验某一列数据
     *
     * @param exportClass     要导出的类
     * @param exportList      要导出类集合
     * @param checkColumnData 校验列选择框提示内容
     * @param col             第几列校验
     * @param response        响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          String[] checkColumnData,
                                          int col,
                                          HttpServletResponse response) {

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            Workbook workbook = CustomExcelExportUtils.exportExcel(params, exportClass, exportList);
            createXssfOfSelected(workbook, checkColumnData, col);
            workbook.write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用方法导出!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

    /**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     * 支持校验某一列数据
     *
     * @param exportClass     要导出的类
     * @param exportList      要导出类集合
     * @param checkColumnData 校验列选择框提示内容
     * @param col             第几列校验
     * @param sheetName       导出文件的工作表名称
     * @param response        响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          String[] checkColumnData,
                                          int col,
                                          String sheetName,
                                          HttpServletResponse response) {

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            params.setSheetName(sheetName);
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            Workbook workbook = CustomExcelExportUtils.exportExcel(params, exportClass, exportList);
            createXssfOfSelected(workbook, checkColumnData, col);
            workbook.write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用导出方法!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

    /**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     * 支持校验多列数据
     * for example
     * {
     * 如果需要导出的数据校验第三列和第八列
     * 则:
     * checkColumnData: {
     * 3,["提示数据1","提示数据2","提示数据3",...],
     * 8,["提示数据1","提示数据2","提示数据3",...]
     * }
     * col: [3,8]
     * }
     *
     * @param exportClass     要导出的类
     * @param exportList      要导出类集合
     * @param checkColumnData 校验列选择框提示内容 , 可多个
     * @param col             需要校验的列 , 可多个
     * @param response        响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          Map<Integer, String[]> checkColumnData,
                                          Integer[] col,
                                          HttpServletResponse response) {

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            Workbook workbook = CustomExcelExportUtils.exportExcel(params, exportClass, exportList);
            for (Integer columnNumber : col) {
                createXssfOfSelected(workbook, checkColumnData.get(columnNumber), columnNumber);
            }
            workbook.write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用导出方法!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

    /**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     * 支持校验多列数据
     * for example
     * {
     * 如果需要导出的数据校验第三列和第八列
     * 则:
     * checkColumnData: {
     * 3,["提示数据1","提示数据2","提示数据3",...],
     * 8,["提示数据1","提示数据2","提示数据3",...]
     * }
     * col: [3,8]
     * }
     *
     * @param exportClass     要导出的类
     * @param exportList      要导出类集合
     * @param checkColumnData 校验列选择框提示内容 , 可多个
     * @param col             需要校验的列 , 可多个
     * @param sheetName       工作表名称
     * @param response        响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          Map<Integer, String[]> checkColumnData,
                                          Integer[] col,
                                          String sheetName,
                                          HttpServletResponse response) {

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            params.setSheetName(sheetName);
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            Workbook workbook = CustomExcelExportUtils.exportExcel(params, exportClass, exportList);
            for (Integer columnNumber : col) {
                createXssfOfSelected(workbook, checkColumnData.get(columnNumber), columnNumber);
            }
            workbook.write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用导出方法!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }
}
CustomExcelExportUtils.java

主要用来实现导出自动带序号列

/**
 * 自定义Excel导出工具类, 带序号列
 *
 * @author: a very handsome man
 * @date: 2022-10-25  09:55
 * @description: TODO
 */
public class CustomExcelExportUtils {

    public static Workbook exportExcel(ExportParams entity, List entityList, Collection dataSet) {
        Workbook workbook = getWorkbook(entity.getType(), dataSet.size());
        new CustomExcelExportService().createSheetForMap(workbook, entity, entityList, dataSet);
        return workbook;
    }

    public static Workbook exportExcel(ExportParams entity, Class pojoClass, Collection dataSet) {
        Workbook workbook = getWorkbook(entity.getType(), dataSet.size());
        new CustomExcelExportService().createSheet(workbook, entity, pojoClass, dataSet);
        return workbook;
    }

    private static Workbook getWorkbook(ExcelType type, int size) {
        if (ExcelType.HSSF.equals(type)) {
            return new HSSFWorkbook();
        } else if (size < 100000) {
            return new XSSFWorkbook();
        } else {
            return new SXSSFWorkbook();
        }
    }

    public static void exportExcel(HttpServletResponse response, Workbook workbook) throws Exception {
        response.reset();
        response.setContentType("application/vnd.ms-excel");
        String fileName = System.currentTimeMillis() + ".xlsx";
        response.setHeader("Content-disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
        response.setCharacterEncoding("UTF-8");
        OutputStream output = response.getOutputStream();
        workbook.write(output);
        workbook.close();
        output.close();
    }
}
CustomExcelExportService.java

主要用来实现导出自动带序号列

/**
 * 导出excel Service
 * @author: a very handsome man
 * @date: 2022-10-25  09:57
 * @description: TODO
 */
public class CustomExcelExportService extends ExcelExportService {


    private static int MAX_NUM = 60000;

    @Override
    protected void insertDataToSheet(Workbook workbook, ExportParams entity, List<ExcelExportEntity> entityList, Collection<?> dataSet, Sheet sheet) {
        try {
            dataHandler = entity.getDataHandler();
            if (dataHandler != null && dataHandler.getNeedHandlerFields() != null) {
                needHandlerList = Arrays.asList(dataHandler.getNeedHandlerFields());
            }
            dictHandler = entity.getDictHandler();
            i18nHandler = entity.getI18nHandler();
            // 创建表格样式
            setExcelExportStyler((IExcelExportStyler) entity.getStyle().getConstructor(Workbook.class).newInstance(workbook));
            Drawing patriarch = PoiExcelGraphDataUtil.getDrawingPatriarch(sheet);
            List excelParams = new ArrayList();
            if (entity.isAddIndex()) {
                excelParams.add(indexExcelEntity(entity));
            }
            excelParams.addAll(entityList);
            int index = entity.isCreateHeadRows() ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0;
            int titleHeight = index;
            setCellWith(excelParams, sheet);
            setColumnHidden(excelParams, sheet);
            short rowHeight = entity.getHeight() != 0 ? entity.getHeight() : getRowHeight(excelParams);
            setCurrentIndex(1);
            Iterator its = dataSet.iterator();
            List tempList = new ArrayList();
            while (its.hasNext()) {
                Object t = its.next();
                index += createCells(patriarch, index, t, excelParams, sheet, workbook, rowHeight, 0)[0];
                tempList.add(t);
                if (index >= MAX_NUM) {
                    break;
                }
            }
            if (entity.getFreezeCol() != 0) {
                sheet.createFreezePane(entity.getFreezeCol(), 0, entity.getFreezeCol(), 0);
            }

            mergeCells(sheet, excelParams, titleHeight);

            its = dataSet.iterator();
            for (int i = 0, le = tempList.size(); i < le; i++) {
                its.next();
                its.remove();
            }
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("List data more than max ,data size is {}", dataSet.size());
            }
            // 发现还有剩余list 继续循环创建Sheet
            if (dataSet.size() > 0) {
                createSheetForMap(workbook, entity, entityList, dataSet);
            } else {
                // 创建合计信息
                addStatisticsRow(getExcelExportStyler().getStyles(true, null), sheet);
            }

        } catch (Exception e) {
            LOGGER.error(e.getMessage(), e);
            try {
                dataHandler = entity.getDataHandler();
                if (dataHandler != null && dataHandler.getNeedHandlerFields() != null) {
                    needHandlerList = Arrays.asList(dataHandler.getNeedHandlerFields());
                }
                dictHandler = entity.getDictHandler();
                i18nHandler = entity.getI18nHandler();
                // 创建表格样式
                setExcelExportStyler((IExcelExportStyler) entity.getStyle().getConstructor(Workbook.class).newInstance(workbook));
                Drawing patriarch = PoiExcelGraphDataUtil.getDrawingPatriarch(sheet);
                List excelParams = new ArrayList();
                if (entity.isAddIndex()) {
                    excelParams.add(indexExcelEntity(entity));
                }
                excelParams.addAll(entityList);
                int index = entity.isCreateHeadRows() ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0;
                int titleHeight = index;
                setCellWith(excelParams, sheet);
                setColumnHidden(excelParams, sheet);
                short rowHeight = entity.getHeight() != 0 ? entity.getHeight() : getRowHeight(excelParams);
                setCurrentIndex(1);
                Iterator its = dataSet.iterator();
                List tempList = new ArrayList();
                while (its.hasNext()) {
                    Object t = its.next();
                    index += createCells(patriarch, index, t, excelParams, sheet, workbook, rowHeight, 0)[0];
                    tempList.add(t);
                    if (index >= MAX_NUM) {
                        break;
                    }
                }
                if (entity.getFreezeCol() != 0) {
                    sheet.createFreezePane(entity.getFreezeCol(), 0, entity.getFreezeCol(), 0);
                }

                mergeCells(sheet, excelParams, titleHeight);

                its = dataSet.iterator();
                for (int i = 0, le = tempList.size(); i < le; i++) {
                    its.next();
                    its.remove();
                }
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("List data more than max ,data size is {}", dataSet.size());
                }
                // 发现还有剩余list 继续循环创建Sheet
                if (dataSet.size() > 0) {
                    createSheetForMap(workbook, entity, entityList, dataSet);
                } else {
                    // 创建合计信息
                    addStatisticsRow(getExcelExportStyler().getStyles(true, null), sheet);
                }

            } catch (Exception exception) {
                LOGGER.error(exception.getMessage(), exception);
                throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, exception.getCause());
            }
        }
    }
}
ExcelExportMyStyler.java

excel导出样式类

/**
 * excel导出样式类
 * @author: a very handsome man
 * @date: 2022-12-29  19:41
 * @description: TODO
 */
public class ExcelExportMyStyler extends AbstractExcelExportStyler implements IExcelExportStyler {

    public ExcelExportMyStyler(Workbook workbook) {
        super.createStyles(workbook);
    }

    @Override
    public CellStyle getTitleStyle(short color) {
        return getCellStyle(workbook);
    }

    @SuppressWarnings("deprecation")
    @Override
    public CellStyle stringSeptailStyle(Workbook workbook, boolean isWarp) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setDataFormat(STRING_FORMAT);
        if (isWarp) {
            style.setWrapText(true);
        }
        return style;
    }

    @Override
    public CellStyle getHeaderStyle(short color) {
        CellStyle titleStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setBold(true);// 加粗
        font.setColor(IndexedColors.RED.index);
        font.setFontHeightInPoints((short) 12);
        titleStyle.setFont(font);
        titleStyle.setAlignment(HorizontalAlignment.CENTER);// 居中
        titleStyle.setFillForegroundColor(IndexedColors.WHITE.index);// 设置颜色
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直居中
        titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        titleStyle.setBorderRight(BorderStyle.THIN);
        titleStyle.setWrapText(true);
        return titleStyle;
    }

    @SuppressWarnings("deprecation")
    @Override
    public CellStyle stringNoneStyle(Workbook workbook, boolean isWarp) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setDataFormat(STRING_FORMAT);
        style.setWrapText(isWarp);
        return style;
    }

    /**
     * 标题行样式
     *
     * @param workbook
     * @return
     */
    public static CellStyle getCellStyle(Workbook workbook) {
        CellStyle titleStyle = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setBold(true);// 加粗
        font.setFontHeightInPoints((short) 12);
        titleStyle.setFont(font);
        titleStyle.setAlignment(HorizontalAlignment.CENTER);// 居中
        titleStyle.setVerticalAlignment(VerticalAlignment.CENTER);// 垂直居中
        titleStyle.setFillForegroundColor(IndexedColors.AQUA.index);// 设置颜色
        titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        titleStyle.setBorderRight(BorderStyle.THIN);
        titleStyle.setBorderBottom(BorderStyle.THIN);
        titleStyle.setBorderTop(BorderStyle.THIN);
        titleStyle.setBorderLeft(BorderStyle.THIN);
        titleStyle.setBorderRight(BorderStyle.THIN);
        titleStyle.setWrapText(true);
        return titleStyle;
    }
}
FileUtils.java
/**
 * 文件操作工具类
 *
 * @author: 一位大帅哥
 * @date: 2022/9/22 10:27
 * @description: TODO
 */
@Slf4j
public class FileUtils {

    @Value("${upload.path}")
    private String fileUploadPath;

    /**
     * 文件下载方法
     *
     * @param path 文件地址, 包含文件名及其扩展名
     * @param res
     */
    public static void downloadFile(String path, HttpServletResponse res) {
        OutputStream toClient = null;
        try {
            // 获取下载的路径
            File file = new File(path);
            // 获取文件名
            String filename = file.getName();
            res.setCharacterEncoding("UTF-8");
            res.setContentType("application/octet-stream");
            filename = URLEncoder.encode(filename, "UTF-8");
            // 设置文件下载后的指定文件名
            res.addHeader("Content-Disposition", filename);
            byte[] readBytes = FileUtil.readBytes(path);
            toClient = res.getOutputStream();
            toClient.write(readBytes);
            toClient.flush();
            log.info("文件下载成功,文件名:{}", filename);
        } catch (IOException e) {
            e.printStackTrace();
            log.error("下载文件错误:{}", e.getMessage());
        } finally {
            try {
                // 关闭缓冲输出流
                if (toClient != null) {
                    toClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
                log.error("下载文件错误:{}", e.getMessage());
            }
        }
    }

    /**
     * 上传文件
     *
     * @param file    文件
     * @param fileUrl 欲要上传到服务器的文件地址
     */
    public static void uploadFile(MultipartFile file, String fileUrl) {
        // 获取文件的后缀 这个获取是会携带.的 注意
        String suffixName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf("."));
        // 防止文件名重复 , 导致文件创建失败, 文件名后加uuid区分
        fileUrl = fileUrl + UUID.randomUUID() + suffixName;
        // 判断该文件夹是否存在 不存在的话就创建
        File dest = new File(fileUrl);
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }
        try {
            // 保存文件
            BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(fileUrl));
            outputStream.write(file.getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("文件上传错误: {}", e.getMessage());
        }
    }

    /**
     * 返回带.的文件扩展名
     *
     * @param fileName 文件名
     * @return 扩展名
     */
    public static String getFileExtension(String fileName) {

        // 返回带.的文件扩展名
        return fileName.substring(fileName.lastIndexOf("."));
    }

    /**
     * 导出多个文件 , 打包为压缩文件
     *
     * @param fileList    文件集合 , 字符串, 文件的绝对地址
     * @param zipFileName 打包后的压缩文件名
     * @param response    响应流
     * @throws IOException 异常
     */
    public static void zipFiles(List<String> fileList,
                                String zipFileName,
                                HttpServletResponse response) throws IOException {
        byte[] buf = new byte[1024];
        BufferedOutputStream bos = null;
        ZipOutputStream out = null;
        try {
            bos = new BufferedOutputStream(response.getOutputStream());
            //响应到浏览器
            setResponseZipData(response, zipFileName);
            out = new ZipOutputStream(bos);
            setResponseZipData(response, getExportFileName(".zip"));
            for (String filePath : fileList) {
                File file = new File(filePath);
                FileInputStream in = new FileInputStream(file);
                out.putNextEntry(new ZipEntry(file.getName()));
                int len;
                while ((len = in.read(buf)) != -1) {
                    out.write(buf, 0, len);
                }
                PoitlIOUtils.closeQuietlyMulti(in);
            }
        } catch (IOException e) {
            log.error("打包失败: {}!", e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(out, bos);
        }
    }

    /**
     * 设置response响应头参数 --> .xls版
     *
     * @param response 响应流
     * @param fileName 文件名
     */
    public static void setResponseXlsData(HttpServletResponse response, String fileName) {

        response.setContentType("application/octet-stream");
        URLEncodeUtil.encode(fileName, StandardCharsets.UTF_8);
        log.info("导出文件名为: {}", fileName);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setHeader("content-Type", "application/vnd.ms-excel");
    }

    /**
     * 设置response响应头参数 --> .xlsx版
     *
     * @param response 响应流
     * @param fileName 文件名
     */
    public static void setResponseXlsxData(HttpServletResponse response, String fileName) throws UnsupportedEncodingException {

        // response.setContentType("application/octet-stream");
        // URLEncodeUtil.encode(fileName, StandardCharsets.UTF_8);
        fileName = URLEncoder.encode(fileName, "UTF-8");
        log.info("导出文件名为: {}", fileName);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    }

    /**
     * 设置response响应头参数 --> 通用版
     *
     * @param response 响应流
     * @param fileName 文件名
     */
    public static void setResponseData(HttpServletResponse response, String fileName) {

        response.setContentType("application/octet-stream");
        URLEncodeUtil.encode(fileName, StandardCharsets.UTF_8);
        log.info("导出文件名为: {}", fileName);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
    }

    /**
     * 设置response响应头参数 --> .doc版
     *
     * @param response 响应流
     * @param fileName 文件名
     */
    public static void setResponseDocData(HttpServletResponse response, String fileName) {

        response.setContentType("application/octet-stream");
        URLEncodeUtil.encode(fileName, StandardCharsets.UTF_8);
        log.info("导出文件名为: {}", fileName);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setHeader("content-Type", "application/msword");
    }

    /**
     * 设置response响应头参数 --> .docx版
     *
     * @param response 响应流
     * @param fileName 文件名
     */
    public static void setResponseDocxData(HttpServletResponse response, String fileName) {

        response.setContentType("application/octet-stream");
        URLEncodeUtil.encode(fileName, StandardCharsets.UTF_8);
        log.info("导出文件名为: {}", fileName);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setHeader("content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
    }

    /**
     * 设置response响应头参数 --> .jpe / .jpeg / .jpz / .jpg版
     *
     * @param response 响应流
     * @param fileName 文件名
     */
    public static void setResponseJpgData(HttpServletResponse response, String fileName) {

        response.setContentType("application/octet-stream");
        URLEncodeUtil.encode(fileName, StandardCharsets.UTF_8);
        log.info("导出文件名为: {}", fileName);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setHeader("content-Type", "image/jpeg");
    }

    /**
     * 设置response响应头参数 --> .zip
     *
     * @param response 响应流
     * @param fileName 文件名
     */
    public static void setResponseZipData(HttpServletResponse response, String fileName) {

        response.setContentType("application/x-msdownload");
        URLEncodeUtil.encode(fileName, StandardCharsets.UTF_8);
        log.info("导出文件名为: {}", fileName);
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName);
        response.setHeader("content-Type", "application/x-msdownload");
    }

    /**
     * 压缩图片大小
     *
     * @param pictureUrl 图片url , 或者图片地址
     * @param scale      压缩比例 , 0 - 1之间
     * @return 压缩后的图像
     */
    public static BufferedImage compressedPicture(String pictureUrl, float scale) {

        try {
            // 获取原始图像
            BufferedImage templateImage = ImageIO.read(new URL(pictureUrl));
            // 获取原始图像的长度和宽度
            int height = templateImage.getHeight();
            int width = templateImage.getWidth();
            // 压缩之后的长度和宽度
            int doHeight = (int) (scale * height);
            int doWidth = (int) (scale * width);

            BufferedImage finalImage = new BufferedImage(doWidth, doHeight, BufferedImage.TYPE_INT_RGB);
            finalImage.getGraphics().drawImage(templateImage.getScaledInstance(doWidth, doHeight, Image.SCALE_SMOOTH), 0, 0, null);
            return finalImage;
        } catch (Exception e) {
            e.printStackTrace();
            log.error("压缩图片失败:{}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取全英文时间戳的文件名
     *
     * @param suffix 文件后缀
     * @return 文件名
     */
    public static String getExportFileName(String suffix) {
        return "export_" + DateTimeUtils.getDateTimeFormat(DateConstant.DATETIME_FORMAT24_NOT_LINE) + suffix;
    }

}

前提要了解easyPoi使用方法,没有了解过可以了解下,也很简单。

ok,到这里ExcelUtil的工具类的全部代码就这些了,下面我们挑一些方法,调用看看,试试效果是什么样子的。

首先来看看,参数最少的通用导出方法:可以看到,只有三个参数,一个是导出类的Class,一个要导出的集合,一个是响应流。

当然,既然是基于easyPoi,那么我下面的演示肯定都是实体类中都加了easyPoi导出对应的注解,下面只是一个示例:

/**
 * @author: GM
 * @date: 2023/11/1 15:27
 * @description: 项目用章申请台账resultVo
 */
@Data
@EqualsAndHashCode(callSuper = true)
public class ProjectStampLedgerResultVo extends PageResultDTO implements Serializable {

    private static final long serialVersionUID = 2803170257569474013L;

    /**
     * 流程编码
     */
    @Excel(name = "流程编码", width = 32)
    private String processNumber;

    /**
     * 项目名称
     */
    @Excel(name = "项目名称", width = 15)
    private String projectName;

    /**
     * 合同名称
     */
    @Excel(name = "合同名称", width = 20)
    private String contractName;

    /**
     * 用章原因
     */
    @Excel(name = "用章原因", width = 25)
    private String reasonForChapter;

    /**
     * 用章事项
     */
    @Excel(name = "用章事项", width = 15)
    private String administrativeMatters;

    /**
     * 用章份数
     */
    @Excel(name = "用章份数", width = 12)
    private Integer inChapters;

    /**
     * 审批结束时间
     */
    @Excel(name = "审批结束时间", width = 20, format = DateConstant.DATE_FORMAT)
    private Date approvalEndTime;
}

LogConstant是一个日志变量类,一些常用的日志打印字符串:

/**
 * 日志常量
 * @author: 一位大帅哥
 * @date: 2022/11/8 11:54
 * @description: TODO
 */
public interface LogConstant {

    /**
     * 导入开始时间
     */
    String IMPORT_START_TIME = "导入startTime: {}";

    /**
     * 导入结束时间
     */
    String IMPORT_END_TIME = "导入endTime: {}";

    /**
     * 导入失败
     */
    String IMPORT_FAIL = "导入失败:{}";

    /**
     * 获取文件中的记录错误
     */
    String GET_FILE_RECORD_FAIL = "获取文件中的记录错误: {}";

    /**
     * 导出开始时间
     */
    String EXPORT_START_TIME = "导出startTime: {}";

    /**
     * 导出结束时间
     */
    String EXPORT_END_TIME = "导出endTime: {}";

    /**
     * 导出失败
     */
    String EXPORT_FAIL = "导出失败: {}";

    /**
     * 查询失败
     */
    String QUERY_FAIL = "查询失败: {}";

    /**
     * 查询开始时间
     */
    String QUERY_START_TIME = "查询开始时间 : {}";

    /**
     * 查询结束时间
     */
    String QUERY_END_TIME = "查询结束时间 : {}";

    /**
     * 接口调用
     */
    String CALL_INTERFACE = "接口调用 : {} ";

    /**
     * 保存失败
     */
    String SAVE_FAIL = "保存失败 : {}";

    /**
     * 获取下一步流程节点用户信息失败
     */
    String GET_NEXT_ACTIVITIES_FAIL = "获取下一步流程节点用户信息失败 :{}";

    /**
     * 下载文件失败
     */
    String DOWNLOAD_FILE_FAIL = "下载文件失败:{}";

    /**
     * 下载文件成功
     */
    String DOWNLOAD_FILE_SUS = "下载文件成功:{}";

    /**
     * 请求处理时间
     */
    String REQUEST_PROCESSING_TIME = "请求处理时间: {}";
}
/**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     *
     * @param exportClass 要导出的类
     * @param exportList  要导出类集合
     * @param response    响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        try {
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            outputStream = response.getOutputStream();
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            CustomExcelExportUtils.exportExcel(params, exportClass, exportList).write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用方法导出!");
        } catch (Exception e) {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

// PoitlIOUtils.closeQuietlyMulti(outputStream);该方法是Poi-tl依赖的类方法,就是简单地判断该流是否为空,如果不为空则关闭。可用下面的方法实现同样的效果
/*
if (outputStream != null) {
	outputStream.close();
}
*/

导出的文件截图:

image-20231208142659223

可以看到,导出的东西很简单, 即没有标题行,也没有自定义的sheet名称。不过调用方法极其简单,提供数据和调用一下方法即可。

下面看一下重载的方法,多了写参数:sheetName,titleName。

/**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     *
     * @param exportClass 要导出的类
     * @param exportList  要导出类集合
     * @param sheetName   导出工作表名
     * @param titleName   标题名称
     * @param response    响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          String sheetName,
                                          String titleName,
                                          HttpServletResponse response) {
        ServletOutputStream outputStream = null;
        try {
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            params.setSheetName(sheetName);
            params.setTitle(titleName);
            outputStream = response.getOutputStream();
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            CustomExcelExportUtils.exportExcel(params, exportClass, exportList).write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用方法导出!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

多加了参数,看看导出的效果:

image-20231208150107716

相信有时候大家也会遇到导入导出excel时的字典码转换问题,用户导出了之后,你可以自己把字典值翻译到文档上面,但是文档到了用户手里,他就不会那么规矩的按常理出牌了,往往是自己乱填,导入的结果和字典值对不上,就会导致空值,这时候用户还要反映bug,你说这找谁说理去。

所以下面这个方法就是来对某个为字典值的列来的,给他锁住这一列,让他选择,只能选择数据,而不是手填数据,这就能完美避免用户手填数据不标准和字典值对不上的情况,话不多说,看代码:

/**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     * 支持校验某一列数据
     *
     * @param exportClass     要导出的类
     * @param exportList      要导出类集合
     * @param checkColumnData 校验列选择框提示内容
     * @param col             第几列校验
     * @param response        响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          String[] checkColumnData,
                                          int col,
                                          HttpServletResponse response) {

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            Workbook workbook = CustomExcelExportUtils.exportExcel(params, exportClass, exportList);
            createXssfOfSelected(workbook, checkColumnData, col);
            workbook.write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用方法导出!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

创建选择列的方法:

/**
     * XSSF
     * excel添加下拉数据校验
     *
     * @param workbook   哪个 sheet 页添加校验
     * @param dataSource 数据源数组
     * @param col        第几列校验(0开始)
     */
    public static void createXssfOfSelected(Workbook workbook, String[] dataSource, int col) {
        Sheet sheet = workbook.getSheetAt(0);
        CellRangeAddressList cellRangeAddressList = new CellRangeAddressList(1, 65535, col, col);
        DataValidationHelper helper = sheet.getDataValidationHelper();
        DataValidationConstraint constraint = helper.createExplicitListConstraint(dataSource);
        DataValidation dataValidation = helper.createValidation(constraint, cellRangeAddressList);
        //处理Excel兼容性问题
        if (dataValidation instanceof XSSFDataValidation) {
            dataValidation.setSuppressDropDownArrow(true);
            dataValidation.setShowErrorBox(true);
        } else {
            dataValidation.setSuppressDropDownArrow(false);
        }
        dataValidation.setEmptyCellAllowed(true);
        dataValidation.setShowPromptBox(true);
        dataValidation.createPromptBox("提示", "只能选择下拉框里面的数据!");
        sheet.addValidationData(dataValidation);
    }

OK,这种情况主要用来做导入模板用,只有表头,数据用户自己手填,然后填完导入到页面中。

看看效果:

设置了某一列只可选择数据的效果:

image-20231208145718069

选择框内容为数组数据,这个自行获取,我是查询数据库字典表获取的对应编码值。

image-20231208145822159

只能选择,不能手填,是不是很好用,妈妈再也不用担心我手填的数据不标准了。哈哈哈

下面就也是个重载的方法,和上面的区别就是加了表头和sheet名称,就不演示了:

/**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     * 支持校验某一列数据
     *
     * @param exportClass     要导出的类
     * @param exportList      要导出类集合
     * @param checkColumnData 校验列选择框提示内容
     * @param col             第几列校验
     * @param sheetName       导出文件的工作表名称
     * @param response        响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          String[] checkColumnData,
                                          int col,
                                          String sheetName,
                                          HttpServletResponse response) {

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            params.setSheetName(sheetName);
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            Workbook workbook = CustomExcelExportUtils.exportExcel(params, exportClass, exportList);
            createXssfOfSelected(workbook, checkColumnData, col);
            workbook.write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用导出方法!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

下面就是这个锁定数据列方法的延伸了,一个文档可以同时锁定多个列,每个锁定列也可以保持独立的选择框内容。

ok,看看方法:

/**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     * 支持校验多列数据
     * for example
     * {
     * 如果需要导出的数据校验第三列和第八列
     * 则:
     * checkColumnData: {
     * 3,["提示数据1","提示数据2","提示数据3",...],
     * 8,["提示数据1","提示数据2","提示数据3",...]
     * }
     * col: [3,8]
     * }
     *
     * @param exportClass     要导出的类
     * @param exportList      要导出类集合
     * @param checkColumnData 校验列选择框提示内容 , 可多个
     * @param col             需要校验的列 , 可多个
     * @param response        响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          Map<Integer, String[]> checkColumnData,
                                          Integer[] col,
                                          HttpServletResponse response) {

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            Workbook workbook = CustomExcelExportUtils.exportExcel(params, exportClass, exportList);
            for (Integer columnNumber : col) {
                createXssfOfSelected(workbook, checkColumnData.get(columnNumber), columnNumber);
            }
            workbook.write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用导出方法!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

列数据Map中,key就是要锁定的列号,从0开始,对应的value就是他需要的数据。

看效果:

image-20231208150800578

image-20231208150852072

同时做了两列验证。

下面的一个方法也就是一个重载,多了两个参数,就不展示了,和第一个一样,多了表头和工作表名称自定义。

/**
     * 通用导出方法
     * 带序号, 默认ExcelExportMyStyler格式
     * 支持校验多列数据
     * for example
     * {
     * 如果需要导出的数据校验第三列和第八列
     * 则:
     * checkColumnData: {
     * 3,["提示数据1","提示数据2","提示数据3",...],
     * 8,["提示数据1","提示数据2","提示数据3",...]
     * }
     * col: [3,8]
     * }
     *
     * @param exportClass     要导出的类
     * @param exportList      要导出类集合
     * @param checkColumnData 校验列选择框提示内容 , 可多个
     * @param col             需要校验的列 , 可多个
     * @param sheetName       工作表名称
     * @param response        响应流
     */
    public static void exportExcelGeneral(Class exportClass,
                                          Collection exportList,
                                          Map<Integer, String[]> checkColumnData,
                                          Integer[] col,
                                          String sheetName,
                                          HttpServletResponse response) {

        ServletOutputStream outputStream = null;
        try {
            outputStream = response.getOutputStream();
            ExportParams params = new ExportParams();
            params.setAddIndex(true);
            params.setStyle(ExcelExportMyStyler.class);
            params.setSheetName(sheetName);
            FileUtils.setResponseXlsxData(response, FileUtils.getExportFileName(".xlsx"));
            Workbook workbook = CustomExcelExportUtils.exportExcel(params, exportClass, exportList);
            for (Integer columnNumber : col) {
                createXssfOfSelected(workbook, checkColumnData.get(columnNumber), columnNumber);
            }
            workbook.write(outputStream);
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.info("通用导出方法!");
        } catch (Exception e) {
            e.printStackTrace();
            PoitlIOUtils.closeQuietlyMulti(outputStream);
            log.error(LogConstant.EXPORT_FAIL, e.getMessage());
        } finally {
            PoitlIOUtils.closeQuietlyMulti(outputStream);
        }
    }

下面方法就是针对于数字列的处理了,估计大家也会遇到一些情况,就是说,数字列,用户填了除了数字的其他字段,比如字母,中英文标点之类的,这样的话就会导致导入数据异常,因为数字类型是无法接收,这就很尴尬了。。。其实这种情况来说,我觉得我后端程序员是不粘锅的。嘿嘿。

OK,不多说,来看方法:

/**
     * 为excel文件某一列设置数字,小数整数都可以校验
     *
     * @param workbook 文件
     * @param startCol 第几列校验(0开始)
     * @param endCol   第几列校验(0开始)
     */
    public static void createXssfOfDecimal(Workbook workbook, int startCol, int endCol) {

        Sheet sheet = workbook.getSheetAt(0);
        CellRangeAddressList cell = new CellRangeAddressList(1, 65535, startCol, endCol);
        DataValidationHelper helper = sheet.getDataValidationHelper();
        // 创建一个大于等于0的数值约束
        DataValidationConstraint constraint = helper.createDecimalConstraint(DataValidationConstraint.OperatorType.GREATER_OR_EQUAL, "0.0", null);
        DataValidation validation = helper.createValidation(constraint, cell);
        //处理Excel兼容性问题
        if (validation instanceof XSSFDataValidation) {
            validation.setSuppressDropDownArrow(true);
            validation.setShowErrorBox(true);
        } else {
            validation.setSuppressDropDownArrow(false);
        }
        // 允许空值
        validation.setEmptyCellAllowed(true);
        validation.setShowErrorBox(true);
        validation.createErrorBox("提示", "该列只能是纯数字或小数!");
        sheet.addValidationData(validation);
    }

来看看导出效果:

不是数字 ,就提示,然后不许你保存,这样是不是就能避免很多问题发生呢。

下面的就是属于锦上添花了,校验该数字只能是正整数。OK,看看方法:

/**
     * 为excel文件某一列设置数字整数校验
     *
     * @param workbook 文件
     * @param startCol 第几列校验(0开始)
     * @param endCol   第几列校验(0开始)
     */
    public static void createXssfOfInteger(Workbook workbook, int startCol, int endCol) {

        Sheet sheet = workbook.getSheetAt(0);
        CellRangeAddressList cell = new CellRangeAddressList(1, 65535, startCol, endCol);
        DataValidationHelper helper = sheet.getDataValidationHelper();
        // 创建一个大于等于0的数值约束
        DataValidationConstraint constraint = helper.createIntegerConstraint(DataValidationConstraint.OperatorType.GREATER_OR_EQUAL, "0", null);
        DataValidation validation = helper.createValidation(constraint, cell);
        //处理Excel兼容性问题
        if (validation instanceof XSSFDataValidation) {
            validation.setSuppressDropDownArrow(true);
            validation.setShowErrorBox(true);
        } else {
            validation.setSuppressDropDownArrow(false);
        }
        // 允许空值
        validation.setEmptyCellAllowed(true);
        validation.setShowErrorBox(true);
        validation.createErrorBox("提示", "该列只能是纯数字且不可为小数和负数!");
        sheet.addValidationData(validation);
    }

这个就没有效果图了,因为还没有用过,有兴趣看到这里的朋友们,可以自己导出试试,我觉得,必是没有毛病的代码,奥力给!

ppressDropDownArrow(false);
}
// 允许空值
validation.setEmptyCellAllowed(true);
validation.setShowErrorBox(true);
validation.createErrorBox(“提示”, “该列只能是纯数字或小数!”);
sheet.addValidationData(validation);
}


来看看导出效果:

[外链图片转存中...(img-WYEW1S4c-1702021273538)]







不是数字 ,就提示,然后不许你保存,这样是不是就能避免很多问题发生呢。



下面的就是属于锦上添花了,校验该数字只能是正整数。OK,看看方法:

```java
/**
     * 为excel文件某一列设置数字整数校验
     *
     * @param workbook 文件
     * @param startCol 第几列校验(0开始)
     * @param endCol   第几列校验(0开始)
     */
    public static void createXssfOfInteger(Workbook workbook, int startCol, int endCol) {

        Sheet sheet = workbook.getSheetAt(0);
        CellRangeAddressList cell = new CellRangeAddressList(1, 65535, startCol, endCol);
        DataValidationHelper helper = sheet.getDataValidationHelper();
        // 创建一个大于等于0的数值约束
        DataValidationConstraint constraint = helper.createIntegerConstraint(DataValidationConstraint.OperatorType.GREATER_OR_EQUAL, "0", null);
        DataValidation validation = helper.createValidation(constraint, cell);
        //处理Excel兼容性问题
        if (validation instanceof XSSFDataValidation) {
            validation.setSuppressDropDownArrow(true);
            validation.setShowErrorBox(true);
        } else {
            validation.setSuppressDropDownArrow(false);
        }
        // 允许空值
        validation.setEmptyCellAllowed(true);
        validation.setShowErrorBox(true);
        validation.createErrorBox("提示", "该列只能是纯数字且不可为小数和负数!");
        sheet.addValidationData(validation);
    }

这个就没有效果图了,因为还没有用过,有兴趣看到这里的朋友们,可以自己导出试试,我觉得,必是没有毛病的代码,奥力给!

到这里也就结束了,能看到这里的我相信也是确实对这方面有需要,也想了解的,代码放心食用,没有毛病,如果可以的话,动动大家发财的小手给博主点点赞,也是花了一下午在公司摸鱼写的文档,嘿嘿。三连莫负。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值