Hutool-poi是针对Apache POI的封装,操作Excel【三】

package com.example.demo.hutool;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import cn.hutool.poi.excel.StyleSet;
import lombok.Data;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.junit.Test;

import java.util.*;

/**
 * @Description Hutool-poi是针对Apache POI的封装
 *
 *  使用Hutool的方法操作Office文件,Hutool提供的类有:
 *      ExcelUtil Excel工具类,读取的快捷方法都被封装于此。
 *      ExcelReader Excel读取器,Excel读取的封装,可以直接构造后使用。
 *      ExcelWriter Excel生成并写出器,Excel写出的封装(写出到流或者文件),可以直接构造后使用。
 *
 *  Excel 写入器 此工具用于通过POI将数据写出到Excel,此对象可完成以下两个功能:
 *      1. 编辑已存在的Excel,可写出原Excel文件,也可写出到其它地方(到文件或到流)
 *      2. 新建一个空的Excel工作簿,完成数据填充后写出(到文件或到流)
 *
 *  ExcelWriter类的主要方法:
 *      构造器:
 *      ExcelWriter() 默认生成xls格式的Excel文件
 *          此构造不传入写出的Excel文件路径,只能调用flush(OutputStream)方法写出到流
 *          若写出到文件,还需调用setDestFile(File)方法自定义写出的文件,然后调用flush()方法写出到文件
 *      ExcelWriter(boolean isXlsx) 此构造不传入写出的Excel文件路径,只能调用flush(OutputStream)方法写出到流
 *          若写出到文件,需要调用flush(File) 写出到文件
 *      ExcelWriter(boolean isXlsx, String sheetName) 此构造不传入写出的Excel文件路径,只能调用flush(OutputStream)方法写出到流
 *          若写出到文件,需要调用flush(File) 写出到文件
 *      ExcelWriter(org.apache.poi.ss.usermodel.Sheet sheet) 此构造不传入写出的Excel文件路径,只能调用flush(OutputStream)方法写出到流
 *          若写出到文件,还需调用setDestFile(File)方法自定义写出的文件,然后调用flush()方法写出到文件
 *      ExcelWriter(org.apache.poi.ss.usermodel.Workbook workbook, String sheetName) 此构造不传入写出的Excel文件路径,只能调用flush(OutputStream)方法写出到流
 *          若写出到文件,还需调用setDestFile(File)方法自定义写出的文件,然后调用flush()方法写出到文件
 *      ExcelWriter(File destFile) 默认写出到第一个sheet,第一个sheet名为sheet1
 *      ExcelWriter(File destFile, String sheetName)
 *      ExcelWriter(String destFilePath) 默认写出到第一个sheet,第一个sheet名为sheet1
 *      ExcelWriter(String destFilePath, String sheetName)
 *
 *      方法:
 *      ExcelWriter	addHeaderAlias(String name, String alias) 增加标题别名
 *      ExcelWriter	addSelect(org.apache.poi.ss.util.CellRangeAddressList regions, String... selectList) 增加下拉列表
 *      ExcelWriter	addSelect(int x, int y, String... selectList) 增加下拉列表
 *      ExcelWriter	addValidationData(org.apache.poi.ss.usermodel.DataValidation dataValidation)
 *          增加单元格控制,比如下拉列表、日期验证、数字范围验证等
 *      ExcelWriter	autoSizeColumn(int columnIndex) 设置某列为自动宽度,不考虑合并单元格
 *          此方法必须在指定列数据完全写出后调用才有效。
 *      ExcelWriter	autoSizeColumnAll() 设置所有列为自动宽度,不考虑合并单元格
 *          此方法必须在指定列数据完全写出后调用才有效。
 *          列数计算是通过第一行计算的
 *      org.apache.poi.ss.usermodel.Font	createFont() 创建字体
 *      ExcelBase.createCellStyle(int, int)
 *
 *      ExcelWriter	flush() 将Excel Workbook刷出到预定义的文件
 *      ExcelWriter	flush(File destFile) 将Excel Workbook刷出到文件
 *      ExcelWriter	flush(OutputStream out) 将Excel Workbook刷出到输出流
 *      ExcelWriter	flush(OutputStream out, boolean isCloseOut) 将Excel Workbook刷出到输出流
 *
 *      org.apache.poi.ss.usermodel.CellStyle	getCellStyle() 获取单元格样式,获取样式后可自定义样式
 *      int	getCurrentRow() 获得当前行
 *      String	getDisposition(String fileName, Charset charset) 获取Content-Disposition头对应的值,可
 *          以通过调用以下方法快速设置下载Excel的头信息
 *      org.apache.poi.ss.usermodel.CellStyle	getHeadCellStyle() 获取头部样式,获取样式后可自定义样式
 *
 *      StyleSet	getStyleSet() 获取样式集,样式集可以自定义包括 ☆☆☆☆☆
 *
 *      ExcelWriter	merge(int lastColumn) 合并当前行的单元格 样式为默认标题样式,可使用getHeadCellStyle()方法调用后自定义默认样式
 *      ExcelWriter	merge(int lastColumn, Object content) 合并当前行的单元格,并写入对象到单元格
 *      ExcelWriter	merge(int lastColumn, Object content, boolean isSetHeaderStyle)
 *      ExcelWriter	merge(int firstRow, int lastRow, int firstColumn, int lastColumn, Object content, boolean isSetHeaderStyle)
 *
 *      ExcelWriter	passCurrentRow() 跳过当前行
 *      ExcelWriter	passRows(int rows) 跳过指定行数
 *      ExcelWriter	renameSheet(int sheet, String sheetName) 重命名sheet
 *      ExcelWriter	renameSheet(String sheetName) 重命名当前sheet
 *      ExcelWriter	reset() 重置Writer
 *      ExcelWriter	resetRow() 重置当前行为0
 *
 *      ExcelWriter	setColumnWidth(int columnIndex, int width) 设置列宽(单位为一个字符的宽度,例如传入width为10,表示10个字符的宽度)
 *      ExcelWriter	setCurrentRow(int rowIndex) 设置当前所在行
 *      ExcelWriter	setCurrentRowToEnd() 定位到最后一行的后边,用于追加数据
 *      ExcelWriter	setDefaultRowHeight(int height) 设置默认行高,值为一个点的高度
 *      ExcelWriter	setDestFile(File destFile) 设置写出的目标文件
 *      ExcelWriter	setFreezePane(int rowSplit) 设置窗口冻结,之前冻结的窗口会被覆盖,如果rowSplit为0表示取消冻结
 *      ExcelWriter	setFreezePane(int colSplit, int rowSplit) 设置窗口冻结,之前冻结的窗口会被覆盖,如果colSplit和rowSplit为0表示取消冻结
 *      ExcelWriter	setHeaderAlias(Map<String,String> headerAlias) 设置标题别名,key为Map中的key,value为别名
 *      ExcelWriter	setHeaderOrFooter(String text, Align align, boolean isFooter) 设置Excel页眉或页脚
 *      ExcelWriter	setRowHeight(int rownum, int height) 设置行高,值为一个点的高度
 *      ExcelWriter	setRowStyle(int y, org.apache.poi.ss.usermodel.CellStyle style) 设置行样式
 *      ExcelWriter	setSheet(int sheetIndex) 自定义需要读取或写出的Sheet,如果给定的sheet不存在,创建之(命名为默认)
 *          在读取中,此方法用于切换读取的sheet,在写出时,此方法用于新建或者切换sheet
 *      ExcelWriter	setSheet(String sheetName)
 *      ExcelWriter	setStyleSet(StyleSet styleSet) 设置样式集,如果不使用样式,传入null
 *
 *      ExcelWriter	write(Iterable<?> data) 写出数据,本方法只是将数据写入Workbook中的Sheet,并不写出到文件
 *          写出的起始行为当前行号,可使用getCurrentRow()方法调用,根据写出的的行数,当前行号自动增加样式为默认样式,
 *          可使用getCellStyle()方法调用后自定义默认样式默认的,当当前行号为0时,写出标题(如果为Map或Bean),否则不写标题。
 *      ExcelWriter	write(Iterable<?> data, boolean isWriteKeyAsHead)
 *      ExcelWriter	writeCellValue(int x, int y, Object value) 给指定单元格赋值,使用默认单元格样式
 *      ExcelWriter	writeCellValue(String locationRef, Object value) 给指定单元格赋值,使用默认单元格样式
 *      ExcelWriter	writeHeadRow(Iterable<?> rowData) 写出一行标题数据
 *      ExcelWriter	writeRow(Iterable<?> rowData) 写出一行数据
 *      ExcelWriter	writeRow(Map<?,?> rowMap, boolean isWriteKeyAsHead) 将一个Map写入到Excel,isWriteKeyAsHead为true写出两行,
 *          Map的keys做为一行,values做为第二行,否则只写出一行values 如果rowMap为空(包括null),则写出空行。
 *      ExcelWriter	writeRow(Object rowBean, boolean isWriteKeyAsHead)
 *
 *
 * @Auther guofeng.xie
 * @Date 2020/11/15 16:10
 */
