Hutool excel导出

作者: 无我_无他_有你 | 来源:发表于2021-05-27 20:46 被阅读0次

    easyExcel 文档不是很友好,所以转用hutool 工具导出excel,百度到的很多都没多少营养,略作总结,望君不吝赐教。
    该篇博客可以让你画出不是太复杂的excel 如:


    image.png

    ps: 该篇文章为代码画excel,不介绍模板填充方式,因为模板填充较为简单。

    excel导出Hutool官方教程
    excel导出Hutool api 地址
    https://apidoc.gitee.com/loolly/hutool/cn/hutool/poi/excel/package-frame.html

    版本依赖,项目中直接引入了hutool-all依赖包,其中包括了导出excel所需的所有依赖包

    <dependency>
         <groupId>cn.hutool</groupId>
         <artifactId>hutool-all</artifactId>
         <version>5.5.0</version>
    </dependency>
    

    api 中已经详细写了方法的说明,再此不多加阐述

    1.字体样式常用方法

        /**
         * 方法描述: 设置基础字体样式字体 这里保留最基础的样式使用
         *
         * @param workbook 工作簿
         * @param bold     是否粗体
         * @param fontName 字体名称
         * @param fontSize 字体大小
         * @return org.apache.poi.ss.usermodel.Font
         * @author wqf
         * @date 2021/5/19 15:58
         */
        public static Font setBaseFont(Workbook workbook, boolean bold, boolean italic, String fontName, int fontSize) {
            Font font = workbook.createFont();
            //设置字体名称 宋体 / 微软雅黑 /等
            font.setFontName(fontName);
            //设置是否斜体
            font.setItalic(italic);
            //设置字体高度
            //font.setFontHeight((short) fontHeight);
            //设置字体大小 以磅为单位
            font.setFontHeightInPoints((short) fontSize);
            //设置是否加粗
            font.setBold(bold);
            //默认字体颜色
            // font.setColor(Font.COLOR_NORMAL);
            //红色
            //font.setColor(Font.COLOR_RED);
            //设置下划线样式
            //font.setUnderline(Font.ANSI_CHARSET);
            //设定文字删除线
            //font.setStrikeout(true);
            return font;
        }
    
    1. 全局样式设置
     private static StyleSet GlobalStyleSet(ExcelWriter writer, Workbook workbook,Font font) {
            //全局样式设置
            StyleSet styleSet = writer.getStyleSet();
            CellStyle cellStyle = styleSet.getCellStyle();
            //设置全局文本居中
            styleSet.setAlign(HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
            //设置全局字体样式
            styleSet.setFont(font);
            //设置背景颜色 第二个参数表示是否将样式应用到头部
            styleSet.setBackgroundColor(IndexedColors.WHITE, true);
            //设置自动换行 当文本长于单元格宽度是否换行
            styleSet.setWrapText();
            // 设置全局边框样式
            styleSet.setBorder(BorderStyle.THIN, IndexedColors.BLACK);
            return styleSet;
        }
    
    1. 头部标题样式
    //设置全局样式
    StyleSet styleSet = GlobalStyleSet(writer, workbook);
    //设置头部标题样式
    CellStyle headCellStyle = styleSet.getHeadCellStyle();
    //水平居中
    headCellStyle.setAlignment(HorizontalAlignment.CENTER);
    //垂直居中
    headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
    //设置字体样式
    headCellStyle.setFont(setBaseFont(workbook, true, false, "宋体", 12));
    writer.setStyleSet(styleSet);
    
    1. 数字保留小数
      例:保留两位小数
    CellStyle cellStyleForNumber = styleSet.getCellStyleForNumber();
    cellStyleForNumber.setDataFormat((short)2);
    

    5.时间格式化
    例如格式为:YYYY/MM/dd 格式

    CellStyle cellStyleForDate = styleSet.getCellStyleForDate();
    //14 代表的时间格式是 yyyy/MM/dd
    cellStyleForDate.setDataFormat((short)14);
    

    时间格式占时只看到这一种格式常见些,像yyyy-MM-dd 格式都没找到,就只有在写入数据写先处理下时间格式了。

    1. 行(Row)样式
    //获取输出构造器 设置工作簿名称
    ExcelWriter writer = ExcelUtil.getWriterWithSheet(sheetName);
    Workbook workbook = writer.getWorkbook();
    Sheet sheet = writer.getSheet();
    Row row = sheet.getRow(rowIndex);
     if(sheet.getRow(rowIndex )==null){
          //rowIndex 表示的是第几行,例:创建第二行,rowIndex=1
          sheet.createRow(rowIndex );
      }
    //创建样式
    CellStyle cellStyle = workbook.createCellStyle();
    cellStyle .setVerticalAlignment(VerticalAlignment.CENTER);
    cellStyle .setAlignment(HorizontalAlignment.LEFT);
    cellStyle .setFont(setBaseFont(workbook, true, false, "宋体", 12));
    cellStyle .setBorderBottom(BorderStyle.THIN);
    cellStyle .setBorderLeft(BorderStyle.THIN);
    cellStyle .setBorderRight(BorderStyle.THIN);
    cellStyle .setBorderTop(BorderStyle.THIN);
    //应用样式到某一行(
    row .setRowStyle(cellStyle );
    //应用样式到某一行 (或者这样写) rowIndex  表示的是第几行
    //writer.setRowStyle(rowIndex ,cellStyle );
    
    1. 单元格(Cell)样式
    Row row = sheet.getRow(rowIndex);
    if(sheet.getRow(rowIndex )==null){
          //rowIndex 表示的是第几行,例:创建第二行,rowIndex=1
          sheet.createRow(rowIndex );
      }
    //创建本行的第几个单元格  cellIndex=0 表示第一个
    if(row.get(cellIndex)==null){
        row .createCell(cellIndex);
    }
    
    //创建样式
    CellStyle cellStyle = workbook.createCellStyle();
    cellStyle .setVerticalAlignment(VerticalAlignment.CENTER);
    cellStyle .setAlignment(HorizontalAlignment.LEFT);
    cellStyle .setFont(setBaseFont(workbook, true, false, "宋体", 12));
    cellStyle .setBorderBottom(BorderStyle.THIN);
    cellStyle .setBorderLeft(BorderStyle.THIN);
    cellStyle .setBorderRight(BorderStyle.THIN);
    cellStyle .setBorderTop(BorderStyle.THIN);
    //应用样式到某一行(
    row .setRowStyle(cellStyle );
    //应用样式到某一行 (或者这样写) rowIndex  表示的是第几行
    //writer.setRowStyle(rowIndex ,cellStyle );
    
    1. 合并单元格
      //处理标题行 合并某行的单元格,并写入对象到单元格,如果写到单元格中的内容非null,行号自动+1,否则当前行号不变
    //主要有两种方式
    1. writer.merge(cellIndex, content, true);  
    表示当前行 合并从第一个单元到cellIndex+1个单元,并填充内容content,第三个参数表示是否将头部标题样式应用到这里。
    或者
    2.writer.merge(startRowIndex,endRowIndex, startCellIndex, endCellIndex, content, false);
    表示和并第startRowIndex+1行到endRowIndex+1行 ,并合并从第endCellIndex+1个单元到endCellIndex+1个单元格,并填充content内容,最后一个字段表示是否将头部标题样式应用到这里。
    
    1. 列表别名
    //LinkedHashMap 中的数据是根据put先后顺序来的,HashMap数据时无序的。
    //使用方法 writer.setHeaderAlias(headerAlias); 时如果使用HashMap 可能展示的数
    //据顺序会错乱
    Map<String, String> headerAlias = new LinkedHashMap<>();
    headerAlias.put(字段名1, 列名1);
    headerAlias.put(字段名2, 列名2);
    headerAlias.put(字段名3, 列名3);
    headerAlias.put(字段名4, 列名4);
    headerAlias.put(字段名5, 列名5);
    writer.setHeaderAlias(headerAlias);
    //或者一项一项设置列的别名 列别名顺序会跟代码中addHeaderAlias顺序一致
    writer.addHeaderAlias(字段名1,列名1);
    writer.addHeaderAlias(字段名2,列名2);
    
    1. 列宽问题
      8.1 自动列宽 百度查到一个方法有用 ,但实际好像还是会有点问题,大家可以先试试
      博客链接 :https://blog.csdn.net/kongbai953/article/details/110382544
    /**
         * 自适应宽度(中文支持)
         * @param sheet
         * @param size 因为for循环从0开始,size值为 列数-1
         */
        public static void setSizeColumn(Sheet sheet, int size) {
            for (int columnNum = 0; columnNum <= size; columnNum++) {
                int columnWidth = sheet.getColumnWidth(columnNum) / 256;
                for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
                    Row currentRow;
                    //当前行未被使用过
                    if (sheet.getRow(rowNum) == null) {
                        currentRow = sheet.createRow(rowNum);
                    } else {
                        currentRow = sheet.getRow(rowNum);
                    }
    
                    if (currentRow.getCell(columnNum) != null) {
                        Cell currentCell = currentRow.getCell(columnNum);
                        if (currentCell.getCellType() == XSSFCell.CELL_TYPE_STRING) {
                            int length = currentCell.getStringCellValue().getBytes().length;
                            if (columnWidth < length) {
                                columnWidth = length;
                            }
                        }
                    }
                }
                sheet.setColumnWidth(columnNum, columnWidth * 256);
            }
        }
    

    8.2 手动列宽设置

    //表示 第一列的列宽是15
     writer.setColumnWidth(0, 15);
    
    1. 另外常用方法

    //跳过当前行 即当前行不写内容

    writer.passCurrentRow();
    

    //定位到最后一行,常用于在末尾追加数据

    writer.setCurrentRowToEnd();
    

    10 . 下载excel代码 在数据都填充完成后,调用该方法即可

     /**
         * 方法描述: 下载excel文件
         *
         * @param response 响应
         * @param fileName 文件名称
         * @param writer   writer
         * @return void
         * @author wqf
         * @date 2021/5/24 16:20
         */
        private static void downloadExcel(HttpServletResponse response, String fileName, ExcelWriter writer) {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            // test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
            ServletOutputStream out = null;
            try {
                // 设置请求头属性
                response.setHeader("Content-Disposition", "attachment;filename=" + new String((fileName + ".xlsx").getBytes(), StandardCharsets.ISO_8859_1));
                out = response.getOutputStream();
                // 写出到文件
                writer.flush(out, true);
                // 关闭writer,释放内存
                writer.close();
                // 此处记得关闭输出Servlet流
                IoUtil.close(out);
            } catch (IOException e) {
                log.error(e.getMessage());
                e.printStackTrace();
            }
        }
    
    1. excel 添加下拉框
    CellRangeAddressList addressList = new CellRangeAddressList(2, 2, 5, 5);
    DataValidationHelper helper = sheet.getDataValidationHelper();
     // 设置下拉框数据
    String[] str = new String[]{"男", "女","阴阳人"};
    DataValidationConstraint constraint = helper.createExplicitListConstraint(str);
    DataValidation dataValidation = helper.createValidation(constraint, addressList);
    writer.addValidationData(dataValidation);
    

    12.背景色填充

    //示例:将单元格背景填充为黄色
    short index = IndexedColors.YELLOW.index;
    cellStyle.setFillForegroundColor(index);
    cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
    

    总结 : 整合了一个工具类,仅作参考

    /**
     * @Author: wqf
     * @Date: 2021/05/28
     * @Description: hutool 工具导出excel(非填充模板,手工画)
     */
    @Slf4j
    public class HutoolExcelUtil {
        /**
         * YYYY/MM/dd 时间格式
         */
        private static final short LOCAL_DATE_FORMAT_SLASH = 14;
    
        /**
         * 方法描述: 创建excel
         *
         * @param isXlsx excel文件类型 true-xlsx/false-xls
         * @return cn.hutool.poi.excel.ExcelWriter
         * @author wqf
         * @date 2021/6/1 9:47
         */
        public static ExcelWriter createExcel(boolean isXlsx) {
            return ExcelUtil.getWriter(isXlsx);
        }
    
        /**
         * 方法描述: 全局基础样式设置
         * 默认 全局水平居中+垂直居中
         * 默认 自动换行
         * 默认单元格边框颜色为黑色,细线条
         * 默认背景颜色为白色
         *
         * @param writer writer
         * @param font   字体样式
         * @return cn.hutool.poi.excel.StyleSet
         * @author wqf
         * @date 2021/5/28 10:43
         */
        public static StyleSet setBaseGlobalStyle(ExcelWriter writer, Font font) {
            //全局样式设置
            StyleSet styleSet = writer.getStyleSet();
            //设置全局文本居中
            styleSet.setAlign(HorizontalAlignment.CENTER, VerticalAlignment.CENTER);
            //设置全局字体样式
            styleSet.setFont(font, true);
            //设置背景颜色 第二个参数表示是否将样式应用到头部
            styleSet.setBackgroundColor(IndexedColors.WHITE, true);
            //设置自动换行 当文本长于单元格宽度是否换行
            //styleSet.setWrapText();
            // 设置全局边框样式
            styleSet.setBorder(BorderStyle.THIN, IndexedColors.BLACK);
            return styleSet;
        }
    
        /**
         * 方法描述: 设置标题的基础样式
         *
         * @param styleSet            StyleSet
         * @param font                字体样式
         * @param horizontalAlignment 水平排列方式
         * @param verticalAlignment   垂直排列方式
         * @return org.apache.poi.ss.usermodel.CellStyle
         * @author wqf
         * @date 2021/5/28 10:16
         */
        public static CellStyle createHeadCellStyle(StyleSet styleSet, Font font,
                                                    HorizontalAlignment horizontalAlignment,
                                                    VerticalAlignment verticalAlignment) {
            CellStyle headCellStyle = styleSet.getHeadCellStyle();
            headCellStyle.setAlignment(horizontalAlignment);
            headCellStyle.setVerticalAlignment(verticalAlignment);
            headCellStyle.setFont(font);
            return headCellStyle;
        }
    
        /**
         * 方法描述: 设置基础字体样式字体 这里保留最基础的样式使用
         *
         * @param bold     是否粗体
         * @param fontName 字体名称
         * @param fontSize 字体大小
         * @return org.apache.poi.ss.usermodel.Font
         * @author wqf
         * @date 2021/5/19 15:58
         */
        public static Font createFont(ExcelWriter writer, boolean bold, boolean italic, String fontName, int fontSize) {
            Font font = writer.getWorkbook().createFont();
            //设置字体名称 宋体 / 微软雅黑 /等
            font.setFontName(fontName);
            //设置是否斜体
            font.setItalic(italic);
            //设置字体大小 以磅为单位
            font.setFontHeightInPoints((short) fontSize);
            //设置是否加粗
            font.setBold(bold);
            return font;
        }
    
        /**
         * 方法描述: 设置行或单元格基本样式
         *
         * @param writer              writer
         * @param font                字体样式
         * @param verticalAlignment   垂直居中
         * @param horizontalAlignment 水平居中
         * @return void
         * @author wqf
         * @date 2021/5/28 10:28
         */
        public static CellStyle createCellStyle(ExcelWriter writer, Font font, boolean wrapText,
                                                VerticalAlignment verticalAlignment,
                                                HorizontalAlignment horizontalAlignment) {
            CellStyle cellStyle = writer.getWorkbook().createCellStyle();
            cellStyle.setVerticalAlignment(verticalAlignment);
            cellStyle.setAlignment(horizontalAlignment);
            cellStyle.setWrapText(wrapText);
            cellStyle.setFont(font);
            return cellStyle;
        }
    
        /**
         * 方法描述: 设置边框样式
         *
         * @param cellStyle 样式对象
         * @param bottom    下边框
         * @param left      左边框
         * @param right     右边框
         * @param top       上边框
         * @return void
         * @author wqf
         * @date 2021/5/28 10:23
         */
        public static void setBorderStyle(CellStyle cellStyle, BorderStyle bottom, BorderStyle left, BorderStyle right,
                                          BorderStyle top) {
            cellStyle.setBorderBottom(bottom);
            cellStyle.setBorderLeft(left);
            cellStyle.setBorderRight(right);
            cellStyle.setBorderTop(top);
        }
    
        /**
         * 方法描述: 获取对象需要导出的列和别名 这里按字段顺序来(可以在自定义注解上添加属性标识字段顺序,重写方法)
         * 在需要导出的字段上贴上注解 这里是@ExcelProperty,也可以用自定义注解
         * 注解需要有value 标识别名 order 标识字段顺序
         *
         * @param clazz 对象类型
         * @return int 导出的字段个数
         * @author wqf
         * @date 2021/4/29 16:56
         */
        public static int setHeaderAlias(ExcelWriter writer, Class<?> clazz) {
            //需要导出的字段数
            Field[] fields = clazz.getDeclaredFields();
            TreeMap<Integer, Map<String, String>> headerAliasMap = new TreeMap<>();
            Arrays.stream(fields).forEach(f -> {
                if (f.isAnnotationPresent(ExcelProperty.class)) {
                    ExcelProperty annotation = f.getAnnotation(ExcelProperty.class);
                    //别名
                    String[] value = annotation.value();
                    int order = annotation.order();
                    Map<String, String> alisMap = new HashMap<>();
                    String fieldName = f.getName();
                    //字段名
                    String headerAlias = value[0];
                    alisMap.put(fieldName, headerAlias);
                    headerAliasMap.put(order, alisMap);
                }
            });
            LinkedHashMap<String, String> linkedMap = new LinkedHashMap<>();
            for (Map.Entry<Integer, Map<String, String>> entry : headerAliasMap.entrySet()) {
                linkedMap.putAll(entry.getValue());
            }
            writer.setHeaderAlias(linkedMap);
            return linkedMap.size();
        }
    
        /**
         * 方法描述: 自适应宽度(中文支持)
         * 
         * @param sheet 页
         * @param size  因为for循环从0开始,size值为 列数-1
         * @return void
         * @author wqf
         * @date 2021/5/28 14:06
         */
        public static void setSizeColumn(Sheet sheet, int size) {
            for (int columnNum = 0; columnNum <= size; columnNum++) {
                int columnWidth = sheet.getColumnWidth(columnNum) / 256;
                for (int rowNum = 0; rowNum <= sheet.getLastRowNum(); rowNum++) {
                    Row currentRow;
                    //当前行未被使用过
                    if (sheet.getRow(rowNum) == null) {
                        currentRow = sheet.createRow(rowNum);
                    } else {
                        currentRow = sheet.getRow(rowNum);
                    }
    
                    if (currentRow.getCell(columnNum) != null) {
                        Cell currentCell = currentRow.getCell(columnNum);
                        if (currentCell.getCellType() == CellType.STRING) {
                            int length = currentCell.getStringCellValue().getBytes().length;
                            if (columnWidth < length) {
                                columnWidth = length;
                            }
                        }
                    }
                }
                sheet.setColumnWidth(columnNum, columnWidth * 256);
            }
        }
    
        /**
         * 方法描述: excel 导出下载
         *
         * @param response 响应
         * @param fileName 文件名
         * @param writer   writer
         * @return void
         * @author wqf
         * @date 2021/6/1 11:11
         */
        public static void downloadExcel(HttpServletResponse response, String fileName, ExcelWriter writer) {
            response.setContentType("application/vnd.ms-excel;charset=utf-8");
            // test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
            ServletOutputStream out = null;
            try {
                // 设置请求头属性
                response.setHeader("Content-Disposition",
                        "attachment;filename=" + new String((fileName + ".xlsx").getBytes(), StandardCharsets.ISO_8859_1));
                out = response.getOutputStream();
                // 写出到文件
                writer.flush(out, true);
                // 关闭writer,释放内存
                writer.close();
                // 此处记得关闭输出Servlet流
                IoUtil.close(out);
            } catch (IOException e) {
                log.info("文件下载失败==" + e);
            }
        }
    
        /**
         * 方法描述: 最简单的导出,直接将数据放到excel
         * 导入的数据最好是List<map>格式数据,主要原因是List<Object> ,
         * 对象有字段是LocalDate或者是LocalDateTime类型的数据,
         * 时间格式化可能达不到想要的效果
         *
         * @param data       对象集合 两种
         * @param globalFont 全局字体样式
         * @param clazz      导出的对应class类型
         * @return void
         * @author wqf
         * @date 2021/5/28 11:22
         */
        public static ExcelWriter exportBaseExcel(ExcelWriter writer, List<?> data, Font globalFont, Class clazz) {
            Sheet sheet = writer.getSheet();
            writer.setStyleSet(setBaseGlobalStyle(writer, globalFont));
            int columnSize = setHeaderAlias(writer, clazz);
            writer.setOnlyAlias(true);
            writer.write(data);
            setSizeColumn(sheet, columnSize);
            return writer;
        }
    }
    

    相关文章

      网友评论

        本文标题:Hutool excel导出

        本文链接:https://www.haomeiwen.com/subject/qtmpjltx.html