Spring Boot:基于Easyexcel实现不同场景的导出功能(二)

原创 凡夫贩夫 凡夫贬夫 2024-01-21 10:20 发表于河南

图片

前言

如果你正在寻找一种高效、易用的Spring Boot项目的导出解决方案,那么这篇关于基于Easyexcel实现不同场景的导出功能的技术文章恰好符合你的需求。文章深入浅出地介绍了如何使用Easyexcel来实现导出功能,并提供了多种不同场景下的实战案例,无论是初学者还是有经验的开发者都能受益匪浅。不要错过这篇值得一读的技术文章!

凡夫贬夫

CSDN博客专家、高级Java开发工程师,专注Java技术干货分享,如果对我感兴趣,那就关注我吧!

98篇原创内容

公众号

导出的数据包含有图片

导出excel表格的数据包含有图片,这种场景比较少。通Easyexcel实现这样的需求,我认为最简便的方法就是使用前面提到的自定义转换器(com.alibaba.excel.converters.Converter);假如有这样一个场景,导出员工的信息,还要包括员工的一寸照。通常情况下,数据库并不会真的存一张图片,而是图片存储位置的相对路径。

1、新建一个类EmpHeadPhotoConverter,实现com.alibaba.excel.converters.Converter接口,并重写convertToExcelData()方法;

2、在重写convertToExcelData()方法中,根据图片的相同路径或网络地址读取出图片的字节流作为构建WriteCellData对象的参数然后返回;

3、在员工信息的实体类Employee的照片列引入自定义的类型转换器(EmpHeadPhotoConverter)

4、使用EasyExcel的工厂方法把数据写出到excel表格中;

注:这里是使用默认的样式,所以看起来可能点丑;@ContentRowHeight()用于调节数据行的高度;@ColumnWidth用于调节数据列的宽度;