public class TestExcelWriter {
    /**
     * ExcelWriter类的使用
     *
     * Hutool针对将数据写出到Excel做了封装
     *
     * Hutool将Excel写出封装为ExcelWriter,原理为包装了Workbook对象,
     * 每次调用merge(合并单元格)或者write(写出数据)方法后只是将数据写入到Workbook,并不写出文件,
     * 只有调用flush或者close方法后才会真正写出文件。
     */

    //1. 将行列对象写出到Excel
    @Test
    public void testExcelWriter() {
        //① 我们先定义一个嵌套的List,List的元素也是一个List,内层的一个List代表一行数据,每行都有4个单元格,最终list对象代表多行数据。
        List<String> row1 = CollUtil.newArrayList("aa", "bb", "cc", "dd");
        List<String> row2 = CollUtil.newArrayList("aa1", "bb1", "cc1", "dd1");
        List<String> row3 = CollUtil.newArrayList("aa2", "bb2", "cc2", "dd2");
        List<String> row4 = CollUtil.newArrayList("aa3", "bb3", "cc3", "dd3");
        List<String> row5 = CollUtil.newArrayList("aa4", "bb4", "cc4", "dd4");
        List<List<String>> rows = CollUtil.newArrayList(row1, row2, row3, row4, row5);

        //② 然后我们创建ExcelWriter对象后写出数据
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter("E:/test/writeTest.xlsx");
        //通过构造方法创建writer
        //ExcelWriter writer = new ExcelWriter("d:/writeTest.xls");

        //跳过当前行,既第一行,非必须,在此演示用
        writer.passCurrentRow();

        //合并单元格后的标题行,使用默认标题样式
        writer.merge(row1.size() - 1, "测试标题");
        //一次性写出内容,强制输出标题
        writer.write(rows, true);
        //关闭writer,释放内存
        writer.close();
    }

