EasyExcel使用总结
EasyExcel
文章目录
- EasyExcel
- 1、导入
- 1.1、基本方式导入
- 1.导入依赖
- 2. 加载源文件
- 基本语法
- 3. 读取数据行
- 4. 读取结果
- 1.2、模型映射导入
- 1.定义实体映射类
- 2. 操作读取
- 基本语法
- 3. 读取数据行
- 4. 读取结果
- 1.3、导入类型转换器
- 语法
- 1.4、导入监听器
- 基本语法:
- 1.5、多行表头导入
- 基本语法:
- 1.6、导入异常处理
- 1.7、文件上传导入
- 2、导出
- 1、基本方式导出
- 基本语法
- 2、模型映射导出
- 基本语法
- 3、自定义导出格式转换
- 语法
- 4、排除那些列导出
- 语法
- 5、导出行高列宽
- 语法:
- 6、合并单元格导出
- 语法
- 自定义合并单元格
- 7、导出动态表头
- 语法
- 自定义导出动态表头
- 8、导出超链接、批注、公式
- 导出超链接语法
- 导出批注语法
- 导出公式语法
- 9、导出图片内容
- 导出图片内容语法
- 3、模版填充
- 1、模版填充对象
- 基本语法Map填充
- 基本语法对象填充
- 2、模版填充列表
- 语法
- 3、模版填充组合
- 基本语法
- 4、导出文件下载
- 语法
1、导入
1.1、基本方式导入
1.导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.js</groupId><artifactId>EasyExcel-Test</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--easy-excel--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.4</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion></exclusions></dependency><!--Junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><!--slf4j接口--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.6</version></dependency><!--slf4j实现--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>2.0.6</version></dependency><!--fast-josn--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.22</version></dependency></dependencies></project>
2. 加载源文件
使用File 或 InputStream 的方式加载Excel 源文件
基本语法
//示例:从本地File文件导入。
File file = new File("Excel本地文件路径.xlsx");
List<Object>list = EasyExcel.read(file).sheet(0).doReadsync();//示例:从InputStream输入流中导入。
InputStream inputStream = TestSample.class.getClassLoader(),aetResourceAsstream("Excel资源路径,xlsx");
List<Object>list = EasyExcel.read(inputStream).sheet(0).doReadsync();
3. 读取数据行
使用 EasyExcel 载入并读取源文件数据行内容
实例
package cn.js;import com.alibaba.excel.EasyExcel;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;import java.io.File;
import java.util.List;/*** Description:** @Author Js* @Create 2025-05-03 20:05* @Version 1.0*/
@Slf4j
public class EasyExcelTest {@Testpublic void testFile(){File file = new File("C:\\Users\\lenovo\\Desktop\\123\\Easy-test.xlsx");List<Object> list = EasyExcel.read(file).sheet(0).doReadSync();for (Object item : list) {log.info("item:{}",item);}}
}
实例2
package cn.js;import com.alibaba.excel.EasyExcel;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;import java.io.File;
import java.io.InputStream;
import java.util.List;/*** Description:** @Author Js* @Create 2025-05-03 20:05* @Version 1.0*/
@Slf4j
public class EasyExcelTest {/*** 我们将:Easy-test.xlsx 文件放到 resource 目录下面*/@Testpublic void testInputStream(){InputStream inputStream = EasyExcelTest.class.getClassLoader().getResourceAsStream("Easy-test.xlsx");List<Object> list = EasyExcel.read(inputStream).sheet(0).doReadSync();for (Object item : list) {log.info("item:{}",item);}}}
4. 读取结果
获取数据行条目及各行数据内容
1.2、模型映射导入
我们第一种导出结果,可以看出,是一个Map 的结构,我们在获取数据的时候,如果通过角标
Key
获取值的话,很不方便的,而且每一个key 对应的Value 的类型也不一样。如果我们定义好一个类,将类中的属性和Excel 列进行一 一 绑定,这样既能知道value的类型,也更加明确的好获取每个数据。
1.定义实体映射类
package cn.js;import lombok.Data;import java.util.Date;/*** Description:** @Author Js* @Create 2025-05-03 20:34* @Version 1.0*/
@Data
public class UserInfoModel {/*** 昵称*/private String userName;/*** 性别*/private String userGender;/*** 生日*/@DateTimeFormat(value="yyyy年MM月dd日 HH时mm分ss秒")private Date userBirth;/*** 邮箱*/private String userEmail;/*** 积分*/private Integer userScore;/*** 排名*/// private Double userRank;@NumberFormat(value="#.##%")private String userRank;}
2. 操作读取
基本语法
关联映射 @ExcelProperty:将类的属性,和excel的单元格进行绑定,默认是按照顺序进行解析的,注意类的字段类型,要符合excel中的字段,否则会报错;建议使用“列名” 进行绑定@ExcelProperty(index=0)@ExcelProperty(value ="列名")格式转换@DateTimeFormat(value="yyyy年MM月dd日 HH时mm分ss秒")@NumberFormat(value="#.##%")@ExcelProperty(converter=自定义格式转换.class)相关方法EasyExcel.read(inputStream).head(映射模型.class).doReadSync();
3. 读取数据行
@Testpublic void testInputStreamWithModel() {InputStream inputStream = EasyExcelTest.class.getClassLoader().getResourceAsStream("Easy-test.xlsx");List<UserInfoModel> list = EasyExcel.read(inputStream).sheet(0).head(UserInfoModel.class).doReadSync();for (UserInfoModel item : list) {log.info("昵称:{},性别{},生日{},邮箱{},积分{},排名{}", item.getUserName(),item.getUserGender(),item.getUserBirth(),item.getUserEmail(),item.getUserScore(),item.getUserRank());}}
4. 读取结果
1.3、导入类型转换器
语法
实现 implements Converter<
就是实际导进来需要转换成java中啥类型
> 接口中convertToJavaData 方法在需要转换的映射模型字段上面加上如下注解
@ExcelProperty(converter = 类型转换器.class)
类型转换器
package cn.js;import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;/*** Description:** @Author Js* @Create 2025-05-03 21:04* @Version 1.0*/// Converter<Integer>:就是实际导进来需要转换成啥类型
public class UserInfoGenderConverter implements Converter<Integer> {/*** 导入时: 把excel中的数据转成java类型*/@Overridepublic Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {String value = cellData.getStringValue();switch (value) {case "男":return 1;case "女":return 2;default:return 0;}}/*** 导出时: 把java中的数据转成符合excel类型*/@Overridepublic WriteCellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {return Converter.super.convertToExcelData(value, contentProperty, globalConfiguration);}
}
使用类型转换器:
@ExcelProperty(converter = 类型转换器所在的类.class)
,将这个注解贴在要转换的模型映射类中对应的Excel字段上面,即可。 如:将excel中的男,女转换成:1,0
/*** 性别 */ @ExcelProperty(converter = UserInfoGenderConverter.class)//类型转换器 private Integer userGender; //private String userGender;
package cn.js;import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import com.alibaba.excel.annotation.format.NumberFormat;
import lombok.Data;import java.util.Date;/*** Description:** @Author Js* @Create 2025-05-03 20:34* @Version 1.0*/
@Data
public class UserInfoModel {/*** 昵称*/private String userName;/*** 性别*/@ExcelProperty(converter = UserInfoGenderConverter.class)//类型转换器private Integer userGender;//private String userGender;/*** 生日*/@DateTimeFormat(value="yyyy年MM月dd日 HH时mm分ss秒")private Date userBirth;/*** 邮箱*/private String userEmail;/*** 积分*/private Integer userScore;/*** 排名*/@NumberFormat(value="#.##%")private String userRank;//private Double userRank;}
测试
@Testpublic void testInputStreamWithModel() {InputStream inputStream = EasyExcelTest.class.getClassLoader().getResourceAsStream("Easy-test.xlsx");List<UserInfoModel> list = EasyExcel.read(inputStream).sheet(0).head(UserInfoModel.class).doReadSync();for (UserInfoModel item : list) {log.info("昵称:{}, 性别:{}, 生日:{}, 邮箱:{}, 积分:{}, 排名:{}", item.getUserName(),item.getUserGender(),item.getUserBirth(),item.getUserEmail(),item.getUserScore(),item.getUserRank());}}
1.4、导入监听器
为啥需要监听器?我们在读取excel 文件时候,不管是File 还是InputStream 流,都是直接使用
.doReadSync()
方法直接读取,但是我们在实际当中,可能还得需要对Excel中数据进行:1.数据格式校验
2.自动适配内容
3.解析异常处理
4.分批入库
5.节约内存 ……操作
基本语法:
//1.示例:使用匿名内部类。
EasyExcel.read(inputStream)
.head(UserInfoModel.class)
.registerReadListener(new ReadListener<映射模型>(){})
.sheet(0);//2.示例:使用监听实现类。
public class 监听实现类 implements ReadListender<映射模型>{}EasyExcel.read(inputStream)
.head(UserInfoModel.class)
.registerReadListener(new监听实现类())
.sheet(0);//3.示例:简写方式。
EasyExcel.read(inputStream, UserinfoModel.class, new 监听实现类()).sheet(0);
使用步骤
package cn.js.listener;import cn.js.model.UserInfoModel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.read.listener.ReadListener;
import lombok.extern.slf4j.Slf4j;/*** Description:** @Author Js* @Create 2025-05-03 21:52* @Version 1.0*/
@Slf4j
public class UserInfoReadListener implements ReadListener<UserInfoModel> {/*** 解析excel中每一条数据时,会执行的方法* @param userInfoModel* @param analysisContext*/@Overridepublic void invoke(UserInfoModel userInfoModel, AnalysisContext analysisContext) {log.info("解析每一行excel的 invoke 方法:{}" ,userInfoModel);}/*** 解析完 excel中所有数据时,会执行的方法* @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {log.info("解析完excel的 doAfterAllAnalysed 方法:" );}
}
使用
@Testpublic void testInputStreamWithListener() {InputStream inputStream = EasyExcelTest.class.getClassLoader().getResourceAsStream("Easy-test.xlsx");List<UserInfoModel> list = EasyExcel.read(inputStream).sheet(0).registerReadListener(new UserInfoReadListener())//监听器.head(UserInfoModel.class).doReadSync();}
1.5、多行表头导入
应用场景
一般在导入数据的时候我们会给用户一个模版,让用户按照模版要求进行导入。
比方说下图,前五行,是我们提供给用户的注意事项,从第六行开始,才是我们的excel数据的表头,此时我们应该指定,数据真正的表头,是第几行。
基本语法:
EasyExcel.read(inputStream)
.sheet(0)
.head(映射模型.class)
//关键代码:设置表头行数。
.headRowNumber(6)
.registerReadListener(new监听器实现类())
.""””..
测试
@Testpublic void testInputStreamWithModel1() {InputStream inputStream = EasyExcelTest.class.getClassLoader().getResourceAsStream("Easy-test1.xlsx");List<UserInfoModel> list = EasyExcel.read(inputStream).sheet(0).head(UserInfoModel.class).headRowNumber(6)//关键代码:设置表头行数。.doReadSync();for (UserInfoModel item : list) {log.info("昵称:{}, 性别:{}, 生日:{}, 邮箱:{}, 积分:{}, 排名:{}", item.getUserName(),item.getUserGender(),item.getUserBirth(),item.getUserEmail(),item.getUserScore(),item.getUserRank());}}
1.6、导入异常处理
处理方式也是实现监听器,并重写其中的
onException
方法,里面的异常封装着数据错误信息。public void onException(Exception exception, AnalysisContext context) throws Exception
基本语法:
/*** 解析异常时,会执行的方法* @param exception* @param context* @throws Exception*/@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {// ReadListener.super.onException(exception, context);ExcelDataConvertException dataConvertException = (ExcelDataConvertException) exception;//获取行的下标Integer rowIndex = dataConvertException.getRowIndex();//获取列的下标Integer columnIndex = dataConvertException.getColumnIndex();//数据String content = dataConvertException.getCellData().getStringValue();//原因String message = dataConvertException.getMessage();log.error("解析失败,请检查输入的第{}行第{}列数据是否正确:{}",rowIndex,columnIndex,message);log.warn("Excel data conversion error at row {}, column {}, content: {}", rowIndex, columnIndex, content);throw new ExcelAnalysisStopException();//必须抛出}
标准化处理
- 定义一个读取错误的Moder类
package cn.js.model;import lombok.AllArgsConstructor; import lombok.Data;import java.io.Serializable;/** * Description: * * @Author Js * @Create 2025-05-03 22:57 * @Version 1.0 */ @Data @AllArgsConstructor public class ReadErrorModel implements Serializable {private static final long serialVersionUID = 1L;/*** 错误信息*/private String message;/*** 行号*/private Integer rowIndex;/*** 列号*/private Integer columnIndex;/*** 单元格数据*/private String cellData;}
测试
package cn.js.listener;import cn.js.model.UserInfoModel; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.read.listener.ReadListener; import lombok.extern.slf4j.Slf4j;/*** Description:** @Author Js* @Create 2025-05-03 21:52* @Version 1.0*/ @Slf4j public class UserInfoReadListener implements ReadListener<UserInfoModel> {/*** 解析excel中每一条数据时,会执行的方法* @param userInfoModel* @param analysisContext*/@Overridepublic void invoke(UserInfoModel userInfoModel, AnalysisContext analysisContext) {log.info("解析每一行excel的 invoke 方法:{}" ,userInfoModel);}/*** 解析完 excel中所有数据时,会执行的方法* @param analysisContext*/@Overridepublic void doAfterAllAnalysed(AnalysisContext analysisContext) {log.info("解析完excel的 doAfterAllAnalysed 方法:" );}/*** 解析异常时,会执行的方法** @param exception* @param context* @throws Exception*/@Overridepublic void onException(Exception exception, AnalysisContext context) throws Exception {// ReadListener.super.onException(exception, context);ExcelDataConvertException dataConvertException = (ExcelDataConvertException) exception;//获取行的下标Integer rowIndex = dataConvertException.getRowIndex();//获取列的下标Integer columnIndex = dataConvertException.getColumnIndex();//数据String content = dataConvertException.getCellData().getStringValue();//原因String message = dataConvertException.getMessage();this.readErrorModel = new ReadErrorModel(rowIndex, columnIndex, content, message);throw new ExcelAnalysisStopException();//必须抛出} }
运行
@Testpublic void testInputStreamWithListener2() {InputStream inputStream = EasyExcelTest.class.getClassLoader().getResourceAsStream("Easy-test.xlsx");UserInfoReadListener listener = new UserInfoReadListener();List<UserInfoModel> list = EasyExcel.read(inputStream).sheet(0).registerReadListener(listener)//监听器.head(UserInfoModel.class).doReadSync();if(listener.getReadErrorModel()!=null){log.info("读取失败:{}",listener.getReadErrorModel());}else {log.info("读取成功:{}",list);}}
1.7、文件上传导入
导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.js</groupId><artifactId>EasyExcel-Test</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!--easy-excel--><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.2.1</version><exclusions><exclusion><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId></exclusion><exclusion><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId></exclusion></exclusions></dependency><!--commons--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.23.0</version></dependency><!--Junit--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.2</version><scope>test</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><!--slf4j接口--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>2.0.6</version></dependency><!--slf4j实现--><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-simple</artifactId><version>2.0.6</version></dependency><!--fast-josn--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.22</version></dependency><!--springBoot--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.7.11</version><exclusions><exclusion><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.yaml</groupId><artifactId>snakeyaml</artifactId><version>2.0</version></dependency></dependencies></project>
package cn.js.controller;import cn.js.model.UserInfoModel;
import com.alibaba.excel.EasyExcel;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.IOException;
import java.io.InputStream;
import java.util.List;/*** Description:** @Author Js* @Create 2025-05-03 23:18* @Version 1.0*/
@RestController
@RequestMapping("/hom")
public class HomController {@RequestMapping("/test")public String test(){return "hello";}@PostMapping("/test2")public List<UserInfoModel> update(MultipartFile file) throws IOException {//获取:文件输入流InputStream inputStream = file.getInputStream();List<UserInfoModel> list = EasyExcel.read(inputStream).sheet(0).head(UserInfoModel.class).registerReadListener(new UserInfoReadListener())//监听器doReadSync();return list;}}
2、导出
1、基本方式导出
基本语法
EasyExcel.write("导出目标").sheet().doWrite("集合数据");
//导出目标:1.string 文件路径2.File 文件对象3.OutStream 输出流//集合数据:1.List<List<Object>>2.List<Map<Integer,Object>>3.List<Object>
使用List集合导出
package cn.js;import cn.js.model.UserInfoModel;
import com.alibaba.excel.EasyExcel;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;import java.util.Arrays;
import java.util.List;/*** Description:** @Author Js* @Create 2025-05-04 13:04* @Version 1.0*/
@Slf4j
public class EasyWiteTest {private static final String FILE_NAME = "C:\\Users\\lenovo\\Desktop\\123\\test.xlsx";@Testpublic void witeList(){List<Object> list1 = Arrays.asList(1, 2, 3);List<Object> list2 = Arrays.asList("郭德纲", "王德纲", "张德纲");List<List<Object>> list = Arrays.asList(list1, list2);EasyExcel.write(FILE_NAME).sheet("测试").doWrite(list);}
}
使用Map集合导出
@Testpublic void witeMap() throws ParseException {Map<Integer, Object> map1 = new HashMap<>();map1.put(0, "张三");map1.put(1, "男");map1.put(2, DateUtils.parseDate("2025-05-04"));map1.put(3, "zhangsan@163.com");HashMap<Integer, Object> map2 = new HashMap<>();map2.put(0, "李四");map2.put(1, "女");map2.put(2, DateUtils.parseDate("2025-05-04"));map2.put(3, "lisi@163.com");List<Map<Integer, Object>> list = Arrays.asList(map1, map2);EasyExcel.write(FILE_NAME).sheet("测试").doWrite(list);}
使用List对象集合导出
package cn.js.model;import cn.js.converter.UserInfoGenderConverter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.format.DateTimeFormat;
import lombok.AllArgsConstructor;
import lombok.Data;import java.util.Date;/*** Description:** @Author Js* @Create 2025-05-04 13:20* @Version 1.0*/
@Data
@AllArgsConstructor
public class UserWriteModel {/*** 昵称*/private String userName;/*** 性别*/private String userGender;/*** 生日*/@DateTimeFormat(value="yyyy年MM月dd日 HH时mm分ss秒")private Date userBirth;/*** 邮箱*/private String userEmail;
}
@Testpublic void objectList() throws ParseException {UserWriteModel model1 = new UserWriteModel("张三", "男", DateUtils.parseDate("2025-05-04"), "zhangsan@163.com");UserWriteModel model2 = new UserWriteModel("李四", "女", DateUtils.parseDate("2025-05-04"), "lisi@163.com");List<UserWriteModel> list = Arrays.asList(model1, model2);EasyExcel.write(FILE_NAME).sheet("测试").doWrite(list);}
2、模型映射导出
其一步实我们,在上一步中ListObject 使用过程当中就已经使用过了,但是可以发现导出的时候Excel 中是没有表头的,而且数据没有格式化……等操作
基本语法
// 关联映射&设置标题@ExcelProperty(index=0)//表示:数据放在excel中那一列@ExcelProperty(value ="列名")@ExcelProperty(value ={"主标题","副标题"})//显示隐藏@Excellgnore//在那个模型映射字段添加该注解,这个字段在导出的,就会忽略掉//设置那些模型字段导出EasyExcel.write(导出目标).head(映射模型.class).excludeColumnFiledNames(Collection<String>)//根据集合设置,那些列不导出,Collection<String>:那些模型映射类的字段,:userName,userGender,将这些封装成Lsit集合。.includeColumnFiledNames(Collection<String>)//根据集合设置,那些列导出.doWrite(集合数据); //格式转换@DateTimeFormat(value="yyyy年MM月dd日")@NumberFormat(value="#.##%")@ExcelProperty(converter=自定义转换.class)// 相关方法EasyExcel.write(导出目标).head(映射模型.class).doWrite(集合数据);
关联映射&设置标题
package cn.js.model;import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import lombok.AllArgsConstructor; import lombok.Data;import java.math.BigDecimal; import java.util.Date;/*** Description:** @Author Js* @Create 2025-05-04 13:20* @Version 1.0*/ @Data @AllArgsConstructor public class UserWriteModel {/*** 昵称*/@ExcelProperty(value = {"基本信息", "姓名"})private String userName;/*** 性别*/@ExcelProperty(value = {"基本信息", "性别"})private Integer userGender;/*** 生日*/@ExcelProperty(value = {"基本信息", "生日"})@DateTimeFormat(value = "yyyy年MM月dd日 HH时mm分ss秒")private Date userBirth;/*** 邮箱*/@ExcelProperty(value = {"基本信息", "邮箱"})private String userEmail;/*** 积分*/@ExcelProperty(value = {"账户信息", "积分"})private Integer userScore;@ExcelProperty(value = {"账户信息", "奖励"})private BigDecimal userReward; }
@Testpublic void objectList2() throws ParseException {UserWriteModel model1 = new UserWriteModel("张三疯", 1, DateUtils.parseDate("2025-05-04"), "zhangsan@163.com", 123, BigDecimal.valueOf(123.456));UserWriteModel model2 = new UserWriteModel("李四军", 0, DateUtils.parseDate("2025-05-04"), "lisi@163.com", 789, BigDecimal.valueOf(789.258));List<UserWriteModel> list = Arrays.asList(model1, model2);EasyExcel.write(FILE_NAME).sheet("测试").head(UserWriteModel.class).doWrite(list);}
3、自定义导出格式转换
语法
实现 implements Converter<
就是实际导进来需要转换成java中啥类型
> 接口中convertToExcelData
方法在需要转换的映射模型字段上面加上如下注解:
@ExcelProperty(converter = 类型转换器.class)
类型转换器
package cn.js;import com.alibaba.excel.converters.Converter;
import com.alibaba.excel.metadata.GlobalConfiguration;
import com.alibaba.excel.metadata.data.ReadCellData;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.metadata.property.ExcelContentProperty;/*** Description:** @Author Js* @Create 2025-05-03 21:04* @Version 1.0*/// Converter<Integer>:就是实际导进来需要转换成啥类型
public class UserInfoGenderConverter implements Converter<Integer> {/*** 导入时: 把excel中的数据转成java类型*/@Overridepublic Integer convertToJavaData(ReadCellData<?> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {String value = cellData.getStringValue();switch (value) {case "男":return 1;case "女":return 2;default:return 0;}}/*** 导出时: 把java中的数据转成符合excel类型*/@Overridepublic WriteCellData<?> convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {switch (value) {case 1:return new WriteCellData<>("男");case 2:return new WriteCellData<>("女");default:return new WriteCellData<>("未知");}}
}
测试
模型映射类添加类型转换器
/** * 性别 */ @ExcelProperty(value = {"基本信息", "性别"},converter = UserInfoGenderConverter.class) private Integer userGender;
1
@Testpublic void objectList2() throws ParseException {UserWriteModel model1 = new UserWriteModel("张三疯", 1, DateUtils.parseDate("2025-05-04"), "zhangsan@163.com", 123, BigDecimal.valueOf(123.456));UserWriteModel model2 = new UserWriteModel("李四军", 0, DateUtils.parseDate("2025-05-04"), "lisi@163.com", 789, BigDecimal.valueOf(789.258));List<UserWriteModel> list = Arrays.asList(model1, model2);EasyExcel.write(FILE_NAME).sheet("测试").head(UserWriteModel.class).doWrite(list);}
4、排除那些列导出
语法
- 直接在模型映射类的字段上面添加注解
//显示隐藏 @Excellgnore//在那个模型映射字段添加该注解,这个字段在导出的,就会忽略掉
在导出的时候设置那些是否导出
//设置那些模型字段导出EasyExcel.write(导出目标).head(映射模型.class)//根据集合设置,那些列不导出,Collection<String>:那些模型映射类的字段,如:userName,userGender,将这些封装成Lsit集合。.excludeColumnFiledNames(Collection<String>)//根据集合设置,那些列导出.includeColumnFiledNames(Collection<String>).doWrite(集合数据);
5、导出行高列宽
语法:
手动设置,通过在模型映射类的字段上面添加注解,或者在模型类上面添加,在模型类上面添加,所有导出的字段都生效。
//行高(内容):@ContentRowHeight(value=10) //行高(标题):@HeadRowHeight(value=20) //列宽:@ColumnWidth(value=25)
自动列宽,也可以参照
LongestMatchColumnWidthStyleStrategy
类重写一个EasyExcel.write(file)//自动列宽:根据内容长度自动匹配:默认按照标题匹配 .registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet() .doWrite(data);
6、合并单元格导出
语法
使用注解:
//firstRowIndex:开始第几行,lastRowindex结束是第几行,firstcolumnindex:第几列开始,lastColumnIndex:第几列结束 @OnceAbsoluteMerge(firstRowIndex =2,lastRowindex =3, firstcolumnindex=0,lastColumnIndex=0) public class 模型映射类{}@ContentLoopMerge(eachRow=2) private String fieldName;
- 自定义策略:
// 循环合并:new LoopMergeStrategy(eachRow:2,columnIndex:0);// 合并一次: new OnceAbsoluteMergestrategy(firstRowindex: 0, lastRowindex: 1, firstcolumnindex: 4, lastcolumnindex: 4);// 使用策略: EasyExcel.write(file).head(映射模型.class).sheet().registerWriteHandler(合并策略).doWrite(数据);
测试
@Testpublic void objectList3() throws ParseException {UserWriteModel model1 = new UserWriteModel("第一团队","张三疯", 1, DateUtils.parseDate("2025-05-04"), "zhangsan@163.com", 123, BigDecimal.valueOf(123.456));UserWriteModel model2 = new UserWriteModel("第一团队","李四军", 0, DateUtils.parseDate("2025-05-05"), "lisi@163.com", 789, BigDecimal.valueOf(789.258));UserWriteModel model3 = new UserWriteModel("第二团队", "王五", 1, DateUtils.parseDate("2025-05-06"), "zhangsxxn@163.com", 124, BigDecimal.valueOf(123.056));UserWriteModel model4 = new UserWriteModel("第二团队", "赵六", 1, DateUtils.parseDate("2025-05-07"), "zhdsfgxxn@163.com", 604, BigDecimal.valueOf(435.010));UserWriteModel model5 = new UserWriteModel("第三团队", "孙七", 0, DateUtils.parseDate("2025-05-08"), "zhdsfgxxn@163.com", 604, BigDecimal.valueOf(405.231));List<UserWriteModel> list = Arrays.asList(model1, model2, model3, model4, model5);EasyExcel.write(FILE_NAME).sheet("测试").head(UserWriteModel.class)// .registerWriteHandler(new OnceAbsoluteMergeStrategy(2,3,0,0)).registerWriteHandler(new LoopMergeStrategy(2,0)).doWrite(list);}
自定义合并单元格
合并单元格,有两种方式:
- 是实现
RowWriteHandler
接口,这个是行合并,也是默认的- 是实现
CellWriteHandler
接口,这个是列合并实现
CellWriteHandler
接口package cn.js.converter;import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;import java.io.Serializable; import java.util.List;/*** Description:** @Author Js* @Create 2025-05-04 14:54* @Version 1.0*/ public class CustomMergeStrategy implements CellWriteHandler {@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 如果是表头,不做处理if(isHead) {return;}//relativeRowIndex: 当前行号,如果当前是第一行,则不做处理if(relativeRowIndex== 0) {return;}//获取当前表格,当前行下标,上一行下标,上一行对象,上一列对象Sheet sheet = cell.getSheet();int rowIndexCurrent = cell.getRowIndex();int lastRowIndex = rowIndexCurrent - 1;Row rowPrev = sheet.getRow(lastRowIndex);Cell cellPrev = rowPrev.getCell(cell.getColumnIndex());//获取当前单元格的值Object cellValueCurrent = cell.getCellType() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();//获取上一单元格的值Object cellValuePrev = cellPrev.getCellType() == CellType.STRING ? cellPrev.getStringCellValue() : cellPrev.getNumericCellValue();//如果当前单元格的值和上一单元格的值相同,则合并单元格if(cellValueCurrent.equals(cellValuePrev)) {Boolean isMerged = false;//获取已有的合并区域for(int i = 0;i<sheet.getNumMergedRegions();i++) {org.apache.poi.ss.util.CellRangeAddress range = sheet.getMergedRegion(i);if(range.isInRange(rowIndexCurrent, cell.getColumnIndex())){//如果当前单元格已经在合并区域中,则先移除合并区域sheet.removeMergedRegion(i);//重新合并单元格的结束行range.setLastRow(rowIndexCurrent);//重新添加合并区域sheet.addMergedRegion(range);isMerged = true;break;}}if(!isMerged) {//如果当前单元格不在合并区域中,则直接添加新的合并区域sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(lastRowIndex, rowIndexCurrent, cellPrev.getColumnIndex(), cellPrev.getColumnIndex()));}}} }
测试
- 模型类
package cn.js.model;import cn.js.converter.UserInfoGenderConverter; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import lombok.AllArgsConstructor; import lombok.Data;import java.math.BigDecimal; import java.util.Date;/*** Description:** @Author Js* @Create 2025-05-04 13:20* @Version 1.0*/ @Data @AllArgsConstructor public class UserWriteModel {/*** 团队名称*/@ExcelProperty(value = "团队名称")private String teamName;/*** 昵称*/@ExcelProperty(value = {"基本信息", "姓名"})private String userName;/*** 性别*/@ExcelProperty(value = {"基本信息", "性别"},converter = UserInfoGenderConverter.class)private Integer userGender;/*** 生日*/@ExcelProperty(value = {"基本信息", "生日"})@DateTimeFormat(value = "yyyy年MM月dd日 HH时mm分ss秒")private Date userBirth;/*** 邮箱*/@ExcelProperty(value = {"基本信息", "邮箱"})private String userEmail;/*** 积分*/@ExcelProperty(value = {"账户信息", "积分"})private Integer userScore;@ExcelProperty(value = {"账户信息", "奖励"})private BigDecimal userReward; }
- 测试类
@Testpublic void objectList3() throws ParseException {UserWriteModel model1 = new UserWriteModel("第一团队","张三疯", 1, DateUtils.parseDate("2025-05-04"), "zhangsan@163.com", 123, BigDecimal.valueOf(123.456));UserWriteModel model2 = new UserWriteModel("第一团队","李四军", 0, DateUtils.parseDate("2025-05-05"), "lisi@163.com", 789, BigDecimal.valueOf(789.258));UserWriteModel model3 = new UserWriteModel("第二团队", "王五", 1, DateUtils.parseDate("2025-05-06"), "zhangsxxn@163.com", 124, BigDecimal.valueOf(123.056));UserWriteModel model4 = new UserWriteModel("第二团队", "赵六", 1, DateUtils.parseDate("2025-05-07"), "zhdsfgxxn@163.com", 604, BigDecimal.valueOf(435.010));UserWriteModel model5 = new UserWriteModel("第三团队", "孙七", 0, DateUtils.parseDate("2025-05-08"), "zhdsfgxxn@163.com", 604, BigDecimal.valueOf(405.231));List<UserWriteModel> list = Arrays.asList(model1, model2, model3, model4, model5);EasyExcel.write(FILE_NAME).sheet("测试").head(UserWriteModel.class)// .registerWriteHandler(new OnceAbsoluteMergeStrategy(2,3,0,0)) // .registerWriteHandler(new LoopMergeStrategy(2,0)).registerWriteHandler(new CustomMergeStrategy()).doWrite(list);}
但是一般是合并指定列相同的数据
- 自定义合并单元格配置类
package cn.js.converter;import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.data.WriteCellData; import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet;import java.util.List;/*** Description:** @Author Js* @Create 2025-05-04 14:54* @Version 1.0*/ public class CustomMergeStrategy implements CellWriteHandler {//合并列名集合private final List<String> mergeColumnNames;public CustomMergeStrategy(List<String> mergeColumnNames) {this.mergeColumnNames = mergeColumnNames;}@Overridepublic void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {// 如果是表头,不做处理if (isHead) {return;}//relativeRowIndex: 当前行号,如果当前是第一行,则不做处理if (relativeRowIndex == 0) {return;}//如果不是合并列,不做处理if (!mergeColumnNames.contains(head.getFieldName())) {return;}//获取当前表格,当前行下标,上一行下标,上一行对象,上一列对象Sheet sheet = cell.getSheet();int rowIndexCurrent = cell.getRowIndex();int lastRowIndex = rowIndexCurrent - 1;Row rowPrev = sheet.getRow(lastRowIndex);Cell cellPrev = rowPrev.getCell(cell.getColumnIndex());//获取当前单元格的值Object cellValueCurrent = cell.getCellType() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();//获取上一单元格的值Object cellValuePrev = cellPrev.getCellType() == CellType.STRING ? cellPrev.getStringCellValue() : cellPrev.getNumericCellValue();//如果当前单元格的值和上一单元格的值相同,则合并单元格if (cellValueCurrent.equals(cellValuePrev)) {Boolean isMerged = false;//获取已有的合并区域for (int i = 0; i < sheet.getNumMergedRegions(); i++) {org.apache.poi.ss.util.CellRangeAddress range = sheet.getMergedRegion(i);if (range.isInRange(rowIndexCurrent, cell.getColumnIndex())) {//如果当前单元格已经在合并区域中,则先移除合并区域sheet.removeMergedRegion(i);//重新合并单元格的结束行range.setLastRow(rowIndexCurrent);//重新添加合并区域sheet.addMergedRegion(range);isMerged = true;break;}}if (!isMerged) {//如果当前单元格不在合并区域中,则直接添加新的合并区域sheet.addMergedRegion(new org.apache.poi.ss.util.CellRangeAddress(lastRowIndex, rowIndexCurrent, cellPrev.getColumnIndex(), cellPrev.getColumnIndex()));}}} }
- 测试类
@Testpublic void objectList3() throws ParseException {UserWriteModel model1 = new UserWriteModel("第一团队", "张三", 1, DateUtils.parseDate("2025-05-04"), "zhangsan@163.com", 123, BigDecimal.valueOf(123.456));UserWriteModel model2 = new UserWriteModel("第一团队", "张三", 0, DateUtils.parseDate("2025-05-05"), "lisi@163.com", 789, BigDecimal.valueOf(789.258));UserWriteModel model3 = new UserWriteModel("第二团队", "王五", 1, DateUtils.parseDate("2025-05-06"), "zhangsxxn@163.com", 124, BigDecimal.valueOf(123.056));UserWriteModel model4 = new UserWriteModel("第二团队", "赵六", 1, DateUtils.parseDate("2025-05-07"), "zhdsfgxxn@163.com", 604, BigDecimal.valueOf(435.010));UserWriteModel model5 = new UserWriteModel("第三团队", "孙七", 0, DateUtils.parseDate("2025-05-08"), "zhdsfgxxn@163.com", 604, BigDecimal.valueOf(405.231));List<UserWriteModel> list = Arrays.asList(model1, model2, model3, model4, model5);EasyExcel.write(FILE_NAME).sheet("测试").head(UserWriteModel.class)// .registerWriteHandler(new OnceAbsoluteMergeStrategy(2,3,0,0)) // .registerWriteHandler(new LoopMergeStrategy(2,0)).registerWriteHandler(new CustomMergeStrategy(Arrays.asList("teamName", "userGender")))//设置那些列合并.doWrite(list);}
可以看到只合并我们设置的列
7、导出动态表头
语法
可以通过之前学习的
设置排除那些列导出
.//1.显示隐藏 @Excellgnore//在那个模型映射字段添加该注解,这个字段在导出的,就会忽略掉 //2. 设置那些模型字段导出EasyExcel.write(导出目标).head(映射模型.class)//根据集合设置,那些列不导出,Collection<String>:那些模型映射类的字段,如:userName,userGender,将这些封装成Lsit集合。.excludeColumnFiledNames(Collection<String>)//根据集合设置,那些列导出.includeColumnFiledNames(Collection<String>).doWrite(集合数据);
指定表头集合
定义:根据需求动态构建表头集合。
List<List<String>> headList = new ArrayList<>()); headList.add(collections.singletonList("用户昵称")); headList.add(collections.singleonList("用户性别")); headList.add(collections.singletonList("用户年龄")); headList.add(Collections.singletonList("账户佣金")); headList.add(collections.singletonList("账户积分"));
处理:使用动态表头导出相关数据。
EasyExcel.write(file).sheet().head(headList) doWrite(数据集合);
自定义导出动态表头
- 模型类
package cn.js.model;import com.alibaba.excel.annotation.ExcelProperty; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data;import java.io.Serializable; import java.math.BigDecimal; import java.util.Date;/*** Description:** @Author Js* @Create 2025-05-04 15:49* @Version 1.0*/ @Data @TableName("tb_user_info") public class UserInfoEntity implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.ASSIGN_ID)@ExcelProperty(value = {"用户信息", "用户ID"})private Long id;@TableField(value = "user_nickname")@ExcelProperty(value = {"用户信息", "用户昵称"})private String userNickname;@TableField(value = "user_phone")@ExcelProperty(value = {"账号信息", "用户手机"})private String userPhone;@TableField(value = "user_email")@ExcelProperty(value = {"账号信息", "用户邮箱"})private String userEmail;@TableField(value = "user_gender")@ExcelProperty(value = {"其他信息", "用户性别"})private Integer userGender;@TableField(value = "user_birth")@ExcelProperty(value = {"其他信息", "用户生日"})private Date userBirth;@TableField(value = "user_score")@ExcelProperty(value = {"其他信息", "用户积分"})private Integer userScore;@TableField(value = "user_reward")@ExcelProperty(value = {"其他信息", "用户奖励"})private BigDecimal userReward;}
- 测试类
@Testpublic void test4() {// 导出字段名称。List<String> exportFieldNames = Arrays.asList("id", "userNickname", "userPhone", "userEmail", "userScore");//解析字段名称 -> 数据表列名称。Map<String, String[]> map = this.resolveFieldNameMap(UserInfoEntity.class, exportFieldNames);//动态查询。List<String> columnNames = new ArrayList<>(map.keySet());QueryWrapper<UserInfoEntity> queryWrapper = Wrappers.<UserInfoEntity>query().select(columnNames);List<UserInfoEntity> list = this.userInfoService.list(queryWrapper);//动态表头。List<List<String>> headlist = map.values().stream().map(Arrays::asList).collect(Collectors.toList());EasyExcel.write("C:\\Users\\lenovo\\Desktop\\123\\export456.xlsx").sheet("用户信息").head(headlist).doWrite(list);}/*** 解析字段名称 -> 数据表列名称。** @param clz 实体类* @param exportFieldNames 导出字段名称。* @param <T>* @return 返回数据表列名,表头名称*/@SneakyThrowsprivate <T> Map<String, String[]> resolveFieldNameMap(Class<T> clz, List<String> exportFieldNames) {Map<String, String[]> map = new LinkedHashMap<>(exportFieldNames.size());for (String fieldName : exportFieldNames) {Field field = clz.getDeclaredField(fieldName);String columnName = field.isAnnotationPresent(TableId.class) ? field.getAnnotation(TableId.class).value() : field.getAnnotation(TableField.class).value();String[] headNames = field.getAnnotation(ExcelProperty.class).value();map.put(columnName, headNames);}return map;}
8、导出超链接、批注、公式
导出超链接语法
1.属性类型
@ExcelProperty(value="用户编号")
@ColumnWidth(value=15)
private WriteCellData<String>userNumber;2. 导出处理
//声明:超链接数据。
HyperlinkData hyperlinkData = new HyperlinkData();
hyperlinkData.setHyperlinkType(HyperlinkData.HyperlinkType.URL);
hyperlinkData.setAddress("https://www.example.com/u/1001")//处理:使用超链接数据初始化用户编号。
WriteCellData<String> userNumber = new WriteCellData<>("1001");
userNumber.setHyperlinkData(hyperlinkData);//封装:模型对象。
UserInfoModel userInfoModel = new UserInfoModel();
userInfoModel.setUserNumber(userNumber);
测试
- 定义模型类,设置超链接字段
package cn.js.model;import com.alibaba.excel.annotation.ExcelProperty; import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data;import java.io.Serializable; import java.math.BigDecimal; import java.util.Date;/*** Description:** @Author Js* @Create 2025-05-04 15:49* @Version 1.0*/ @Data @TableName("tb_user_info") public class UserInfoEntity implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.ASSIGN_ID)@ExcelProperty(value = {"用户信息", "用户ID"})private Long id;@TableField(value = "user_nickname")@ExcelProperty(value = {"用户信息", "用户昵称"})private String userNickname;@TableField(value = "user_phone")@ExcelProperty(value = {"账号信息", "用户手机"})private String userPhone;@TableField(value = "user_email")@ExcelProperty(value = {"账号信息", "用户邮箱"})private String userEmail;@TableField(value = "user_gender")@ExcelProperty(value = {"其他信息", "用户性别"})private Integer userGender;@TableField(value = "user_birth")@ExcelProperty(value = {"其他信息", "用户生日"})private Date userBirth;@TableField(value = "user_score")@ExcelProperty(value = {"其他信息", "用户积分"})private Integer userScore;@TableField(value = "user_reward")@ExcelProperty(value = {"其他信息", "用户奖励"})private BigDecimal userReward;}
- 测试
@Testpublic void test3() {// 查询:用户信息实体。List<UserInfoEntity> entityList = this.userInfoService.list();//转换:entity -> modelList<UserInfoEntityModel> modelList = entityList.stream().map(item -> {UserInfoEntityModel model = new UserInfoEntityModel();//用户标识。model.setId(item.getId());// 用户昵称。HyperlinkData hyperlinkData = new HyperlinkData();hyperlinkData.setHyperlinkType(HyperlinkData.HyperlinkType.URL);hyperlinkData.setAddress("http://www.xxx.com/usen/" + item.getId());WriteCellData<String> userNickname = new WriteCellData<>(item.getUserNickname());userNickname.setHyperlinkData(hyperlinkData);model.setUserNickname(userNickname);//用户性别。model.setUserGender(item.getUserGender());//用户生日。model.setUserBirth(item.getUserBirth());return model;}).collect(Collectors.toList());EasyExcel.write("C:\\Users\\lenovo\\Desktop\\123\\export156.xlsx").sheet("用户信息").head(UserInfoEntityModel.class).doWrite(modelList);}
导出批注语法
//属性类型:
@ExcelProperty(value = "用户昵称")
@ColumnWidth(value = 15)
private WriteCellData<String> userName;//设置批注//2.导出处理:
//声明:批注数据。
CommentData commentData = new CommentData();
commentData.setRichTextStringData(new RichTextStringData("此用户一天不学习就浑身难受。"));//处理:使用批注数据初始化用户昵称。
WriteCellData<String> userName = new WriteCellData<>("Jshuai ");
userName.setCommentData(commentData);
// 封装:用户信息模型。
UserinfoModel userInfoModel = new UserlnfoModel();
userInfoModel.setUserName(userName);
测试
- 定义模型类,设置批注字段
@ExcelProperty(value = "用户标识") private WriteCellData<Long> id;//设置批注
- 测试
@Testpublic void test4() {// 查询:用户信息实体。List<UserInfoEntity> entityList = this.userInfoService.list();//转换:entity -> modelList<UserInfoEntityModel> modelList = entityList.stream().map(item -> {UserInfoEntityModel model = new UserInfoEntityModel();//添加批注CommentData commentData = new CommentData();//创建批注对象commentData.setAuthor("作者:Jshuai");//设置批注的作者commentData.setRichTextStringData(new RichTextStringData("备注:这是一个备注信息"));WriteCellData<Long> id = new WriteCellData<>(BigDecimal.valueOf(item.getId()));//设置在那个字段上面添加批注id.setCommentData(commentData);//设置批注信息model.setId(id);//将设置批注信息与字段绑定//添加超链接HyperlinkData hyperlinkData = new HyperlinkData();//创建超链接对象hyperlinkData.setHyperlinkType(HyperlinkData.HyperlinkType.URL);//设置超链接类型hyperlinkData.setAddress("http://www.xxx.com/usen/" + item.getId());//设置超链接地址WriteCellData<String> userNickname = new WriteCellData<>(item.getUserNickname());//设置在那个字段上面添加超链接userNickname.setHyperlinkData(hyperlinkData);//设置超链接信息model.setUserNickname(userNickname);//将超链接信息与字段绑定//用户性别。model.setUserGender(item.getUserGender());//用户生日。model.setUserBirth(item.getUserBirth());return model;}).collect(Collectors.toList());EasyExcel.write("C:\\Users\\lenovo\\Desktop\\123\\export156.xlsx").sheet("用户信息").head(UserInfoEntityModel.class).doWrite(modelList);}
导出公式语法
属性类型@ExcelProperty(value = "用户年龄")@ColumnWidth(value = 15)private WriteCellData<Void> userAge;导出处理://声明:公式数据。FormulaData formulaData = new FormulaData();formulaData.setFormulaValue("CONCAT(DATEDIF(C2,NOW(),\"Y\"),\"岁\")");//处理:使用公式数据初始化用户年龄。WriteCellData<Void> userAge = new WriteCellData<>();userAge.setFormulaData(formulaData);
// 封装:用户信息模型。UserinfoModel userInfoModel=new UserinfoModel();userInfoModel.setUserBirth(DateUtils.parseDate("2000-01-01"));userInfoModel.setUserAge(userAge);
测试
- 定义模型类,设置公式字段
//用户生日。@ExcelProperty(value = "用户生日")private WriteCellData<Void> userAge;
- 测试
@Testpublic void test6(){ // 查询:用户信息实体。List<UserInfoEntity> entityList = this.userInfoService.list();// 转换:entity -> model.List<UserInfoEntityModel> modelList = IntStream.range(0, entityList.size()).mapToObj(index -> {// 提取:当前用户信息实体。UserInfoEntity entity = entityList.get(index);// 封装:用户信息模型。UserInfoEntityModel model = new UserInfoEntityModel();// 行号。model.setRowNum(index + 1);//添加批注CommentData commentData = new CommentData();//创建批注对象commentData.setAuthor("作者:Jshuai");//设置批注的作者commentData.setRichTextStringData(new RichTextStringData("备注:这是一个备注信息"));WriteCellData<Long> id = new WriteCellData<>(BigDecimal.valueOf(entity.getId()));//设置在那个字段上面添加批注id.setCommentData(commentData);//设置批注信息model.setId(id);//将设置批注信息与字段绑定// 用户昵称。HyperlinkData hyperlinkData = new HyperlinkData();hyperlinkData.setHyperlinkType(HyperlinkData.HyperlinkType.URL);hyperlinkData.setAddress("http://www.xxx.com/user/" + entity.getId());WriteCellData<String> userNickname = new WriteCellData<>(entity.getUserNickname());userNickname.setHyperlinkData(hyperlinkData);model.setUserNickname(userNickname);// 用户性别。model.setUserGender(entity.getUserGender());// 用户生日。model.setUserBirth(entity.getUserBirth());// 用户年龄。FormulaData formulaData = new FormulaData();formulaData.setFormulaValue("CONCAT(DATEDIF(E" + (index + 2) + ", NOW(), \"Y\"), \"岁\")");WriteCellData<Void> userAge = new WriteCellData<>();userAge.setFormulaData(formulaData);model.setUserAge(userAge);return model;}).collect(Collectors.toList());EasyExcel.write("C:\\Users\\lenovo\\Desktop\\123\\export156.xlsx").sheet("用户信息").head(UserInfoEntityModel.class).doWrite(modelList);}
9、导出图片内容
导出图片内容语法
- 导出图片类型
@ContentRowHeight(value=50)@ColumnWidth(value=30)public class ExportModel {@ExcelProperty(value = "File类型")private File fileImage;@ExcelProperty(value = "byte[]类型")private byte[] byteImage;@ExcelProperty(value = "Inputstream类型")private InputStream inputStreamImage;@ExcelProperty(value = "URL类型")private URL urlImage;@ExcelProperty(value = "string类型", converter = StringImageConverter.class)//不设置转换器的话,导出时是一个字符串private String stringImage;}
- 基本语法
File file = new File("E:\\export.xlsx");// 封装:模型对象。ExportModel exportModel = new ExportModel();exportModel.setFileImage(图片的File对象);exportModel.setByteImage(图片的byte[] 对象);exportModel.setInputStreamImage(图片的InputStream对象);exportModel.setUrlImage(图片的URL对象);exportModel.setStringImage(图片文件路径); //处理:导出操作。 EasyExcel.write(file).sheet().head(ExportModel .class).doWrite(Collections.singletonList(exportModel));
3、模版填充
1、模版填充对象
基本语法Map填充
//封装:Map对象:
Map<String,Object> fillData = new HashMap<>();fillData.put("userNumber","1001");fillData.put("userName","Jshuai");fillData.put("userAccount",BigDecimal.valueOf(666.66));fillData.put("userscore",888);//处理:导出操作。
EasyExcel.write(导出目标)
.withTemplate(模板文件)
.sheet()
.doFill(fillData))//数据填充
测试
@Testpublic void test7(){InputStream resourceAsStream = EasyExcelWiteTest.class.getClassLoader().getResourceAsStream("export-template.xlsx");//封装:Map对象:Map<String,Object> fillData = new HashMap<>();fillData.put("userNumber","1001");fillData.put("userName","Jshuai");fillData.put("userAccount",BigDecimal.valueOf(666.66));fillData.put("userscore",888);//处理:导出操作。EasyExcel.write("C:\\Users\\lenovo\\Desktop\\123\\export-template.xlsx").withTemplate(resourceAsStream).sheet().doFill(fillData);}
基本语法对象填充
- 实体类
@Data public class UserModel {private String userNumber;private String userName;private BigDecimal userAccount;private Integer userScore; }
- 测试
@Testpublic void test8(){InputStream resourceAsStream = EasyExcelWiteTest.class.getClassLoader().getResourceAsStream("export-template.xlsx");//封装:Map对象:UserModel userModel=new UserModel();userModel.setUserNumber("1001");userModel.setUserName("JshuaiBoss");userModel.setUserAccount(BigDecimal.valueOf(666.66));userModel.setUserScore(888);//处理:导出操作。EasyExcel.write("C:\\Users\\lenovo\\Desktop\\123\\export-template.xlsx").withTemplate(resourceAsStream).sheet().doFill(userModel);}
2、模版填充列表
批量填充时,模版设置时,在在占位符前面加一个点
语法
//封装:List对象:
List<Object> fillData = new ArrayList<>();//处理:导出操作。
EasyExcel.write(导出目标)
.withTemplate(模板文件)
.sheet()
.doFill(list))//数据填充
测试
@Testpublic void test9(){InputStream resourceAsStream = EasyExcelWiteTest.class.getClassLoader().getResourceAsStream("export-template.xlsx");//封装:Map对象:UserModel userModel=new UserModel();userModel.setUserNumber("1001");userModel.setUserName("JshuaiBoss");userModel.setUserAccount(BigDecimal.valueOf(666.66));userModel.setUserScore(888);UserModel userModel2=new UserModel();userModel2.setUserNumber("1002");userModel2.setUserName("JshuaiBoss2");userModel2.setUserAccount(BigDecimal.valueOf(666.77));userModel2.setUserScore(999);List<UserModel> list = Arrays.asList(userModel, userModel2);//处理:导出操作。EasyExcel.write("C:\\Users\\lenovo\\Desktop\\123\\export-template.xlsx").withTemplate(resourceAsStream).sheet().doFill(list);}
3、模版填充组合
基本语法
try (ExcelWriter excelWriter = EasyExcel.write(..).withTemplate(..)...){WriteSheet writeSheet = EasyExcel.writerSheet().build();//处理:填充公司信息对象。excelWriter.fill(<公司信息对象 >,writeSheet);//处理:填充部门集合列表。FillConfig fillconfig = Fillconfig.builder().direction(WriteDirectionEnum.HORIZONTAL)//横向,默认纵向.build();excelWriter.fill(new FillWrapper("dept", <部门集合>), fillconfig, writeSheet);//处理:填充员工集合列表。excelWriter.fill(new FillWrapper("employee", <员工集合>),writeSheet);}
测试
@Testpublic void test10() {InputStream exportTemplate = EasyExcelWiteTest.class.getClassLoader().getResourceAsStream("export-templates.xlsx");try (ExcelWriter excelWriter = EasyExcel.write("C:\\Users\\lenovo\\Desktop\\123\\export12026.xlsx").withTemplate(exportTemplate).build()) {WriteSheet writeSheet = EasyExcel.writerSheet().build();// 公司信息。Map<String, Object> companyInfo = new HashMap<>();companyInfo.put("companyName", "大明帝国信息技术有限公司");excelWriter.fill(companyInfo, writeSheet);// 部门信息。Map<String, Object> deptInfo1 = new HashMap<>();deptInfo1.put("deptName", "研发部");deptInfo1.put("deptMaster", "张先生");deptInfo1.put("deptContact", "186****7420");Map<String, Object> deptInfo2 = new HashMap<>();deptInfo2.put("deptName", "设计部");deptInfo2.put("deptMaster", "李女士");deptInfo2.put("deptContact", "185****7420");List<Map<String, Object>> deptList = Arrays.asList(deptInfo1, deptInfo2);FillConfig fillconfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(); // 填充配置excelWriter.fill(new FillWrapper("dept", deptList), fillconfig, writeSheet);// 填充部门信息// 员工信息。Map<String, Object> empInfo1 = new HashMap<>();empInfo1.put("userNumber", "A001002");empInfo1.put("userName", "张三");empInfo1.put("userAccount", 12);empInfo1.put("userscore", BigDecimal.valueOf(120));Map<String, Object> empInfo2 = new HashMap<>();empInfo2.put("userNumber", "A001005");empInfo2.put("userName", "李四");empInfo2.put("userAccount", 16);empInfo2.put("userscore", BigDecimal.valueOf(24));List<Map<String, Object>> empList = Arrays.asList(empInfo1, empInfo2);excelWriter.fill(new FillWrapper("user", empList), writeSheet);// 填充员工信息}}
4、导出文件下载
语法
//1.处理:设置响应参数(内容类型、字符集编码)。
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding(StandardCharsets.UTF_8.name());//2.处理:设置文件名。
String fileName = URLEncoder.encode("用户列表","UTF-8").replaceAll("\\+","%20");
response.setHeader("content-Disposition", "attachment;filename*=UTF-8’" + fileName + ".xlsx");//3.处理:导出文件到输出流。
InputStream inputStream = Application.class.getclassloader().getResourceAsStream("user-export-template.xlsx");
OutputStream outputStream=response.getOutputStream();EasyExcel.write(outputStream);
EasyExcel.write(outputStream).withTemplate(inputStream).sheet("用户列表").doFill(list);