public class EmpHeadPhotoConverter implements Converter<String> {    @Override    public WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {        //根据图片的相对路径或网络地址读取图片到byte输出流(ByteArrayOutputStream)        ByteArrayOutputStream byteArrayOutputStream = null;        InputStream inputStream=null;        try {             inputStream = ClassLoader.getSystemResourceAsStream(value);            byteArrayOutputStream = new ByteArrayOutputStream();            int len=-1;            byte[] bytes = new byte[1024];            while ((len=inputStream.read(bytes))!=-1){                byteArrayOutputStream.write(bytes);            }        } catch (IOException e) {            e.printStackTrace();        } finally {            if (byteArrayOutputStream != null) {                byteArrayOutputStream.close();            }            if (inputStream != null) {                inputStream.close();            }        }        //把输出流中的图片字节数组作为参数构建writeCellData对象并返回        //WriteCellData是EasyExcel对单元格数据的封装        return  new WriteCellData<>(byteArrayOutputStream.toByteArray());    }}
@Data@ContentRowHeight(50)//数据行的高度public class Employee implements Serializable {    @ExcelProperty("姓名")    private String realName;    @ExcelProperty("员工编号")    private String empNo;    @ExcelProperty("性别")    private String sex;    @ExcelProperty("家庭地址")    private String address;    @ExcelProperty("联系电话")    private String phone;    @ExcelProperty("电子邮箱")    private String email;    @ExcelProperty(value = "照片",converter = EmpHeadPhotoConverter.class)    @ColumnWidth(10)//列宽    private String headPhoto;}
@Testpublic void writeImage(){    String exportPath=this.getExportPath();    String exportFile=exportPath+File.separator+"员工基本信息(包含照片).xlsx";    List<Employee> list = new ArrayList<>();    for (int i = 0; i < 3; i++) {        Employee employee = new Employee();        employee.setRealName("张三"+i);        employee.setEmpNo("CH"+(i+1));        employee.setAddress("北京");        employee.setEmpNo("[email protected]");        employee.setSex("女");        employee.setPhone("17777xxxxxx");        //这里是示例,因为我把示例图片放在了classpath下,后面可以根据图片名字在classpath下找到        //在实际的业务开发过程中,这里应该是图片的相对路径或网络地址        employee.setHeadPhoto("zhangsan.jpeg");        list.add(employee);    }    EasyExcel.write(exportFile,Employee.class).sheet().doWrite(list);}

图片

导出表格指定列宽、行高

上面其实是已经说过了,通过注解可以简单的指定导出Excel表格的行、列的高度和宽度:

@ContentRowHeight()用于指定数据行的高度;

@HeadRowHeight()用于指定表头行的高度;

@ColumnWidth()用于指定数据列的宽度;

导出表格自定义样式

我比较喜欢使用easyexcel的一个很重要的原因就是,easyexcel在poi的基础上,封装的比较友好。就比如,在导出的时候,很多情况下需要自定义表格的样式,easyexcel就提供了多种的实现方式。主要有三种:

1、通过注解;

2、编程式;

3、自定义类型转换器。

不同的方式,侧重的场景也有所不同,下面通过示例梳理一下使用方法:

编程式自定义样式

通过编程式来自定义导出表格的样式中,有一个非常关键类HorizontalCellStyleStrategy。

1、通过HorizontalCellStyleStrategy可以配置好表头的样式和数据行的样式;

2、使用Easyexcel的工厂方法写出数据前,把通过HorizontalCellStyleStrategy构建好的样式策略注册到表格写出构建器里;

3、使用使用Easyexcel的工厂方法写出数据;

总结:这种方法的优点就是比较简单,且容易理解构建样式的过程;缺点就是不太灵活;比较适合那些导出表格前可以明确知道导出的表格的样式特点;

@Testpublic void writeWithStyle2() {    String exportPath = this.getExportPath();    String exportFile = exportPath + File.separator + "员工基本信息v2.xlsx";    List<Employee> list = new ArrayList<>();    Employee employee = new Employee();    employee.setRealName("张三");    employee.setEmpNo("CH001");    employee.setSex("女");    Employee employee2 = new Employee();    employee2.setRealName("李四");    employee2.setEmpNo("CH002");    employee2.setSex("男");    list.add(employee);    list.add(employee2);    // 头的策略    WriteCellStyle headWriteCellStyle = new WriteCellStyle();    // 背景设置为红色    headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());    WriteFont headWriteFont = new WriteFont();    headWriteFont.setFontHeightInPoints((short)20);    headWriteCellStyle.setWriteFont(headWriteFont);    // 内容的策略    WriteCellStyle contentWriteCellStyle = new WriteCellStyle();    // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定    contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);    // 背景绿色    contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());    WriteFont contentWriteFont = new WriteFont();    // 字体大小    contentWriteFont.setFontHeightInPoints((short)20);    contentWriteCellStyle.setWriteFont(contentWriteFont);    // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现    HorizontalCellStyleStrategy horizontalCellStyleStrategy =            new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
    // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭    EasyExcel.write(exportFile, Employee.class)            .registerWriteHandler(horizontalCellStyleStrategy)            .sheet()            .doWrite(list);}

注解形式自定义样式

通过注解的形式来自定义导出表格的样式,和编程式的比较类似,明显的区别是一个需要通过在编写代码来定义样式并应用这个样式;另一个是需要 使用注解定义好表格样式,应用样式的过程easyexcel内部已经实现了,不用自己编写代码来实现。总体上特点是一样的:使用简单,且比较好理解,缺点就是不灵活,不能动态的设置导出表格内单元格的样式。比较常用的注解有以下(有的是作用在类上,有的是作用在属性上,注解需要设置哪些属性可以点以注解的源里一看就很清楚):

作用在类上:

@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10)// 头字体设置成20@HeadFontStyle(fontHeightInPoints = 20)// 内容的背景设置成绿色 IndexedColors.GREEN.getIndex()@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17)// 内容字体设置成20@ContentFontStyle(fontHeightInPoints = 20)

作用在属性上

// 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex()@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14)// 字符串的头字体设置成20@HeadFontStyle(fontHeightInPoints = 30)// 字符串的内容的背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex()@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40)// 字符串的内容字体设置成20@ContentFontStyle(fontHeightInPoints = 30)

自定义类型转换器形式定义样式

前两种的样式定义方法,都比较固定,不能根据导出数据的规则来动态设置表格内单元格的样式,如导出员工信息表格里如果性别是女的员工数据行,则使用红色字体,如果是男性,则是使用蓝色;因为导出数据通常是从数据源里动态取出的,在导出前没办法确定哪些行是男性,哪些员工是女性,所以需要动态的设置导出表格的样式,自定义类型转换器就可以很好的解决这个问题。

1、新建一个类SexColourConverter,实现com.alibaba.excel.converters.Converter接口,并重写convertToExcelData()方法;

2、重写convertToExcelData()方法中,根据单元格的内容设置不同的样式,示例中:如果性别是男,则字体为蓝色;如果性别是女,则字体颜色是红色;

3、在员工信息的实体类Employee的性别(sex)属性上,通过@ExcelProperty()引入自定义的类型转换器SexColourConverter;

4、使用Easyexcel的工厂方法实现表格数据的写出;

总结:这种方法很灵活,非常适合一些报表中,要求导出表格中数据达到在不同规则就要求有不同的样式的场景。在我做过的项目里,有不少导出都有类似的规则:某个属性达到预警阈值时,要导出数据的单元格格式标成红色。

public class SexColourConverter implements Converter<String> {    @Override    public WriteCellData<?> convertToExcelData(String value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {        WriteCellStyle writeCellStyle = new WriteCellStyle();        WriteFont writeFont = new WriteFont();        if ("男".equals(value)) {            writeFont.setColor((short) 12);        }        if ("女".equals(value)) {            writeFont.setColor((short) 10);        }        writeCellStyle.setWriteFont(writeFont);        WriteCellData<Object> cellData = new WriteCellData<>();        cellData.setWriteCellStyle(writeCellStyle);        cellData.setType(CellDataTypeEnum.STRING);        cellData.setStringValue(value);        return cellData;    }}
@Datapublic class Employee implements Serializable {    @ExcelProperty("姓名")    private String realName;    @ExcelProperty("员工编号")    private String empNo;    @ExcelProperty(value = "性别",converter = SexColourConverter.class)    private String sex;}@Testpublic void writeWithStyle() {    String exportPath = this.getExportPath();    String exportFile = exportPath + File.separator + "员工基本信息v2.xlsx";    List<Employee> list = new ArrayList<>();    Employee employee = new Employee();    employee.setRealName("张三");    employee.setEmpNo("CH001");    employee.setSex("女");    Employee employee2 = new Employee();    employee2.setRealName("李四");    employee2.setEmpNo("CH002");    employee2.setSex("男");    list.add(employee);    list.add(employee2);    EasyExcel.write(exportFile, Employee.class).sheet().doWrite(list);}

在设置单元格背景或字体的颜色的时候,颜色会对应一个short类型的数据,下面就具体对应关系:

图片

凡夫贬夫

CSDN博客专家、高级Java开发工程师,专注Java技术干货分享,如果对我感兴趣,那就关注我吧!

98篇原创内容

公众号