EasyExcel 导出简单应用(文章末附demo下载地址)
应用场景: 主从表单中,用户想定制excel导出数据。看过一点Apache poi,一般人上手还是要花一些时间,且Apache poi做Excel的一些处理存在内存溢出等缺陷。相对于Apache poi存在明显的优势就是上手块,且内存占用小,故采用EasyExcel。
EasyExcel官网
基于EasyExcel实现Excel导出下载
准备:
- SpringBoot + JPA + lombok
- EasyExcel(最新maven依赖)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.1.2</version>
</dependency>
- 数据库Mysql
- Student学生表 (建表sql)
CREATE TABLE `student` (
`id` bigint NOT NULL AUTO_INCREMENT,
`username` varchar(100) DEFAULT NULL,
`age` int DEFAULT NULL,
`attendtime` datetime DEFAULT NULL,
`address` varchar(256) DEFAULT NULL,
`schoolclass` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
- Excel模板文件
模板下载
模板参数说明:
- 大括号“{}” 引用的参数就是后面导出Excel需要填充的参数
- 英文句号“.”表示该填充数据可能多条,则此时会自动填充换行
- Excel中样式(行高 列宽等)及颜色会在导出时一并设置成和模板一致(这种调试样式就可以直接在Excel中进行调试,再将模板放到服务器指定位置,避免在代码中进行繁琐的样式设置操作)
相关类说明
1. Student基类
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Entity
@Table(name = "student")
public class Student implements Serializable {
/**
* 主键id也是序号,由于数据库序号设置的自增
*/
@GeneratedValue(strategy= GenerationType.IDENTITY)
@Id
private Long id;
private String username;
private int age;
/**
* 入学时间,设置java.sql.Timestamp类型,便于后面自定义Convert类时对格式进行转换
*/
private Timestamp attendtime;
private String address;
private int schoolclass;
}
注:@GeneratedValue(strategy= GenerationType.IDENTITY) 采用数据库ID自增长的方式来自增主键字段
2. 构造导出Excel方法
/**
* 设置web响应输出的文件名称
* @param response web响应
* @param fileName 导出文件名称
*/
private static void setResponseHeader(HttpServletResponse response, String fileName) {
response.reset();
response.setContentType("application/vnd.ms-excel;charset=utf-8");
try {
response.setHeader("Content-Disposition", "attachment;filename=" +
URLEncoder.encode(fileName + ".xlsx", "UTF-8"));
} catch (UnsupportedEncodingException e) {
log.error("不支持的编码", e.getLocalizedMessage());
}
response.setCharacterEncoding("UTF-8");
}
public static void exportStudedntExcel(HttpServletResponse response, HashMap<String,Object> datas,String fileName) throws IOException{
setResponseHeader(response, fileName);
//未获取到数据时
if (datas.get("data") == null){
return;
}
ExcelWriter workbook= null;
BufferedOutputStream bos = new BufferedOutputStream(response.getOutputStream());
try{
String template="student_fill_template.xlsx";
//日期转化格式字符串
TimestampStringConverter converter = new TimestampStringConverter();
workbook = EasyExcel.write(bos).registerConverter(converter).withTemplate(template).build();
WriteSheet sheet = EasyExcel.writerSheet("Sheet1").build();
FillConfig fillConfig = FillConfig.builder().forceNewRow(true).build();
//填充议题数据
workbook.fill(datas.get("data"),fillConfig,sheet);
//datas.remove("data");
//获取副标题及角标
HashMap<String,Object> map = new LinkedHashMap<>();
map.put("schoolclass",datas.get("schoolclass"));
map.put("exporttime",datas.get("exporttime"));
//填充角标及标题数据
workbook.fill(map,sheet);
}catch (Throwable ex){
log.error("exportMeetExcel",ex.getMessage());
}finally {
bos.flush();
if (workbook != null){
workbook.finish();
}
}
}
- setResponseHeader 设置Excel下载的请求头格式及文件名
- workbook = EasyExcel.write(bos, Student.class).withTemplate(template).build();
- withTemplate(template) 根据模板Excel构造一个工作簿
- .build() 构造生成ExcelWriter时要手动释放资源,而不使用build生成的ExcelWriterBuilder对象会自动释放资源,这里使用ExcelWriter对象是因为此deno中到向模板填充的数据需要多次进行填充,若使用ExcelWriterBuilder一次使用后就自动释放资源,导致后面的填充失败!
- TimestampStringConverter 自定义对象见下一节
- FillConfig 对象用于填充数据时的一些设置,比如此处,由于学生信息数据行是多行数据,forceNewRow(true)作用是在末尾新增,如若不进行此项操作,则最后一行的导出时间填充时会覆盖模板位置的值
3.Timestamp日期格式自定义转换器类TimestampStringConverter
public class TimestampStringConverter implements Converter<Timestamp> {
@Override
public Class<?> supportJavaTypeKey() {
return Timestamp.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public WriteCellData<?> convertToExcelData(Timestamp value, ExcelContentProperty contentProperty,
GlobalConfiguration globalConfiguration) {
WriteCellData cellData = new WriteCellData();
String cellValue;
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
cellValue = DateUtils.format(value.toLocalDateTime(), "yyyy年MM月dd日", globalConfiguration.getLocale());
} else {
cellValue = DateUtils.format(value.toLocalDateTime(), contentProperty.getDateTimeFormatProperty().getFormat(),
globalConfiguration.getLocale());
}
cellData.setType(CellDataTypeEnum.STRING);
cellData.setStringValue(cellValue);
cellData.setData(cellValue);
return cellData;
}
}
- convertToExcelData 方法中 value为数据中为Timestamp类型的值,此处我获取Timestamp 将时间戳转化为yyyy年MM月dd日的字符串格式,在创建工作簿的时候使用registerConverter将转换器注册到工作簿中。
- 若只想转换该类型的某个实体属性的值,可以借助 @ExcelProperty 注解,添加 converter 属性,如:
@ExcelProperty(value = "入学时间", converter = TimestampStringConverter.class)
private Timestamp attendtime;
工程创建说明
该工程是基于SpringBoot + Jpa的一个从数据库导出Excel的案例,所以在创建工程时可以直接通过Spring Initializr创建一个web工程并导入对应包
本工程目录说明
student_fill_template.xlsx 为Excel模板,注意放置位置
该工程有两个接口
POST:http://127.0.0.1:8080/init 向student表中初始化学生信息
GET:http://127.0.0.1:8080/export/{classno} 从学生student表中导出学生信息以excel的形式保存,其中classno是班级编号,1-9,对应枚举如下:
One("高一一班",1),Two("高一二班",2),Three("高一三班",3),
Four("高二一班",4),Five("高二二班",5),Six("高二三班",6),
Seven("高三一班",5),Eight("高三二班",8),Nine("高三三班",9);