赞
踩
<dependencies> <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId> <version>2.2.6</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <version>2.3.5.RELEASE</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.16</version> <scope>compile</scope> </dependency> </dependencies>
// JavaBean import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @NoArgsConstructor @AllArgsConstructor @Data @Builder public class User { @ExcelProperty(value = "用户编号") private Integer userId; @ExcelProperty(value = "姓名") private String userName; @ExcelProperty(value = "性别") private String gender; @ExcelProperty(value = "工资") private Double salary; @ExcelProperty(value = "入职时间") private Date hireDate; // lombok 会生成getter/setter方法 } // 测试类 import com.alibaba.excel.EasyExcel; import com.ublink.domain.User; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.Date; import java.util.List; public class test01 { @Test public void testWriteExcel() { //没有文件的话就先去创建一下 String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx"; // 向Excel中写入数据 也可以通过 head(Class<?>) 指定数据模板 EasyExcel.write(filename, User.class) .sheet("用户信息") .doWrite(getUserData()); } @Test public void testWriteExcel2() { String filename = "C:\\Users\\Admin\\Desktop\\user1.xlsx"; // 创建ExcelWriter对象 ExcelWriter excelWriter = EasyExcel.write(filename, User.class).build(); // 创建Sheet对象 WriteSheet writeSheet = EasyExcel.writerSheet("用户信息").build(); // 向Excel中写入数据 excelWriter.write(getUserData(), writeSheet); // 关闭流 excelWriter.finish(); } // 根据user模板构建数据 private List<User> getUserData() { List<User> users = new ArrayList<User>(); for (int i = 1; i <= 10; i++) { User user = User.builder() .userId(i) .userName("admin" + i) .gender(i % 2 == 0 ? "男" : "女") .salary(i * 1000.00) .hireDate(new Date()) .build(); users.add(user); } return users; } }
一般来说的话文件写入在找不到文件时会自动创建,防止意外的话直接手动创建就是了
这些数据我写在user.xlsx的第二张表里
import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelReader; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.read.builder.ExcelReaderBuilder; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.support.ExcelTypeEnum; import com.ublink.domain.User; import org.junit.Test; public class test02 { @Test // 在读取Excel表格数据时, 将读取的每行记录映射成一条LinkedHashMap记录, 而没有映射成实体类. public void testRead() { String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx"; // 创建ExcelReaderBuilder对象 ExcelReaderBuilder readerBuilder = EasyExcel.read(); // 获取文件对象 readerBuilder.file(filename); // 指定映射的数据模板 // readerBuilder.head(DemoData.class); // 指定sheet readerBuilder.sheet(0); // 自动关闭输入流 readerBuilder.autoCloseStream(true); // 设置Excel文件格式 readerBuilder.excelType(ExcelTypeEnum.XLSX); // 注册监听器进行数据的解析 readerBuilder.registerReadListener(new AnalysisEventListener() { // 每解析一行数据,该方法会被调用一次 @Override public void invoke(Object demoData, AnalysisContext analysisContext) { // 如果没有指定数据模板, 解析的数据会封装成 LinkedHashMap返回 // demoData instanceof LinkedHashMap 返回 true System.out.println("解析数据为:" + demoData.toString()); } // 全部解析完成被调用 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("解析完成..."); // 可以将解析的数据保存到数据库 } }); readerBuilder.doReadAll(); /* // 构建读取器 ExcelReader excelReader = readerBuilder.build(); // 读取Excel excelReader.readAll(); // 关闭流 excelReader.finish();*/ } @Test public void testReadExcel() { // 读取的excel文件路径 String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx"; // 读取excel EasyExcel.read(filename, User.class, new AnalysisEventListener<User>() { // 每解析一行数据,该方法会被调用一次 @Override public void invoke(User user, AnalysisContext analysisContext) { System.out.println("解析数据为:" + user.toString()); } // 全部解析完成被调用 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("解析完成..."); // 可以将解析的数据保存到数据库 } }).sheet().doRead(); } @Test public void testReadExcel2() { // 读取的excel文件路径 String filename = "D:\\study\\excel\\read.xlsx"; // 创建一个数据格式来装读取到的数据 Class<DemoData> head = DemoData.class; // 创建ExcelReader对象 ExcelReader excelReader = EasyExcel.read(filename, head, new AnalysisEventListener<DemoData>() { // 每解析一行数据,该方法会被调用一次 @Override public void invoke(DemoData demoData, AnalysisContext analysisContext) { System.out.println("解析数据为:" + demoData.toString()); } // 全部解析完成被调用 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("解析完成..."); // 可以将解析的数据保存到数据库 } }).build(); // 创建sheet对象,并读取Excel的第一个sheet(下标从0开始), 也可以根据sheet名称获取 ReadSheet sheet = EasyExcel.readSheet(0).build(); // 读取sheet表格数据, 参数是可变参数,可以读取多个sheet excelReader.read(sheet); // 需要自己关闭流操作,在读取文件时会创建临时文件,如果不关闭,会损耗磁盘,严重的磁盘爆掉 excelReader.finish(); } }
结果1:
这是由于我将两张表放在一个文件里,因此打印了两张表的数据
结果2:映射后的效果
@NoArgsConstructor @AllArgsConstructor @Data @Builder public class DemoData { @ExcelProperty(value = "字符串标题", index = 0) private String name; @ExcelProperty(value = "日期标题", index = 1) // 格式化日期类型数据 @DateTimeFormat(value = "yyyy年MM月dd日 HH时mm分ss秒") private Date hireDate; @ExcelProperty(value = "数字标题", index = 2) // 格式化数字类型数据,保留一位小数 @NumberFormat(value = "###.#") private String salary; //注意: @NumberFormat对于Double类型的数据格式化会失效,建议使用String类型接收数据进行格式化 // private Double salary; // lombok 会生成getter/setter方法 }
我手敲的路径,少了个s(手动捂脸),大家作为反面教材引以为戒哈
C:\Users\Admin\Desktop\user.xlsx
我这边猜测的可能性最大的是:
文件被打开了(比如看看学习成果)导致文件访问异常
字段不匹配:检查一下表格文件的表头字段是不是跟JavaBean属性名对应的
@Test
public void testWriteExcel3() {
String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx";
// 设置排除的属性 也可以在数据模型的字段上加@ExcelIgnore注解排除
Set<String> excludeField = new HashSet<String>();
excludeField.add("hireDate");
excludeField.add("salary");
// 写Excel
EasyExcel.write(filename, User.class)
.excludeColumnFiledNames(excludeField)
.sheet("用户信息")
.doWrite(getUserData());
}
@Test
public void testWriteExcel4() {
String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx";
// 设置要导出的字段
Set<String> includeFields = new HashSet<String>();
includeFields.add("userName");
includeFields.add("hireDate");
includeFields.add("salary");
// 写Excel
EasyExcel.write(filename, User.class)
.includeColumnFiledNames(includeFields)
.sheet("用户信息")
.doWrite(getUserData());
}
表头字段顺序按JavaBean顺序来,读出的时候按表格文件中的顺序来
修改后的JavaBean
import com.alibaba.excel.annotation.ExcelProperty; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @NoArgsConstructor @AllArgsConstructor @Data @Builder public class User { @ExcelProperty(value = "用户编号") private Integer userId; @ExcelProperty(value = "姓名", index = 1) private String userName; @ExcelProperty(value = "性别") private String gender; @ExcelProperty(value = "工资", index = 0) private Double salary; @ExcelProperty(value = "入职时间", index = 2) private Date hireDate; // lombok 会生成getter/setter方法 }
再次执行testWriteExcel4方法查看结果
使用@DateTimeFormat()注解转化日期时间,value属性填写日期格式
使用@NumberFormat()注解转化数字,value写数字格式,#代替数字位置
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.NumberFormat; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @NoArgsConstructor @AllArgsConstructor @Data @Builder public class DemoData { @ExcelProperty(value = "字符串标题", index = 1) private String name; @ExcelProperty(value = "日期标题", index = 2) // 格式化日期类型数据 @DateTimeFormat(value = "yyyy年MM月dd日 HH时mm分ss秒") private Date hireDate; @ExcelProperty(value = "数字标题", index = 0) // 格式化数字类型数据,保留一位小数 @NumberFormat(value = "###.#") private String salary; //注意: @NumberFormat对于Double类型的数据格式化会失效,建议使用String类型接收数据进行格式化 // private Double salary; // lombok 会生成getter/setter方法 }
测试类进行读取
@Test public void testRead() { String filename = "C:\\Users\\Admin\\Desktop\\user.xlsx"; // 创建ExcelReaderBuilder对象 ExcelReaderBuilder readerBuilder = EasyExcel.read(); // 获取文件对象 readerBuilder.file(filename); // 指定映射的数据模板 // readerBuilder.head(DemoData.class); // 指定sheet readerBuilder.sheet(0); // 自动关闭输入流 readerBuilder.autoCloseStream(true); // 设置Excel文件格式 readerBuilder.excelType(ExcelTypeEnum.XLSX); // 注册监听器进行数据的解析 readerBuilder.registerReadListener(new AnalysisEventListener() { // 每解析一行数据,该方法会被调用一次 @Override public void invoke(Object demoData, AnalysisContext analysisContext) { // 如果没有指定数据模板, 解析的数据会封装成 LinkedHashMap返回 // demoData instanceof LinkedHashMap 返回 true System.out.println("解析数据为:" + demoData.toString()); } // 全部解析完成被调用 @Override public void doAfterAllAnalysed(AnalysisContext analysisContext) { System.out.println("解析完成..."); // 可以将解析的数据保存到数据库 } }); readerBuilder.doReadAll(); /* // 构建读取器 ExcelReader excelReader = readerBuilder.build(); // 读取Excel excelReader.readAll(); // 关闭流 excelReader.finish();*/ }
结果:
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentRowHeight; import com.alibaba.excel.annotation.write.style.HeadRowHeight; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.util.Date; @NoArgsConstructor @AllArgsConstructor @Data @Builder @HeadRowHeight(value = 30) // 头部行高 @ContentRowHeight(value = 25) // 内容行高 @ColumnWidth(value = 20) // 列宽 public class WidthAndHeightData { @ExcelProperty(value = "字符串标题") private String string; @ExcelProperty(value = "日期标题") private Date date; @ExcelProperty(value = "数字标题") @ColumnWidth(value = 25) private Double doubleData; // lombok 会生成getter/setter方法 }
import com.alibaba.excel.EasyExcel; import com.ublink.domain.WidthAndHeightData; import org.junit.Test; import java.util.ArrayList; import java.util.Date; import java.util.List; public class Test03 { @Test public void testWrite11() { String filename = "C:\Users\Admin\Desktop\userwh.xlsx"; // 构建数据 List<WidthAndHeightData> dataList = new ArrayList<WidthAndHeightData>(); WidthAndHeightData data = WidthAndHeightData.builder() .string("字符串") .date(new Date()) .doubleData(888.88) .build(); dataList.add(data); // 向Excel中写入数据 EasyExcel.write(filename, WidthAndHeightData.class) .sheet("行高和列宽测试") .doWrite(dataList); } }
结果
import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.*; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.apache.poi.ss.usermodel.FillPatternType; import java.util.Date; @NoArgsConstructor @AllArgsConstructor @Data @Builder @HeadRowHeight(value = 30) // 头部行高 @ContentRowHeight(value = 25) // 内容行高 @ColumnWidth(value = 20) // 列宽 // 头背景设置成红色 IndexedColors.RED.getIndex() @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10) // 头字体设置成20, 字体默认宋体 @HeadFontStyle(fontName = "宋体", fontHeightInPoints = 20) // 内容的背景设置成绿色 IndexedColors.GREEN.getIndex() @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17) // 内容字体设置成20, 字体默认宋体 @ContentFontStyle(fontName = "宋体", fontHeightInPoints = 20) public class DemoStyleData { // 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex() @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14) // 字符串的头字体设置成20 @HeadFontStyle(fontHeightInPoints = 30) // 字符串的内容背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex() @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40) // 字符串的内容字体设置成20,默认宋体 @ContentFontStyle(fontName = "宋体", fontHeightInPoints = 20) @ExcelProperty(value = "字符串标题") private String string; @ExcelProperty(value = "日期标题") private Date date; @ExcelProperty(value = "数字标题") private Double doubleData; // lombok 会生成getter/setter方法 }
@Test public void testWrite12() { String filename = "C:\Users\Admin\Desktop\user12.xlsx"; // 构建数据 List<DemoStyleData> dataList = new ArrayList<>(); DemoStyleData data = DemoStyleData.builder() .string("字符串") .date(new Date()) .doubleData(888.88) .build(); dataList.add(data); // 向Excel中写入数据 EasyExcel.write(filename, DemoStyleData.class) .sheet("样式设置测试") .doWrite(dataList); }
结果
@NoArgsConstructor @AllArgsConstructor @Data @Builder @HeadRowHeight(value = 25) // 头部行高 @ContentRowHeight(value = 20) // 内容行高 @ColumnWidth(value = 20) // 列宽 /** * @OnceAbsoluteMerge 指定从哪一行/列开始,哪一行/列结束,进行单元格合并 * firstRowIndex 起始行索引,从0开始 * lastRowIndex 结束行索引 * firstColumnIndex 起始列索引,从0开始 * lastColumnIndex 结束列索引 */ // 例如: 第2-3行,2-3列进行合并 @OnceAbsoluteMerge(firstRowIndex = 1, lastRowIndex = 2, firstColumnIndex = 1, lastColumnIndex = 2) public class DemoMergeData { // 每隔两行合并一次(竖着合并单元格) // @ContentLoopMerge(eachRow = 2) @ExcelProperty(value = "字符串标题") private String string; @ExcelProperty(value = "日期标题") private Date date; @ExcelProperty(value = "数字标题") private Double doubleData; // lombok 会生成getter/setter方法 }
@Test public void testWrite13() { String filename = "C:\Users\Admin\Desktop\user13.xlsx"; // 构建数据 List<DemoMergeData> dataList = new ArrayList<>(); DemoMergeData data = DemoMergeData.builder() .string("字符串") .date(new Date()) .doubleData(888.88) .build(); dataList.add(data); // 向Excel中写入数据 EasyExcel.write(filename, DemoMergeData.class) .sheet("单元格合并测试") .doWrite(dataList); }
结果
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。