<>Springboot + Easyexcel 读取数据
<>简单读取excel文件
读取下图的 excel 数据
导入依赖,阿里的easyexcel插件
<dependency> <groupId>com.alibaba</groupId> <artifactId>easyexcel</artifactId>
<version>2.1.6</version> </dependency>
创建一个用来 读取 excel的实体类
实体类的属性可以用
@ExcelProperty(index = 0),index=0,找的是上图 A列(第一列)
@ExcelProperty(value = “标号”)
两种都可以用,但是不要两个一起用
实体类:
public class TemplateEntity { @ExcelProperty("标号") private Integer label;
@ExcelProperty("字符串") private String str; @ExcelProperty("数字") private Integer
num; //getter/setter 省略 }
定义一个 监听类:
public class TemplateListener extends AnalysisEventListener<TemplateEntity> {
private List<TemplateEntity> list = new ArrayList<>(); // 一条一条读取数据,全部添加到list集合里
@Override public void invoke(TemplateEntity data, AnalysisContext
analysisContext) { list.add(data); } @Override public void doAfterAllAnalysed(
AnalysisContext analysisContext) {} public List<TemplateEntity> getData() {
return list; } }
service:
public interface TemplateService { /** * 导入excel */ Result importExcel(
MultipartFile file) throws IOException; } @Service public class
TemplateServiceImpl implements TemplateService { @Override public Result
importExcel(MultipartFile file) throws IOException{ List<TemplateEntity>
entities= getTemplateEntities(file); // 处理数据 System.out.println(entities);
return Result.success(entities); } // 读取 excel 数据 private List<TemplateEntity>
getTemplateEntities(MultipartFile file) throws IOException { TemplateListener
listener= new TemplateListener(); // 定义的 listener EasyExcel.read(file.
getInputStream(), TemplateEntity.class, listener).sheet().doRead(); // 返回 所有数据
return listener.getData(); } }
Controller 上传文件接口
@RestController @RequestMapping("/sys") public class TemplateController {
@Autowired private TemplateService templateService; @RequestMapping("/import")
public Result importData(@RequestPart("file") MultipartFile file) throws
IOException{ return templateService.importExcel(file); } }
Postman测试
{ "code": 200, "msg": "处理成功", "data": [ { "label": 1, "str": "a", "num": 20 },
{ "label": 2, "str": "b", "num": 30 }, { "label": 3, "str": "c", "num": 40 },
... }
<>日期格式
excel文件
实体类中可以使用@DateFormat(阿里包下的)注解:
要使用String类型来接收数据才有用
public class TemplateEntity { @ExcelProperty("标号") private Integer label;
@ExcelProperty("字符串") private String str; @ExcelProperty("数字") private Integer
num; @ExcelProperty("时间") // 这里需要用string接收才会格式化 @DateTimeFormat("yyyy-MM-dd")
private String date; // getter/setter省略 }
<>多sheet
<>两sheet表头数据不一致
这里为了演示效果,sheet1和sheet3是不同表头的,sheet2目前是空的数据表
思路:需要再定义一个excel接收数据的实体类,然后创建监听类,重写方法
读取时,指定不同的监听类,excel接收数据的实体类对象,然后放入map中返回即可
<>具体实现
实体类
TemplateEntity接收sheet1
@Data public class TemplateEntity { @ExcelProperty("标号") private Integer label;
@ExcelProperty("字符串") private String str; @ExcelProperty("数字") private Integer
num; @ExcelProperty(value = "时间") @DateTimeFormat("yyyy-MM-dd") private String
date; }
OtherTemplateEntity接收sheet3
@Data public class OtherTemplateEntity { @ExcelProperty("标号") private String
label; @ExcelProperty("名称") private String name; @ExcelProperty("类型") private
String type; @ExcelProperty(value = "时间") @DateTimeFormat("yyyy-MM-dd") private
String date; }
监听类
public class TemplateListener extends AnalysisEventListener<TemplateEntity> {
private List<TemplateEntity> list = new ArrayList<>(); // 一条一条读取数据,全部添加到list集合里
@Override public void invoke(TemplateEntity data, AnalysisContext
analysisContext) { list.add(data); } @Override public void doAfterAllAnalysed(
AnalysisContext analysisContext) {} public List<TemplateEntity> getData() {
return list; } } public class OtherTemplateListener extends
AnalysisEventListener<OtherTemplateEntity> { private List<OtherTemplateEntity>
list= new ArrayList<>(); @Override public void invoke(OtherTemplateEntity data,
AnalysisContext context) { list.add(data); } @Override public void
doAfterAllAnalysed(AnalysisContext context) {} public List<OtherTemplateEntity>
getData() { return list; } }
controller层
@PostMapping("/importMany") public R importMany(@RequestPart("file")
MultipartFile file) throws IOException { return easyExcelService.importManyExcel
(file); }
service实现层
public R importManyExcel(MultipartFile file) throws IOException { Map<String,
Object> map = getTemplateEntitiesMany(file); List<TemplateEntity> data1 = (List<
TemplateEntity>) map.get("data1"); List<OtherTemplateEntity> data2 = (List<
OtherTemplateEntity>) map.get("data2"); log.info("data1数据=={}", data1); log.info
("data2数据=={}", data2); return R.success(map); } private Map<String, Object>
getTemplateEntitiesMany(MultipartFile file) throws IOException { Map<String,
Object> map = new HashMap<>(); TemplateListener listener = new TemplateListener(
); // 定义的 listener OtherTemplateListener otherListener = new
OtherTemplateListener(); ExcelReader excelReader = EasyExcel.read(file.
getInputStream()).build(); // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
// readSheet参数设置读取sheet的序号 // 读取sheet1 ReadSheet readSheet1 = EasyExcel.
readSheet(0).head(TemplateEntity.class).registerReadListener(listener).build();
// 读取sheet3 ReadSheet readSheet2 = EasyExcel.readSheet(2).head(
OtherTemplateEntity.class).registerReadListener(otherListener).build();
excelReader.read(readSheet1, readSheet2); // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
excelReader.finish(); // 取出数据放入map中,然后返回 List<TemplateEntity> data1 = listener.
getData(); List<OtherTemplateEntity> data2 = otherListener.getData(); map.put(
"data1", data1); map.put("data2", data2); return map; }
<>读取结果
{ "code": 200, "msg": "OK", "message": null, "data": { "data2": [ { "label":
"a", "name": "a1", "type": "t1", "date": "2022-01-07" }, { "label": "b", "name":
"b1", "type": "t2", "date": "2022-01-07" } ...... ], "data1": [ { "label": 1,
"str": "a", "num": 20, "date": "2021-12-20" }, { "label": 2, "str": "b", "num":
30, "date": "2021-12-20" } ...... ] } }
<>两sheet表头数据一致
在sheet2加上数据,和sheet1的表头数据一致
<>具体实现
数据实体类,由于sheet1和sheet2表头一致,故用一个实体类即可
@Data public class TemplateEntity { @ExcelProperty("标号") private Integer label;
@ExcelProperty("字符串") private String str; @ExcelProperty("数字") private Integer
num; @ExcelProperty(value = "时间") @DateTimeFormat("yyyy-MM-dd") private String
date; }
监听类
public class TemplateListener extends AnalysisEventListener<TemplateEntity> {
private List<TemplateEntity> list = new ArrayList<>(); @Override public void
invoke(TemplateEntity data, AnalysisContext context) { list.add(data); }
@Override public void doAfterAllAnalysed(AnalysisContext context) {} public List
<TemplateEntity> getData() { return list; } }
service实现层
这里返回什么根据自己的业务需求,我是把两个sheet的数据分别放在各自的集合里了,也可以都放到一个集合里返回,具体实现看个人需求
@Override public R importManyExcelEq(MultipartFile file) throws IOException {
Map<String, Object> map = getTemplateEntitiesManyEq(file); List<TemplateEntity>
data1= (List<TemplateEntity>) map.get("data1"); List<TemplateEntity> data2 = (
List<TemplateEntity>) map.get("data2"); log.info("data1数据=={}", data1); log.info
("data2数据=={}", data2); return R.success(map); } private Map<String, Object>
getTemplateEntitiesManyEq(MultipartFile file) throws IOException { Map<String,
Object> map = new HashMap<>(); TemplateListener listenerSheet1 = new
TemplateListener(); // 定义的 listener TemplateListener listenerSheet2 = new
TemplateListener(); ExcelReader excelReader = EasyExcel.read(file.getInputStream
()).build(); // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener //
readSheet参数设置读取sheet的序号 // 读取sheet1 ReadSheet readSheet1 = EasyExcel.readSheet(0
).head(TemplateEntity.class).registerReadListener(listenerSheet1).build(); //
读取sheet2 ReadSheet readSheet2 = EasyExcel.readSheet(1).head(TemplateEntity.class
).registerReadListener(listenerSheet2).build(); excelReader.read(readSheet1,
readSheet2); // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的 excelReader.finish(); List<
TemplateEntity> data1 = listenerSheet1.getData(); List<TemplateEntity> data2 =
listenerSheet2.getData(); map.put("data1", data1); map.put("data2", data2);
return map; }
<>读取结果
{ "code": 200, "msg": "OK", "message": null, "data": { "data2": [ { "label": 1,
"str": "a2", "num": 200, "date": "2022-02-15" }, { "label": 2, "str": "b2",
"num": 300, "date": "2022-02-15" } ...... ], "data1": [ { "label": 1, "str": "a"
, "num": 20, "date": "2021-12-20" }, { "label": 2, "str": "b", "num": 30, "date"
: "2021-12-20" } ...... ] } }
<>多行头
读取时设置头行数即可
headRowNumber是头行数,如下是设置头行数2,那么读取时会从第三行开始读取数据
private List<TemplateEntity> getTemplateEntities(MultipartFile file) throws
IOException { TemplateListener listener = new TemplateListener(); // 定义的
listener EasyExcel.read(file.getInputStream(), TemplateEntity.class, listener).
sheet(0).headRowNumber(2).doRead(); // 返回 所有数据 return listener.getData(); }
<>读取表头数据
在监听类中重写invokeHeadMap方法,将表头数据也添加即可
public class TemplateListener extends AnalysisEventListener<TemplateEntity> {
private List<TemplateEntity> list = new ArrayList<>(); @Override public void
invoke(TemplateEntity data, AnalysisContext context) { list.add(data); }
@Override public void doAfterAllAnalysed(AnalysisContext context) {} public List
<TemplateEntity> getData() { return list; } @Override public void invokeHeadMap(
Map<Integer, String> headMap, AnalysisContext context) { // 读取到头数据 LOGGER.info(
"解析到一条头数据:{}", JSON.toJSONString(headMap)) }
<>Springboot + Easyexcel 写入数据
<>简单导出excel
实体类省略,还是上面的TemplateEntity
导出excel数据,这里有两种写法,拟定好文件名称直接传入方法,会自动创建一个文件
// 模拟数据 private List<TemplateEntity> exportData() { List<TemplateEntity>
entities= new ArrayList<>(); for (int i = 0; i< 10; i++) { TemplateEntity entity
= new TemplateEntity(); entity.setStr("字符串" + i); entity.setDate("数据" + i);
entity.setLabel(i+1); entity.setNum(i); entities.add(entity); } return entities;
} public R export() { String path = "C:\\Users\\EDZ\\Desktop\\"; // 写法1 String
fileName= path + System.currentTimeMillis() + ".xlsx"; // 这里
需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, TemplateEntity.class).sheet("模板").doWrite(exportData()
); // 写法2 // 这里 需要指定写用哪个class去写 ExcelWriter excelWriter = EasyExcel.write(
fileName, TemplateEntity.class).build(); WriteSheet writeSheet = EasyExcel.
writerSheet("模板").build(); excelWriter.write(exportData(), writeSheet); //
千万别忘记finish 会帮忙关闭流 excelWriter.finish(); return R.success(); }
写入后的结果
<>过滤导出列
public R export() { String path = "C:\\Users\\EDZ\\Desktop\\"; String fileName
= path + System.currentTimeMillis() + ".xlsx"; // 加入要忽略date字段 Set<String>
excludeColumnFiledNames= new HashSet<String>(); excludeColumnFiledNames.add(
"date"); EasyExcel.write(fileName,TemplateEntity.class).excludeColumnFiledNames(
excludeColumnFiledNames).sheet("模板").doWrite(exportData()); }
写入后结果
<>复杂头写入
实体类
@Data public class TemplateEntity { @ExcelProperty({"主标题", "标号"}) private
Integer label; @ExcelProperty({"主标题", "字符串"}) private String str; @ExcelProperty
({"主标题", "数字"}) private Integer num; @ExcelProperty({"主标题", "时间"})
@DateTimeFormat("yyyy-MM-dd") private String date; }
写入后数据
<>多sheet写入
<>写入到同一个sheet
@Override public R export() { String path = "C:\\Users\\EDZ\\Desktop\\"; String
fileName= path + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, TemplateEntity.class).build(
); // 这里注意 如果同一个sheet只要创建一次 WriteSheet writeSheet = EasyExcel.writerSheet("模板").
build(); // 去调用写入,这里我调用了3次,实际使用时根据数据库分页的总的页数来 for (int i = 0; i < 3; i++) { //
分页去数据库查询数据 这里可以去数据库查询每一页的数据 List<TemplateEntity> data = exportData();
excelWriter.write(data, writeSheet); } // 千万别忘记finish 会帮忙关闭流 excelWriter.finish(
); return R.success(); }
<>写到不同sheet,同一个表头
@Override public R export() { String path = "C:\\Users\\EDZ\\Desktop\\"; String
fileName= path + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去写
WriteSheet writeSheet; ExcelWriter excelWriter = EasyExcel.write(fileName,
TemplateEntity.class).build(); //
去调用写入,这里我调用了三次,实际使用时根据数据库分页的总的页数来。这里最终会写到3个sheet里面 for (int i = 0; i < 3; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo writeSheet = EasyExcel.writerSheet(i, "模板" +
i).build(); // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 List<TemplateEntity> data =
exportData(); excelWriter.write(data, writeSheet); } // 千万别忘记finish 会帮忙关闭流
excelWriter.finish(); return R.success(); }
写入后结果
<>写到不同sheet,不同的表头
public R export() { String path = "C:\\Users\\EDZ\\Desktop\\"; String fileName
= path + System.currentTimeMillis() + ".xlsx"; WriteSheet writeSheet;
ExcelWriter excelWriter = EasyExcel.write(fileName).build(); //
去调用写入,这里我调用了3次,实际使用时根据数据库分页的总的页数来。这里最终会写到3个sheet里面 for (int i = 0; i < 3; i++) {
// 我这里 sheet1和sheet2用TemplateEntity类,sheet3用OtherTemplateEntity if (i <= 1) {
writeSheet= EasyExcel.writerSheet(i, "模板" + (i + 1)).head(TemplateEntity.class).
build(); // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 List<TemplateEntity> data = exportData()
; excelWriter.write(data, writeSheet); } else { writeSheet = EasyExcel.
writerSheet(i, "模板" + (i + 1)).head(OtherTemplateEntity.class).build(); //
分页去数据库查询数据 这里可以去数据库查询每一页的数据 List<OtherTemplateEntity> data = exportDataOther();
excelWriter.write(data, writeSheet); } } // 千万别忘记finish 会帮忙关闭流 excelWriter.
finish(); return R.success(); }
写入后结果
sheet1(TemplateEntity类的表头)
sheet3(OtherTemplateEntity类的表头)
收工!