Spring Boot 集成 EasyExcel 导出 Excel 文件【复杂表头】

发布于:2025-03-01 ⋅ 阅读:(8) ⋅ 点赞:(0)

前言:

Excel 导出在项目开发中是一个非常常见的业务场景,通过 Java 相关的类库可以轻松实现 Excel 的读写操作,常见的类库有 Apache POI、EasyPoi 和 EasyExcel,本篇我们要分享的是使用 EasyExcel 完成复杂表头的 Excel 导出,希望可以帮助到有需要的朋友。

模拟业务场景

假设有一个 Excel 的导出需求,表头如下:

在这里插入图片描述

对于这种比较复杂的表头如果实用 Apache POI 来实现会比较的麻烦,这里我们使用 EasyExcel 来实现,将会比较简单。

Spring Boot 集成 EasyExcel

Spring Boot 集成 EasyExcel 其实就是引入依赖即可使用,pom.xml 引入依赖如下:

<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>easyexcel</artifactId>
	<version>3.2.1</version>
</dependency>

EasyExcel Github 地址

EasyExcel 在 Github 上有 33K Stars,是阿里巴巴开源的,但很遗憾,最近宣布停更了,未来将逐步进入维护模式,将继续修复 Bug,但不再主动新增功能,据了解,EasyExcel 作者玉箫去年已经从阿里离职,最近他宣布启动 EasyExcel-Plus 项目,称这个新版本将在原有的基础上进一步提升性能和扩展功能。

创建 VO 类

在字段名上加上 @ExcelProperty 注解就可以实现上面我们这种较为复杂的 Excel 表头,创建实体类如下:

package com.my.study.pojo.vo;

import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * @ClassName: InterviewInformationVO
 * @Author: Author
 * @Date: 2024/11/13 19:31
 * @Description:
 */
@Data
@ColumnWidth(20)
public class InterviewInformationVO {

    @ApiModelProperty("姓名")
    @ExcelProperty(index = 0, value = {"面试记录表", "姓名"})
    @ColumnWidth(15)
    private String name;

    @ApiModelProperty("年龄")
    @ExcelProperty(index = 1, value = {"面试记录表", "基本信息", "年龄"})
    @ColumnWidth(15)
    private int age;

    @ApiModelProperty("性别")
    @ExcelProperty(index = 2, value = {"面试记录表", "基本信息", "性别"})
    @ColumnWidth(15)
    private String sex;

    @ApiModelProperty("籍贯")
    @ExcelProperty(index = 3, value = {"面试记录表", "基本信息", "籍贯"})
    @ColumnWidth(15)
    private String nativePlace;

    @ApiModelProperty("自我评价")
    @ExcelProperty(index = 4, value = {"面试记录表", "自我评价"})
    @ColumnWidth(15)
    private String selfEvaluation;

    @ApiModelProperty("沟通能力分")
    @ExcelProperty(index = 5, value = {"面试记录表", "一轮面试","面试官A","沟通能力分"})
    @ColumnWidth(15)
    private int cmmunicationAkillsScore1A;

    @ApiModelProperty("专业能力分")
    @ExcelProperty(index = 6, value = {"面试记录表", "一轮面试","面试官A","专业能力分"})
    @ColumnWidth(15)
    private int professionalAbilityScore1A;

    @ApiModelProperty("沟通能力分")
    @ExcelProperty(index = 7, value = {"面试记录表", "一轮面试","面试官B","沟通能力分"})
    @ColumnWidth(15)
    private int cmmunicationAkillsScore1B;

    @ApiModelProperty("专业能力分")
    @ExcelProperty(index = 8, value = {"面试记录表", "一轮面试","面试官B","专业能力分"})
    @ColumnWidth(15)
    private int professionalAbilityScore1B;

    @ApiModelProperty("沟通能力分")
    @ExcelProperty(index = 9, value = {"面试记录表", "二轮面试","面试官A","沟通能力分"})
    @ColumnWidth(15)
    private int cmmunicationAkillsScore2A;