    //2. 写出Map数据
    @Test
    public void testExcelWriter2() {
        //① 构造数据
        Map<String, Object> row1 = new LinkedHashMap<>();
        row1.put("姓名", "张三");
        row1.put("年龄", 23);
        row1.put("成绩", 88.32);
        row1.put("是否合格", true);
        row1.put("考试日期", DateUtil.date());

        Map<String, Object> row2 = new LinkedHashMap<>();
        row2.put("姓名", "李四");
        row2.put("年龄", 33);
        row2.put("成绩", 59.50);
        row2.put("是否合格", false);
        row2.put("考试日期", DateUtil.date());

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList(row1, row2);

        //② 写出数据
        // 通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter("E:/test/writeMapTest.xlsx");
        // 合并单元格后的标题行,使用默认标题样式
        writer.merge(row1.size() - 1, "一班成绩单");
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(rows, true);
        // 关闭writer,释放内存
        writer.close();
    }

    //3. 写出Bean数据
    @Test
    public void testExcelWriter3() {
        //② 构造数据
        TestBean bean1 = new TestBean();
        bean1.setName("张三");
        bean1.setAge(22);
        bean1.setPass(true);
        bean1.setScore(66.30);
        bean1.setExamDate(DateUtil.date());

        TestBean bean2 = new TestBean();
        bean2.setName("李四");
        bean2.setAge(28);
        bean2.setPass(false);
        bean2.setScore(38.50);
        bean2.setExamDate(DateUtil.date());

        List<TestBean> rows = CollUtil.newArrayList(bean1, bean2);

        //③ 写出数据
        // 通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter("E:/test/writeBeanTest.xlsx");
        // 合并单元格后的标题行,使用默认标题样式
        writer.merge(4, "一班成绩单");
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(rows, true);
        // 关闭writer,释放内存
        writer.close();
    }

    //① 定义Bean
    @Data
    public static class TestBean {
        private String name;
        private int age;
        private double score;
        private boolean isPass;
        private Date examDate;
    }

