目录
2.2.10 通过注解形式设置写入Excel的样式(字体字号,填充颜色等)
3.2.1 根据Excel中指定的列名或者列的下标读取指定列的数据
第一章 引入相关依赖
使用maven管理项目,引入EasyExcel依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.22</version>
</dependency>
第二章 导出数据进入excel
2.1 导出的简单实现
2.1.1 创建导出实体类dto
首先创建需要使用的dto,用于设置导出使用的模板类;
使用easyExcel提供的注解@ExcelProperty标记字段
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
@ExcelProperty("用户编号")
private Integer userId;
@ExcelProperty("姓名")
private String userName;
@ExcelProperty("性别")
private String gender;
@ExcelProperty("工资")
private Double salary;
@ExcelProperty("入职时间")
private Date hireDate;
}
2.1.2 第一种实现方式
@Test
public void test1() {
String fileNameAndLocation = "E:\\xx\\xxx\\easyExcel\\src\\main\\resources\\user1.xlsx";
//User是设定好的dto,专门用来做导出。使用EasyExcel的相关标签设置了表头等
List<User> users = new ArrayList<>();
User user1 = new User(101, "李四", "男", 10000.09, new Date());
User user2 = new User(102, "小美", "女", 10033.09, new Date());
users.add(user1);
users.add(user2);
//将数据写到excel的第一个sheet标签中,并且给sheet标签起名字
//会自动在设定的位置创建excel
EasyExcel.write(fileNameAndLocation, User.class)
.sheet("用户信息")
.doWrite(users);
//不用关闭流资源,执行完后,会自动关闭文件流
}
2.1.3 第二种实现方式
@Test
public void test2() {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\xxx\\easyExcel\\src\\main\\resources\\user2.xlsx";
/**
* 构建要写入的数据
* User类是一个自定义的特殊类,专门用来构建向Excel中写数据的类型类
* @ExcelProperty是easyexcel提供的注解,用来定义表格的头部
*/
List<User> data = new ArrayList<>();
User user = new User(2001, "李雷", "男", 1000.123, new Date());
data.add(user);
//创建Excel写对象
ExcelWriter excelWriter = EasyExcel.write(fileNameAndLocation, User.class).build();
//创建sheet对象
WriteSheet writeSheet = EasyExcel.writerSheet("用户信息").build();
//将数据写到sheet标签中
excelWriter.write(data, writeSheet);
//关闭流,文件流手动关闭
excelWriter.finish();
}
2.2 导出的扩展
2.2.1 将类中某几个字段排除掉,不写入Excel中
@Test
public void test3() {
//创建保存位置以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user3.xlsx";
List<User> data = new ArrayList<>();
User user = new User(2001, "李雷", "男", 1000.123, new Date());
data.add(user);
//构建要排除导出的列
Set<String> excludeColumnFIelds = new HashSet<>();
excludeColumnFIelds.add("hireDate");
excludeColumnFIelds.add("userName");
EasyExcel.write(fileNameAndLocation, User.class)
.excludeColumnFiledNames(excludeColumnFIelds)
.sheet("用户信息表(排除字段后)")
.doWrite(data);
}
2.2.2 只向表格中导出指定某几个字段
@Test
public void test4() {
//创建保存位置以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user4.xlsx";
List<User> data = new ArrayList<>();
User user = new User(2001, "李雷", "男", 1000.123, new Date());
data.add(user);
//构建要导出的列
Set<String> includeColumnFIelds = new HashSet<>();
includeColumnFIelds.add("hireDate");
includeColumnFIelds.add("userName");
EasyExcel.write(fileNameAndLocation, User.class)
.includeColumnFiledNames(includeColumnFIelds)
.sheet("用户信息表(设定的字段)")
.doWrite(data);
}
2.2.3 设定导出的列顺序
创建新的dto,类名为IndexUser;
与之前相比标签内多了一个属性index,该参数从0开始,标识该字段作为excel中第几列出现;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class IndexUser {
/*
* value属性:用来设置该字段对应表格中的表头
* index属性:用来设置列的顺序,也就是设定该字段为表格中的第几列
* */
@ExcelProperty(value = "用户姓名",index = 0)
private String userName;
@ExcelProperty(value = "用户编号",index = 2)
private Integer userId;
@ExcelProperty(value = "入职时间",index = 1)
private Date hireDate;
}
@Test
public void test5() {
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user5.xlsx";
List<IndexUser> data = new ArrayList<>();
IndexUser indexUser = new IndexUser("李四", 1001, new Date());
data.add(indexUser);
EasyExcel.write(fileNameAndLocation, IndexUser.class).sheet("用户信息表").doWrite(data);
}
2.2.4 复杂头数据写入(多级列表头)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ComplexHeadUser {
/**
* {"用户主题1","用户编号"}这种遇到格式设置多级主题
* 第一个参数为一级主题(第一行)
* 第二个参数为二级主题(第二行)
* 如果一级主题名称相同,那么他们会合并单元格
*
* 注意:要是想合并单元格,要求一级主题相邻(有相同一级主题的字段声明时紧挨着),
或者使用index参数设定需要合并单元格的字段相邻
*/
@ExcelProperty(value = {"用户主题1", "用户编号"},index = 0)
private Integer userId;
@ExcelProperty(value = {"用户主题2", "用户名称"},index = 2)
private String userName;
@ExcelProperty(value = {"用户主题1", "入职时间"},index = 1)
private Date hireDate;
}
@Test
public void test6() {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user6.xlsx";
//构建要写入的数据
List<ComplexHeadUser> data = new ArrayList<>();
ComplexHeadUser user = new ComplexHeadUser(1001, "丽丽", new Date());
data.add(user);
EasyExcel.write(fileNameAndLocation, ComplexHeadUser.class).sheet("abc").doWrite(data);
}
效果图如下:
2.2.5 重复写到Excel的同一个sheet中
@Test
public void test7() {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user7.xlsx";
//构建数据
List<User> data = new ArrayList<>();
User user1 = new User(2001, "李雷1", "男", 1000.123, new Date());
User user2 = new User(2002, "李雷2", "男", 1000.123, new Date());
User user3 = new User(2003, "李雷3", "男", 1000.123, new Date());
User user4 = new User(2004, "李雷4", "男", 1000.123, new Date());
data.add(user1);
data.add(user2);
data.add(user3);
data.add(user4);
//使用第二种方法导出
ExcelWriter excelWriter = EasyExcel.write(fileNameAndLocation, User.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("用户信息表").build();
for (int i = 0; i < 5; i++) {
excelWriter.write(data, writeSheet);
}
//关闭文件流
excelWriter.finish();
}
2.2.6 重复的写到Excel的不同sheet中
@Test
public void test8() {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user8.xlsx";
//构建数据
List<User> data = new ArrayList<>();
User user1 = new User(2001, "李雷1", "男", 1000.123, new Date());
User user2 = new User(2002, "李雷2", "男", 1000.123, new Date());
User user3 = new User(2003, "李雷3", "男", 1000.123, new Date());
User user4 = new User(2004, "李雷4", "男", 1000.123, new Date());
data.add(user1);
data.add(user2);
data.add(user3);
data.add(user4);
//创建ExcelWriter对对象并设置用哪个Class(数据类型)去写
ExcelWriter excelWriter = EasyExcel.write(fileNameAndLocation, User.class).build();
//模拟重复写入,模拟重复写入5次
for (int i = 0; i < 5; i++) {
//创建sheet(因为写入到不同的sheet,所以需要多次创建sheet)
//WriteSheet writeSheet = EasyExcel.writerSheet(i,"用户信息"+i).build(); //用下面的格式也可以
WriteSheet writeSheet = EasyExcel.writerSheet("用户信息" + i).build();
excelWriter.write(data, writeSheet);
}
//关闭文件流
excelWriter.finish();
}
2.2.7 日期、数字类型格式化
需要在设置dto的时候使用下面两种注解 @DateTimeFormat : 日期格式化 @NumberFormat : 数字格式化(小数或者百分数)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
/**
* 用户id
*/
@ExcelProperty("用户编号")
private Integer userId;
/**
* 用户名
*/
@ExcelProperty("姓名")
private String userName;
/**
* 性别
*/
@ExcelProperty("性别")
private String gender;
/**
* 工资
* 格式化小数类型,如果是百分数那么定义为 #.##% 比如9.12%
*/
@NumberFormat("#,###.##")
@ExcelProperty("工资")
private Double salary;
/**
* 雇佣日期
*/
@DateTimeFormat("yyyy年MM月dd日 HH时mm分ss秒")
@ExcelProperty("入职时间")
private Date hireDate;
}
@Test
public void test9() {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user9.xlsx";
//构建数据
List<User> data = new ArrayList<>();
User user1 = new User(2001, "李雷1", "男", 100000000.12223, new Date());
User user2 = new User(2002, "李雷2", "男", 1000.12223, new Date());
User user3 = new User(2003, "李雷3", "男", 1000.12223, new Date());
User user4 = new User(2004, "李雷4", "男", 1000.13323, new Date());
data.add(user1);
data.add(user2);
data.add(user3);
data.add(user4);
EasyExcel.write(fileNameAndLocation, User.class).sheet("用戶信息").doWrite(data);
}
效果图如下:
2.2.8 写入图片到Excel
向Excel导入图片(一共五种方式) 1. 图片可以是一个File格式 2. 图片可以是一个InputStream输入流的方式 3. 图片可以是一个byte[]数组的方式 4. 图片可以是 一个网络的java.net.URL对象方式 5. 图片也可以是一个String类型方式(当是String类型是,需要StringImageConverter类型转换器)下面分别用这5种方式实现写入图片进入Excel中,实际开发中选择一种适合即可。下面设计dto的时候使用的两个设置列表格式的注解将在后面提到。
@Data
@AllArgsConstructor
@NoArgsConstructor
@ContentRowHeight(100) // 内容高度
@ColumnWidth(100 / 4) // 列宽
public class ImageData {
// 使用抽象文件表示一个图片
@ExcelProperty(value = "文件保存")
private File file;
// 使用输入流保存一个图片
@ExcelProperty(value = "输入流保存")
private InputStream inputStream;
//当使用String类型保存一个图片的时候需要使用StringImageConverter转换器
@ExcelProperty(converter = StringImageConverter.class,value = "String保存")
private String string;
// 使用二进制数据保存为一个图片
@ExcelProperty("二进制数据保存")
private byte[] byteArray;
// 使用网络链接保存一个图片
@ExcelProperty(value = "网络url保存")
private URL url;
}
@Test
public void test10() throws IOException {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user10.xlsx";
//构建数据
ArrayList<ImageData> dataArrayList = new ArrayList<>();
ImageData imageData = new ImageData();
//方式一:通过文件保存一个图片
imageData.setFile(new File("E:\\xx\\easyExcel\\src\\main\\resources\\img1.png"));
//方式二:通过输入流保存一个图片
imageData.setInputStream(new FileInputStream(new File("E:\\xx\\easyExcel\\src\\main\\resources\\img1.png")));
//方式三:通过String类型保存一个图片
imageData.setString("E:\\xx\\easyExcel\\src\\main\\resources\\img1.png");
//方式四:通过url网络连接
imageData.setUrl(new URL("https://i-blog.csdnimg.cn/blog_migrate/32713a7065b41cdcf1a00d81d9972f7b.png"));
//方式五:通过二进制数据保存一个图片
int length = (int) new File("E:\\xx\\easyExcel\\src\\main\\resources\\img1.png").length();
byte[] bytes = new byte[length];
FileInputStream inputStream = new FileInputStream("E:\\xx\\easyExcel\\src\\main\\resources\\img1.png");
inputStream.read(bytes, 0, length);
imageData.setByteArray(bytes);
dataArrayList.add(imageData);
//写数据
EasyExcel.write(fileNameAndLocation, ImageData.class).sheet("图片信息").doWrite(dataArrayList);
//关闭流
inputStream.close();
}
实际的效果图如下展示 :
2.2.9 设置写入Excel的列宽行高设置
@Data
@AllArgsConstructor
@NoArgsConstructor
@ContentRowHeight(30) //设置内容单元格高度
@HeadRowHeight(40) //设置表头单元格高度
@ColumnWidth(25) //内容单元格宽度和内容单元格宽度是一样的,只有一个注解
public class WidthAndHeightData {
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ColumnWidth(20) //设置列宽(可以修饰类,也可以修饰具体属性)
@ExcelProperty("数字标题")
private Double doubleData;
}
@Test
public void test11() {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user11.xlsx";
//构建数据
List<WidthAndHeightData> list = new ArrayList<WidthAndHeightData>();
WidthAndHeightData wd = new WidthAndHeightData();
wd.setString("红猫");
wd.setDoubleData(200.12);
wd.setDate(new Date());
list.add(wd);
//写数据
EasyExcel.write(fileNameAndLocation, WidthAndHeightData.class).sheet("信息").doWrite(list);
}
效果图如下所示。
2.2.10 通过注解形式设置写入Excel的样式(字体字号,填充颜色等)
//头背景设置成红色 IndexedColors.RED.getIndex()
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10)
//内容的背景设置成绿色 IndexedColors.GREEN.getIndex()
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17)
//表头单元格 字体设置为宋体10号
@HeadFontStyle(fontHeightInPoints = 10,fontName = "宋体")
//内容字体设置成10号
@ContentFontStyle(fontHeightInPoints = 10)
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StyleColumnData {
// 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex()
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14)
// 字符串的内容的背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex()
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40)
// 字符串的头字体设置成11
@HeadFontStyle(fontHeightInPoints = 11)
// 字符串的内容字体设置成11
@ContentFontStyle(fontHeightInPoints = 11)
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
}
/**
* 通过注解形式设置写入Excel的样式,字体字号,背景填充颜色
*/
@Test
public void test12() {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user12.xlsx";
//构建数据
List<StyleColumnData> list = new ArrayList<>();
StyleColumnData scd = new StyleColumnData();
scd.setDate(new Date());
scd.setDoubleData(200.12);
scd.setString("小美美");
list.add(scd);
EasyExcel.write(fileNameAndLocation, StyleColumnData.class).sheet("信息").doWrite(list);
}
具体效果如下。
2.2.11 合并单元格
- 使用注解@OnceAbsoluteMerge设置列或者行的合并,根据行得两个绝对行号和列的两个绝对列号,开始的index都是0,指代第一行或者第一列。这个主机在实体类的上面标注。
- 注解@ContentLoopMerge使用在属性的上面,表示竖着循环合并单元格。如下面表示每两行合并一次,并且每两个中的第一个作为合并的内容,就是说当前两行内容分别是a,b,合并后的内容显示的是a。
@Data
@AllArgsConstructor
@NoArgsConstructor
@OnceAbsoluteMerge(firstRowIndex = 1,lastRowIndex = 2,firstColumnIndex = 1,lastColumnIndex = 2)
public class MergeData {
//每隔两行合并一次(竖着合并单元格)
@ContentLoopMerge(eachRow = 2)
@ExcelProperty("字符串标题")
private String string;
@ExcelProperty("日期标题")
private Date date;
@ExcelProperty("数字标题")
private Double doubleData;
}
@Test
public void test13() {
//创建文件保存的位置,以及文件名
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user13.xlsx";
//构建数据
List<MergeData> list = new ArrayList<>();
MergeData dmd = new MergeData();
dmd.setDate(new Date());
dmd.setDoubleData(200.12);
dmd.setString("双面龟");
MergeData dmd2 = new MergeData();
dmd2.setDate(new Date());
dmd2.setDoubleData(200.12);
dmd2.setString("小美美");
MergeData dmd3 = new MergeData();
dmd3.setDate(new Date());
dmd3.setDoubleData(200.12);
dmd3.setString("小美美");
MergeData dmd4 = new MergeData();
dmd4.setDate(new Date());
dmd4.setDoubleData(200.12);
dmd4.setString("双面龟");
MergeData dmd5 = new MergeData();
dmd5.setDate(new Date());
dmd5.setDoubleData(200.12);
dmd5.setString("双面龟");
list.add(dmd);
list.add(dmd2);
list.add(dmd3);
list.add(dmd4);
list.add(dmd5);
EasyExcel.write(fileNameAndLocation, MergeData.class).sheet("信息sheet").doWrite(list);
}
效果图如下。
第三章 从Excel中读取数据
3.1两种简单的方法实现读取
设定需要读取的文件Excel如下
注意下面这种方式,没有设置对应关系,所以每个属性要和Excel中的字段对应上。顺序不能错。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DemoData {
private String name;
private Date hireDate;
private Double salary;
}
3.1.1 实现方式一
.sheet()里面不设置读取的对应的sheet名的话或者sheet对应的index(从0开始),默认是读取第一个sheet
@Test
public void test2_0() {
//读取的文件路径(需要读取的Excel的位置)
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user2_0.xlsx";
//创用来接收Excel表格对应数据的实体类
Class<DemoData> head = DemoData.class;
//读取数据
EasyExcel.read(fileNameAndLocation, head, new AnalysisEventListener<DemoData>() {
//解析每一条数据的时候被调用
@Override
public void invoke(DemoData data, AnalysisContext context) {
//在这里操作,将解析的每一条数据保存到数据库中,在这里可以调用数据库(比如将数据导入库中)
System.out.println("解析的数据为: " + data);
}
//解析完所有数据的时候被调用
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("数据解析完成..........");
}
}).sheet().doRead();
}
3.1.2 实现方式二
@Test
public void test2_1() {
//读取的文件路径
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user2_1.xlsx";
//创建接收Excel表格数据的实体类
Class<DemoData> head = DemoData.class;
//创建ExcelReader对象
ExcelReader excelReader = EasyExcel.read(fileNameAndLocation, head, new AnalysisEventListener<DemoData>() {
@Override
public void invoke(DemoData data, AnalysisContext context) {
System.out.println("读取到的数据为:" + data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("数据解析已完成");
}
}).build();
//创建sheet对象,并读取Excel的第1个sheet(下标从0开始)
ReadSheet readSheet = EasyExcel.readSheet(0).build();
excelReader.read(readSheet);
//关闭流操作,在读取文件时会创建临时文件,如果不关闭,磁盘爆掉
excelReader.finish();
}
3.2 Excel读取的扩展
3.2.1 根据Excel中指定的列名或者列的下标读取指定列的数据
下面是对应读取excel中数据的实体类 两种匹配excel字段的方式: ①使用表头名name来匹配excel和实体类中的属性 ②使用index来匹配当前属性对应excel中的列位置字段 这里不建议 index 和 name 同时用,要么一个对象只用index,要么一个对象只用name去匹配。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class IndexOrNameData {
/**
* 强制读取第4个
*/
@ExcelProperty(index = 3)
private Double doubleData;
/**
* 用名字去匹配,这里需要注意,如果名字重复,会导致只有一个字段读取到数据
*/
@ExcelProperty("用户编号")
private String string;
@ExcelProperty("入职时间")
private Date date;
}
@Test
public void test21() {
//设定读取的excel位置
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user21.xlsx";
//创建的实体类,来接收对应表格中的数据
Class<IndexOrNameData> head = IndexOrNameData.class;
//读取数据
EasyExcel.read(fileNameAndLocation, head, new AnalysisEventListener<IndexOrNameData>() {
//解析每一条数据的时候被调用
@Override
public void invoke(IndexOrNameData data, AnalysisContext context) {
//在这里操作,将解析的每一条数据保存到数据库中,在这里可以调用数据库
System.out.println("解析的数据为: " + data);
}
//解析完所有数据的时候被调用
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("数据解析完成..........");
}
}).sheet().doRead();
}
3.2.2 格式化Excel中的数据格式(例如时间)
设定的字段会根据名称或者index,对应上属性和excel中的字段。然后根据使用的注解设定的格式去接收excel中的数据,并将匹配的数据存储在对应的实体类属性中。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ConverterData {
@NumberFormat("#.#")
@ExcelProperty("数字标题")
private String salary;
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
@ExcelProperty("日期标题")
private Date hireDate;
}
@Test
public void test22() {
//读取的文件路径
String fileNameAndLocation = "E:\\xx\\easyExcel\\src\\main\\resources\\user22.xlsx";
//创建来接收表格数据的实体类
Class<ConverterData> head = ConverterData.class;
//读取数据
EasyExcel.read(fileNameAndLocation, head, new AnalysisEventListener<ConverterData>() {
/**
* 解析每一条数据的时候被调用
*/
@Override
public void invoke(ConverterData data, AnalysisContext context) {
//在这里操作,将解析的每一条数据保存到数据库中,在这里可以调用数据库
System.out.println("解析的数据为: " + data);
}
/**
* 解析完所有数据的时候被调用
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
System.out.println("数据解析完成..........");
}
}).sheet().doRead();
}
3.2.3 读取多个或者全部的Sheet
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DemoData {
private String name;
private Date hireDate;
private Double salary;
}
@Test
public void test23() {
//读取的文件路径
String fileName = "user11.xlsx";
//创建的一个接收excel数据的实体类
Class<DemoData> head = DemoData.class;
/**
* 读取全部sheet(这种方式要求每个sheet页的内容都能用同一个实体类接收)
*/
EasyExcel.read(fileName, head, new AnalysisEventListener<DemoData>() {
@Override
public void invoke(DemoData data, AnalysisContext context) {
// 每解析一条数据被调用一次
System.out.println("解析的数据为: " + data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 数据解析完成之后被调用
System.out.println("数据解析完成......");
}
}).doReadAll();
System.out.println("============================================================");
/**
* 读取其中的某几个sheet(读取的每个sheet,分别处理)
*/
//构建ExcelReader对象
ExcelReader excelReader = EasyExcel.read(fileName).build();
//创建想要获取的sheet对象
ReadSheet sheet1 = EasyExcel.readSheet(0).head(DemoData.class).registerReadListener(new AnalysisEventListener<DemoData>() {
@Override
public void invoke(DemoData data, AnalysisContext context) {
// 每解析一条数据被调用一次
System.out.println("解析的数据为: " + data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 数据解析完成之后被调用
System.out.println("数据解析完成......");
}
}).build();
ReadSheet sheet2 = EasyExcel.readSheet(2).head(DemoData.class).registerReadListener(new AnalysisEventListener<DemoData>() {
@Override
public void invoke(DemoData data, AnalysisContext context) {
// 每解析一条数据被调用一次
System.out.println("解析的数据为: " + data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 数据解析完成之后被调用
System.out.println("数据解析完成......");
}
}).build();
//读取sheet
excelReader.read(sheet1, sheet2);
//关闭
excelReader.finish();
}
第四章 填充Excel
不用使用注解提前标明实体类中的字段和excel中的对应关系。使用提前设置好的Excel模板接收数据
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FillData {
private String name;
private Integer number;
}
4.1 简单填充(单个对象填充)
- 这种方式只用来填充单条数据,完全可以用列表填充替代(下面说到)。
- 使用{}占位符来代表需要填充的数据,大括号里面的字段和用来填充的实体类中的属性名一致。
设定好的模板如下。
@Test
public void test24(){
//设置填充模板Excel
String templateFileName="E:\\xx\\easyExcel\\src\\main\\resources\\user22.xlsx";
//通过模板文件填充完毕后生成的文件
String fullFile="E:\\xx\\easyExcel\\src\\main\\resources\\fulledFile.xlsx";
//构建要填充的数据
FillData data1 = new FillData();
data1.setName("张三");
data1.setNumber(1001);
//填充操作
EasyExcel.write(fullFile).withTemplate(templateFileName).sheet().doFill(data1);
}
效果如下所示。
4.2 列表填充(多记录填充)
和单条数据填充使用的占位符相比,前面多加了一个“.”’,表示循环存储多条数据
设定的模板如下。
@Test
public void test25(){
//设置填充模板Excel
String templateFileName="E:\\xx\\easyExcel\\src\\main\\resources\\user23.xlsx";
//通过模板文件填充完毕后生成的文件
String fullFile="E:\\xx\\easyExcel\\src\\main\\resources\\fulledFile2.xlsx";
//构建要填充的数据
ArrayList<FillData> arrayList = new ArrayList<>();
FillData data1 = new FillData();
FillData data2 = new FillData();
data1.setName("张三");
data1.setNumber(1001);
data2.setName("李四");
data2.setNumber(1002);
arrayList.add(data1);
arrayList.add(data2);
//填充操作
EasyExcel.write(fullFile).withTemplate(templateFileName).sheet().doFill(arrayList);
}
效果如图所示。
第五章 Web操作(Excel上传/下载)
5.1 引入相关依赖
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<!--用于实现文件上传的依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<!--引入easyExcel相关依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.3</version>
</dependency>
<!-- SpringMVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.1</version>
</dependency>
<!-- 日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<!-- ServletAPI -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<!-- Spring5和Thymeleaf整合包 -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.12.RELEASE</version>
</dependency>
5.2 html设计
使用theymeleaf来渲染页面(这里不需要关注,只需要能看懂如何实现就可以)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>测试easyExcel上传和下载</title>
</head>
<body>
<h2>进入测试页面</h2>
<hr>
<a th:href="@{/easyExcel/download}">下载</a>
<hr>
<form th:action="@{/easyExcel/upload}" method="post" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="submit" value="上传">
</form>
</body>
</html>
前端页面显示如下。
设计dto如下。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class EasyUser {
@ExcelProperty("用户编号")
private Integer userId;
@ExcelProperty("用户名称")
private String userName;
@ExcelProperty("用户性别")
private String gender;
@ExcelProperty("创建时间")
private Date createTime;
}
5.3 实现下载
下面采用设定好的实体类来实现导出,根据需求也可以采用提前设定好的excel模板实现(前文提到)。
@GetMapping("/easyExcel/download")
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
/**
* EasyExcel下载步骤
*/
//设置响应头(格式是固定的)
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
//设置下载的excel的文件名,并设置防止文件名中文乱码
String fileName = URLEncoder.encode("设置的文件名", "utf-8");
//文件下载方式(附件下载还是在当前浏览器打开)。
// 要是在当前浏览器打开(或者说在当前页面打开)第二个参数中的attachment就改称inline
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
//构建写入到Excel中的数据(此数据可以从数据库中获取)
List<EasyUser> users = new ArrayList<>();
EasyUser user1 = new EasyUser(1001, "李雷1", "男", new Date());
EasyUser user2 = new EasyUser(1002, "李雷2", "男", new Date());
EasyUser user3 = new EasyUser(1003, "李雷3", "男", new Date());
users.add(user1);
users.add(user2);
users.add(user3);
EasyExcel.write(response.getOutputStream(), EasyUser.class).sheet("用户信息").doWrite(users);
}
点击下载后,效果如下,当前页面会有附件可以下载。
5.4 实现上传
@PostMapping("/easyExcel/upload")
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload fileUpload = new ServletFileUpload(factory);
//设置单个文件为3M
fileUpload.setFileSizeMax(1024 * 1024 * 3);
//总文件大小为30M
fileUpload.setSizeMax(1024 * 1024 * 3 * 10);
try {
List<FileItem> list = fileUpload.parseRequest(req);
for (FileItem fileItem : list) {
//判断是否为附件
if (!fileItem.isFormField()) {
//是附件
InputStream inputStream = fileItem.getInputStream();
EasyExcel.read(inputStream, EasyUser.class, new AnalysisEventListener<EasyUser>() {
@Override
public void invoke(EasyUser data, AnalysisContext arg1) {
//读完一行就执行一次(调用数据库进行插入操作等操作)
System.out.println("解析一行: " + data);
}
@Override
public void doAfterAllAnalysed(AnalysisContext arg0) {
System.out.println("Excel全部读完被执行......");
}
}).sheet().doRead();
} else {
//普通表单
}
}
} catch (FileUploadException e) {
e.printStackTrace();
}
//上传完成进行转发或者重定向
}
效果如下,选择文件后,点击上传。之后就会读取到文件,然后根据实际业务进行处理。