前言:
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 上有 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月底发布),本篇的分享希望可以帮助到有需要的朋友。
如有不正确的地方欢迎各位指出纠正。