    @ApiModelProperty("专业能力分")
    @ExcelProperty(index = 10, value = {"面试记录表", "二轮面试","面试官A","专业能力分"})
    @ColumnWidth(15)
    private int professionalAbilityScore2A;

    @ApiModelProperty("沟通能力分")
    @ExcelProperty(index = 11, value = {"面试记录表", "二轮面试","面试官B","沟通能力分"})
    @ColumnWidth(15)
    private int cmmunicationAkillsScore2B;

    @ApiModelProperty("专业能力分")
    @ExcelProperty(index = 12, value = {"面试记录表", "二轮面试","面试官B","专业能力分"})
    @ColumnWidth(15)
    private int professionalAbilityScore2B;


}

注意看我使用在段上的注解 @ExcelProperty(index = 5, value = {“面试记录表”, “一轮面试”,“面试官A”,“沟通能力分”}),这简单的一行就实现了表头的合并处理。

导出代码

导出我们选择使用输出流的方式直接返回,当然也可以导出到指定位置,代码如下:

package com.my.study.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.my.study.pojo.vo.InterviewInformationVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @ClassName: MyExcelController
 * @Author: Author
 * @Date: 2024/11/13 19:19
 * @Description:
 */
@RestController
@RequestMapping("/excel")
@Api(tags = {"【Excel 导出控制层】"})
@Slf4j
public class MyExcelController {


    @PostMapping("/export")
    public void export(HttpServletResponse response) {
        try {
            List<InterviewInformationVO> exportList = new ArrayList<>();
            buildInterviewInformation(exportList);
            // 文件名中文名需要转义
            String fileName = URLEncoder.encode("面试记录表-" + DateUtil.format(new Date(), "yyyyMMddHHmmss"), "UTF-8");
            response.setContentType("application/x-download;charset=utf-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            EasyExcel.write(response.getOutputStream(), InterviewInformationVO.class).sheet("sheet1").doWrite(exportList);
        } catch (IOException e) {
            log.error("面试记录表导出失败,失败原因:{}", e.getMessage());
            e.printStackTrace();
        }
    }

    public void buildInterviewInformation(List<InterviewInformationVO> exportList) {
        InterviewInformationVO interviewInformationVO = new InterviewInformationVO();
        interviewInformationVO.setName("张三");
        interviewInformationVO.setAge(25);
        interviewInformationVO.setSex("男");
        interviewInformationVO.setNativePlace("湖北");
        interviewInformationVO.setSelfEvaluation("我是一个工作狂");
        interviewInformationVO.setCmmunicationAkillsScore1A(90);
        interviewInformationVO.setCmmunicationAkillsScore1B(85);
        interviewInformationVO.setProfessionalAbilityScore1A(90);
        interviewInformationVO.setProfessionalAbilityScore1B(90);
        interviewInformationVO.setCmmunicationAkillsScore1A(85);
        interviewInformationVO.setCmmunicationAkillsScore1B(80);
        interviewInformationVO.setProfessionalAbilityScore1A(75);
        interviewInformationVO.setProfessionalAbilityScore1B(80);
        exportList.add(interviewInformationVO);
    }
	
}

触发导出,效果如下:

在这里插入图片描述

实现了我们开始说的表头效果,导出结果符合预期。

我们并没有写多少代码,就完成了看起来比较复杂的表头,这就是 EasyExcel 带来效果,当前 EasyExcel 在内存管理上也有显著的优势。

方式二实现表头

上面我们使用注解的方式实现了表头效果,下面我们使用代码的方式完成表头功能,代码如下:

package com.my.study.controller;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.EasyExcel;
import com.my.study.pojo.vo.InterviewInformationVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @ClassName: MyExcelController
 * @Author: Author
 * @Date: 2024/11/13 19:19
 * @Description:
 */
@RestController
@RequestMapping("/excel")
@Api(tags = {"【Excel 导出控制层】"})
@Slf4j
public class MyExcelController {


