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类的表头)
收工!
转载请注明:Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现 | 胖虎的工具箱-编程导航