SpringBoot+EasyExcel导入导出加水印
Posted 经理,天台风好大
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot+EasyExcel导入导出加水印相关的知识,希望对你有一定的参考价值。
本篇文章内容是针对于接口开发~~
背景
老项目主要采用的POI框架来进行Excel数据的导入和导出,但经常会出现OOM的情况,导致整个服务不可用。后续逐步转移到EasyExcel。
一、EasyExcel介绍
EasyExcel是阿里巴巴开源poi插件之一,主要解决了poi框架使用复杂,sax解析模式不容易操作,数据量大起来容易OOM,解决了POI并发造成的报错。
主要解决方式:通过解压文件的方式加载,一行一行的加载,并且抛弃样式字体等不重要的数据,降低内存的占用。
EasyExcel优势:
- 注解式自定义操作。
- 输入输出简单,提供输入输出过程的接口
- 支持一定程度的单元格合并等灵活化操作
其他详细介绍参考官网
二、案例配置
2.1 依赖
<!-- 后续给Excel加水印的时候会用到 -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>ooxml-schemas</artifactId>
<version>1.0</version>
</dependency>
<!--easyExcel-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.11</version>
</dependency>
<!-- hutool -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.4.0</version>
</dependency>
<!-- web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
其他所需依赖自行添加
2.2 导入导出的实体类
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Member
/**
* EasyExcel使用:导出时忽略该字段
*/
@ExcelIgnore
private Integer id;
@ExcelProperty("用户名")
@ColumnWidth(20)
private String username;
/**
* EasyExcel使用:日期的格式化
*/
@ColumnWidth(20)
@ExcelProperty("出生日期")
@DateTimeFormat("yyyy-MM-dd")
private Date birthday;
/**
* EasyExcel使用:自定义转换器
*/
@ColumnWidth(10)
@ExcelProperty(value = "性别", converter = GenderConverter.class)
private Integer gender;
常用注解:
@ExcelProperty(index = 0, value = “姓名”) :
- 用于设置Excel表头,其中index用户表头的编号,从0开始;value为表头对应的内容。
@ExcelProperty(value = “性别”, converter = GenderConverter.class)
- 自定义转换器
@DateTimeFormat(“yyyy-MM-dd”)
- 用于日期的格式化。
@ContentStyle(dataFormat = 2)
- 保留两位小数
排除指定列的三种方式:
- 方式1:在类上添加 @ExcelIgnoreUnannotated
- 方式2:指定字段加@ExcelIgnore注解
- 方式3:EasyExcel.write(fileName, UserData.class).sheet(“学生信息表”)
.excludeColumnFiledNames(Arrays.asList(“remark”)).doWrite(getData());
这种方法的好处是:同一Excel可以在调用方法时排除不同的数据列。
2.3 自定义性别转换器
自定义内容转换器,类似枚举的实现,将“男”、“女”转换成“0”、“1”的数值。
package com.daniel.utils;
import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.enums.CellDataTypeEnum;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.property.ExcelContentProperty;
/**
* @author daniel
* @createTime 2022/9/16 0016 10:25
* @description
*/
public class GenderConverter implements Converter<Integer>
private static final String MAN = "男";
private static final String WOMAN = "女";
@Override
public Class<?> supportJavaTypeKey()
// 实体类中对象属性类型
return Integer.class;
@Override
public CellDataTypeEnum supportExcelTypeKey()
// Excel中对应的CellData属性类型
return CellDataTypeEnum.STRING;
@Override
public Integer convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty,
GlobalConfiguration globalConfiguration)
// 从Cell中读取数据
String gender = cellData.getStringValue();
// 判断Excel中的值,将其转换为预期的数值
if (MAN.equals(gender))
return 0;
else if (WOMAN.equals(gender))
return 1;
return null;
@Override
public CellData<?> convertToExcelData(Integer integer, ExcelContentProperty excelContentProperty,
GlobalConfiguration globalConfiguration)
// 判断实体类中获取的值,转换为Excel预期的值,并封装为CellData对象
if (integer == null)
return new CellData<>("");
else if (integer == 0)
return new CellData<>(MAN);
else if (integer == 1)
return new CellData<>(WOMAN);
return new CellData<>("");
三、导入导出工具类
3.1 监听类
package com.daniel.utils;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @author daniel
* @createTime 2022/9/16 0016 11:04
* @description 解析监听器
* 每解析一行会回调invoke()方法。
* 整个excel解析结束会执行doAfterAllAnalysed()方法
*
* 没有考虑合并单元格的情况
*/
public class ExcelListener extends AnalysisEventListener<Object>
//定义一个保存Excel所有记录的集合
private List<Object> datas = new ArrayList<>();
public List<Object> getDatas()
return datas;
public void setDatas(List<Object> datas)
this.datas = datas;
/**
* 逐行解析
* object : 当前行的数据
* 这个每一条数据解析都会来调用
* 我们将每一条数据都保存到list集合中
* @param object one row value. Is is same as @link AnalysisContext#readRowHolder()
* @param analysisContext
*/
@Override
public void invoke(Object object, AnalysisContext analysisContext)
System.out.println("读取object=" + object);
//当前行
// context.getCurrentRowNum()
//数据存储到list,供批量处理,或后续自己业务逻辑处理。
if (object != null)
datas.add(object);
// handleBusinessLogic();
/*
如数据过大,可以进行定量分批处理
if(datas.size() >= 200)
handleBusinessLogic();
datas.clear();
*/
/**
* 读取表头内容
* @param headMap 表头
* @param analysisContext
*/
@Override
public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext analysisContext)
System.out.println("表头" + headMap);
/**
* 解析完所有数据后会调用该方法
* @param analysisContext
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext)
//解析结束销毁不用的资源,非必要语句,查看导入的数据
System.out.println("读取Excel完毕" + datas.size());
//根据业务自行实现该方法,例如将解析好的dataList存储到数据库中
private void handleBusinessLogic()
3.2 ExcelUtils工具类
package com.daniel.utils;
import cn.hutool.core.convert.Convert;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* @author daniel
* @createTime 2022/9/16 0016 9:47
* @description
*/
public class ExcelUtils
private static final Logger log = LoggerFactory.getLogger(ExcelUtils.class);
/**
* 读取Excel(多个sheet可以用同一个实体类解析)
* @param excelInputStream
* @param fileName
* @param clazz
* @param <T>
* @return
*/
public static <T> List<T> readExcel(InputStream excelInputStream, String fileName, Class<T> clazz)
ExcelListener excelListener = new ExcelListener();
ExcelReader excelReader = getReader(excelInputStream, fileName,clazz, excelListener);
if (excelReader == null)
return new ArrayList<>();
List<ReadSheet> readSheetList = excelReader.excelExecutor().sheetList();
for (ReadSheet readSheet : readSheetList)
excelReader.read(readSheet);
excelReader.finish();
return Convert.toList(clazz, excelListener.getDatas());
/**
* 导出数据
*
* @param head 类名
* @param excelname excel名字
* @param data 数据
*/
public static void getExcelimporttemplate(Class head, String excelname, List data)
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletResponse response = requestAttributes.getResponse();
// 这里注意 有人反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
//response.setContentType("application/vnd.ms-excel");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
try
//表格头部样式
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//设置背景颜色
//headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
//设置头字体
//WriteFont headWriteFont = new WriteFont();
//headWriteFont.setFontHeightInPoints((short)13);
//headWriteFont.setBold(true);
//headWriteCellStyle.setWriteFont(headWriteFont);
//设置头居中
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//表格内容样式
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//设置 水平居中
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
String fileName = URLEncoder.encode(excelname, "UTF-8").replaceAll("\\\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), head).registerWriteHandler(horizontalCellStyleStrategy).sheet("Sheet1").doWrite(data);
catch (UnsupportedEncodingException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
/**
* 导出数据
*
* @param head 类名
* @param excelname excel名字
* @param data 数据
*/
public static void excelExport(Class head, String excelname, List data)
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletResponse response = requestAttributes.getResponse();
// 这里注意 有人反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
//response.setContentType("application/vnd.ms-excel");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
try
String fileName = URLEncoder.encode(excelname, "UTF-8").replaceAll("\\\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), head).sheet("Sheet1").doWrite(data);
catch (UnsupportedEncodingException e)
e.printStackTrace();
catch (IOException e)
e.printStackTrace();
/**
* 导出数据二级表头
* (合并第一行单元格,第二行开始是业务字段)
* @param bigTitle 合并单元格的名字
* @param head 类名
* @param excelname 导出的excel名字
* @param data 数据
* @param header 导出的字段列名
*/
public static void getBigTitleExcel(String bigTitle, Class head, String excelname, List data, List<String> header)
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletResponse response = requestAttributes.getResponse();
// 这里注意 有人反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
//response.setContentType("application/vnd.ms-excel");
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
//response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
try
//表格头部样式
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
//设置背景颜色
//headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
//设置头字体
//WriteFont headWriteFont = new WriteFont();
//headWriteFont.setFontHeightInPoints((short)13);
//headWriteFont.setBold(true);
//headWriteCellStyle.setWriteFont(headWriteFont);
//设置头居中
headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
//表格内容样式
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
//设置 水平居中
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment<以上是关于SpringBoot+EasyExcel导入导出加水印的主要内容,如果未能解决你的问题,请参考以下文章
Springboot整合easyExcel导入导出Excel
使用VUE+SpringBoot+EasyExcel 整合导入导出数据
Java:SpringBoot使用EasyExcel实现Excel文件的导出下载和上传导入功能