EasyExcel
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 {
@Test
public 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 目录下面
*/
@Test
public 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. 读取数据行
@Test
public 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类型
*/
@Override
public 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类型
*/
@Override
public 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;
}
测试
@Test
public 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
*/
@Override
public void invoke(UserInfoModel userInfoModel, AnalysisContext analysisContext) {
log.info("解析每一行excel的 invoke 方法:{}" ,userInfoModel);
}
/**
* 解析完 excel中所有数据时,会执行的方法
* @param analysisContext
*/
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext) {
log.info("解析完excel的 doAfterAllAnalysed 方法:" );
}
}
使用
@Test
public 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监听器实现类())
.""””..
测试
@Test
public 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 */ @Override public 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 */ @Override public void invoke(UserInfoModel userInfoModel, AnalysisContext analysisContext) { log.info("解析每一行excel的 invoke 方法:{}" ,userInfoModel); } /** * 解析完 excel中所有数据时,会执行的方法 * @param analysisContext */ @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { log.info("解析完excel的 doAfterAllAnalysed 方法:" ); } /** * 解析异常时,会执行的方法 * * @param exception * @param context * @throws Exception */ @Override public 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();//必须抛出 } }
运行
@Test public 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";
@Test
public 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集合导出
@Test
public 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;
}
@Test
public 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; }
@Test public 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类型
*/
@Override
public 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类型
*/
@Override
public 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
@Test public 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(数据);
测试
@Test
public 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 { @Override public 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; }
- 测试类
@Test public 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; } @Override public 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())); } } } }
- 测试类
@Test public 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; }
- 测试类
@Test public 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 返回数据表列名,表头名称 */ @SneakyThrows private <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; }
- 测试
@Test public void test3() { // 查询:用户信息实体。 List<UserInfoEntity> entityList = this.userInfoService.list(); //转换:entity -> model List<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;//设置批注
- 测试
@Test public void test4() { // 查询:用户信息实体。 List<UserInfoEntity> entityList = this.userInfoService.list(); //转换:entity -> model List<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;
- 测试
@Test public 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))//数据填充
测试
@Test
public 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; }
- 测试
@Test public 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))//数据填充
测试
@Test
public 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);
}
测试
@Test
public 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);