    //4. 自定义Bean的key别名(排序标题)
    //提示:
    // (since 4.1.5) 默认情况下Excel中写出Bean字段不能保证顺序,此时可以使用addHeaderAlias方法设置标题别名,
    // Bean的写出顺序就会按照标题别名的加入顺序排序。
    //如果不需要设置标题但是想要排序字段,请调用writer.addHeaderAlias("age", "age")设置一个相同的别名就可以不更换标题。
    // 未设置标题别名的字段不参与排序,会默认排在前面。
    @Test
    public void testExcelWriter4() {
        //① 构造数据
        TestBean bean1 = new TestBean();
        bean1.setName("张三");
        bean1.setAge(22);
        bean1.setPass(true);
        bean1.setScore(66.30);
        bean1.setExamDate(DateUtil.date());

        TestBean bean2 = new TestBean();
        bean2.setName("李四");
        bean2.setAge(28);
        bean2.setPass(false);
        bean2.setScore(38.50);
        bean2.setExamDate(DateUtil.date());

        List<TestBean> rows = CollUtil.newArrayList(bean1, bean2);

        //② 写出数据
        // 通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter("E:/test/writeBeanTest2.xlsx");

        //自定义标题别名
        writer.addHeaderAlias("name", "姓名");
        writer.addHeaderAlias("age", "年龄");
        writer.addHeaderAlias("score", "分数");
        writer.addHeaderAlias("isPass", "是否通过");
        writer.addHeaderAlias("examDate", "考试时间");

        // 合并单元格后的标题行,使用默认标题样式
        writer.merge(4, "一班成绩单");
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(rows, true);
        // 关闭writer,释放内存
        writer.close();
    }

    //5. 写出到流
    @Test
    public void testExcelWriter5() {
        //① 构造数据
        Map<String, Object> row1 = new LinkedHashMap<>();
        row1.put("姓名", "张三");
        row1.put("年龄", 23);
        row1.put("成绩", 88.32);
        row1.put("是否合格", true);
        row1.put("考试日期", DateUtil.date());

        Map<String, Object> row2 = new LinkedHashMap<>();
        row2.put("姓名", "李四");
        row2.put("年龄", 33);
        row2.put("成绩", 59.50);
        row2.put("是否合格", false);
        row2.put("考试日期", DateUtil.date());

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList(row1, row2);

        //② 写出数据到流
        // 通过工具类创建writer,默认创建xls格式
        ExcelWriter writer = ExcelUtil.getWriter();
        //创建xlsx格式的
        //ExcelWriter writer = ExcelUtil.getWriter(true);
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(rows, true);
        //out为OutputStream,需要写出到的目标流 ☆☆☆☆☆
        //writer.flush(out);
        // 关闭writer,释放内存
        writer.close();
    }

    //6.1 写出到客户端下载(写出到Servlet)
    //注意 ExcelUtil.getWriter()默认创建xls格式的Excel,因此写出到客户端也需要自定义文件名为XXX.xls,否则会出现文件损坏的提示。
    //若想生成xlsx格式,请使用ExcelUtil.getWriter(true)创建。
    @Test
    public void testExcelWriter61() {
        //① 构造数据
        TestBean bean1 = new TestBean();
        bean1.setName("张三");
        bean1.setAge(22);
        bean1.setPass(true);
        bean1.setScore(66.30);
        bean1.setExamDate(DateUtil.date());

        TestBean bean2 = new TestBean();
        bean2.setName("李四");
        bean2.setAge(28);
        bean2.setPass(false);
        bean2.setScore(38.50);
        bean2.setExamDate(DateUtil.date());

        List<TestBean> rows = CollUtil.newArrayList(bean1, bean2);

        //② 写出xls
        // 通过工具类创建writer,默认创建xls格式
        ExcelWriter writer = ExcelUtil.getWriter();
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(rows, true);
        //out为OutputStream,需要写出到的目标流

        //response为HttpServletResponse对象
        //response.setContentType("application/vnd.ms-excel;charset=utf-8");
        //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
        //response.setHeader("Content-Disposition","attachment;filename=test.xls");
        //ServletOutputStream out=response.getOutputStream();

        //writer.flush(out, true);
        // 关闭writer,释放内存
        writer.close();
        //此处记得关闭输出Servlet流
        //IoUtil.close(out);
    }

    //6.2 写出xlsx
    @Test
    public void testExcelWriter62() {
        //① 构造数据
        TestBean bean1 = new TestBean();
        bean1.setName("张三");
        bean1.setAge(22);
        bean1.setPass(true);
        bean1.setScore(66.30);
        bean1.setExamDate(DateUtil.date());

        TestBean bean2 = new TestBean();
        bean2.setName("李四");
        bean2.setAge(28);
        bean2.setPass(false);
        bean2.setScore(38.50);
        bean2.setExamDate(DateUtil.date());

        List<TestBean> rows = CollUtil.newArrayList(bean1, bean2);

        //写出xlsx
        ExcelWriter writer = ExcelUtil.getWriter(true);
        writer.write(rows, true);

        //response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        //response.setHeader("Content-Disposition","attachment;filename=test.xlsx");

        //writer.flush(out, true);
        writer.close();
        //IoUtil.close(out);
    }