   @PostMapping("/export2")
    public void export(HttpServletResponse response) {
        try {
            List<InterviewInformationVO> exportList = new ArrayList<>();
            buildInterviewInformation(exportList);
            // 文件名中文名需要转义
            String fileName = URLEncoder.encode("面试记录表-" + DateUtil.format(new Date(), "yyyyMMddHHmmss"), "UTF-8");
            response.setContentType("application/x-download;charset=utf-8");
            response.addHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
            //EasyExcel.write(response.getOutputStream(), InterviewInformationVO.class).sheet("sheet1").doWrite(exportList);
            EasyExcel.write(response.getOutputStream())
                    // 这里放入动态头
                    .head(generateExcelHead())
                    .sheet()
                    // 这里传入数据
                    .doWrite(new ArrayList<>());
            //导出到指定位置
            /*EasyExcel.write("d:\interview_information.xlsx")
                    // 这里放入动态头
                    .head(generateExcelHead())
                    .sheet()
                    // 这里传入数据
                    .doWrite(new ArrayList<>());*/
        } catch (IOException e) {
            log.error("面试记录表导出失败,失败原因:{}", e.getMessage());
            e.printStackTrace();
        }
    }

    private static List<List<String>> generateExcelHead() {
        List<List<String>> result = new ArrayList<>();
        List<String> head0 = new ArrayList<>();
        head0.add("面试记录表");
        head0.add("姓名");
        result.add(head0);

        List<String> head1 = new ArrayList<>();
        head1.add("面试记录表");
        head1.add("基本信息");
        head1.add("年龄");
        result.add(head1);

        List<String> head2 = new ArrayList<>();
        head2.add("面试记录表");
        head2.add("基本信息");
        head2.add("性别");
        result.add(head2);

        List<String> head3 = new ArrayList<>();
        head3.add("面试记录表");
        head3.add("基本信息");
        head3.add("籍贯");
        result.add(head3);

        List<String> head4 = new ArrayList<>();
        head4.add("面试记录表");
        head4.add("自我评价");
        result.add(head4);

        List<String> head5 = new ArrayList<>();
        head5.add("面试记录表");
        head5.add("一轮面试");
        head5.add("面试官A");
        head5.add("沟通能力分");
        result.add(head5);

        List<String> head6 = new ArrayList<>();
        head6.add("面试记录表");
        head6.add("一轮面试");
        head6.add("面试官A");
        head6.add("专业能力分");
        result.add(head6);

        List<String> head7 = new ArrayList<>();
        head7.add("面试记录表");
        head7.add("一轮面试");
        head7.add("面试官B");
        head7.add("沟通能力分");
        result.add(head7);

        List<String> head8 = new ArrayList<>();
        head8.add("面试记录表");
        head8.add("一轮面试");
        head8.add("面试官B");
        head8.add("专业能力分");
        result.add(head8);

        List<String> head9 = new ArrayList<>();
        head9.add("面试记录表");
        head9.add("二轮面试");
        head9.add("面试官A");
        head9.add("沟通能力分");
        result.add(head9);

        List<String> head10 = new ArrayList<>();
        head10.add("面试记录表");
        head10.add("二轮面试");
        head10.add("面试官A");
        head10.add("专业能力分");
        result.add(head10);

        List<String> head11 = new ArrayList<>();
        head11.add("面试记录表");
        head11.add("二轮面试");
        head11.add("面试官B");
        head11.add("沟通能力分");
        result.add(head11);

        List<String> head12 = new ArrayList<>();
        head12.add("面试记录表");
        head12.add("二轮面试");
        head12.add("面试官B");
        head12.add("专业能力分");
        result.add(head12);

        return result;
    }
	
}

触发导出结果如下:

在这里插入图片描述

导出结果符合预期,使用代码来实现表头也很容易,但个人更喜欢使用注解来实现。

总结:本篇简单分享使用 EasyExcel 来实现较为复杂的表头导出 Excel,感谢 EasyExcel 作者的开源,也期待 EasyExcel-Plus 的发布(预计 11月底发布),本篇的分享希望可以帮助到有需要的朋友。

如有不正确的地方欢迎各位指出纠正。