    /**
     * 自定义Excel
     *
     * 设置单元格背景色
     */
    @Test
    public void testExcelWriter7() {
        //1. 构造数据
        Map<String, Object> row1 = new LinkedHashMap<>();
        row1.put("姓名", "张三");
        row1.put("年龄", 23);
        row1.put("成绩", 88.32);
        row1.put("是否合格", true);
        row1.put("考试日期", DateUtil.date());

        Map<String, Object> row2 = new LinkedHashMap<>();
        row2.put("姓名", "李四");
        row2.put("年龄", 33);
        row2.put("成绩", 59.50);
        row2.put("是否合格", false);
        row2.put("考试日期", DateUtil.date());

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList(row1, row2);

        //2. 设置单元格背景色
        //ExcelWriter writer = ExcelUtil.getWriter();
        // 通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriter("E:/test/writeStyleTest.xlsx");
        // 合并单元格后的标题行
        writer.merge(row1.size() - 1, "一班成绩单");

        // 定义单元格背景色
        StyleSet style = writer.getStyleSet();
        // 第二个参数表示是否也设置头部单元格背景
        style.setBackgroundColor(IndexedColors.RED, false);

        // 一次性写出内容,强制输出标题
        writer.write(rows, true);
        // 关闭writer,释放内存
        writer.close();
    }

    /**
     * 自定义Excel
     *
     * 自定义字体
     */
    @Test
    public void testExcelWriter8() {
        //1. 构造数据
        Map<String, Object> row1 = new LinkedHashMap<>();
        row1.put("姓名", "张三");
        row1.put("年龄", 23);
        row1.put("成绩", 88.32);
        row1.put("是否合格", true);
        row1.put("考试日期", DateUtil.date());

        Map<String, Object> row2 = new LinkedHashMap<>();
        row2.put("姓名", "李四");
        row2.put("年龄", 33);
        row2.put("成绩", 59.50);
        row2.put("是否合格", false);
        row2.put("考试日期", DateUtil.date());

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList(row1, row2);

        //2. 自定义字体
        ExcelWriter writer = ExcelUtil.getWriter("E:/test/writeStyleFontTest.xlsx");
        //设置内容字体
        Font font = writer.createFont();
        font.setBold(true);
        font.setColor(Font.COLOR_RED);
        font.setItalic(true);
        //第二个参数表示是否忽略头部样式
        writer.getStyleSet().setFont(font, true);

        // 一次性写出内容,强制输出标题
        writer.write(rows, true);
        // 关闭writer,释放内存
        writer.close();
    }

    /**
     * 自定义Excel
     *
     * 写出多个sheet
     */
    @Test
    public void testExcelWriter9() {
        //1. 构造数据
        Map<String, Object> row1 = new LinkedHashMap<>();
        row1.put("姓名", "张三");
        row1.put("年龄", 23);
        row1.put("成绩", 88.32);
        row1.put("是否合格", true);
        row1.put("考试日期", DateUtil.date());

        Map<String, Object> row2 = new LinkedHashMap<>();
        row2.put("姓名", "李四");
        row2.put("年龄", 33);
        row2.put("成绩", 59.50);
        row2.put("是否合格", false);
        row2.put("考试日期", DateUtil.date());

        ArrayList<Map<String, Object>> rows = CollUtil.newArrayList(row1, row2);

        //2. 写出多个sheet
        //初始化时定义表名
        ExcelWriter writer = new ExcelWriter("E:/test/writeSheetTest.xlsx", "表1");
        // 一次性写出内容,强制输出标题
        writer.write(rows, true);

        //切换sheet,此时从第0行开始写
        writer.setSheet("表2");
        writer.setSheet("表3");

        // 关闭writer,释放内存
        writer.close();
    }

    /**
     * 自定义Excel
     *
     * 更详细的定义样式
     *
     * 在Excel中,由于样式对象个数有限制,因此Hutool根据样式种类分为4个样式对象,使相同类型的单元格可以共享样式对象。
     * 样式按照类别存在于StyleSet中,其中包括:
     *  1. 头部样式 headCellStyle
     *  2. 普通单元格样式 cellStyle
     *  3. 数字单元格样式 cellStyleForNumber
     *  4. 日期单元格样式 cellStyleForDate
     *
     * 其中cellStyleForNumber cellStyleForDate用于控制数字和日期的显示方式。
     */
    @Test
    public void testExcelWriter10() {
        // 通过工具类创建writer,默认创建xls格式
        ExcelWriter writer = ExcelUtil.getWriter();

        //因此我们可以使用以下方式获取CellStyle对象自定义指定种类的样式:
        StyleSet style = writer.getStyleSet();
        CellStyle cellStyle = style.getHeadCellStyle();
        //TODO
    }
}

 

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值