Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

Springboot + Easyexcel 读取数据

简单读取excel文件

读取下图的 excel 数据

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

导入依赖,阿里的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文件

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

实体类中可以使用@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目前是空的数据表

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

思路:需要再定义一个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的表头数据一致
Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

具体实现

数据实体类,由于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();
}

写入后的结果

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

过滤导出列

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());   
    
}

写入后结果

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

复杂头写入

实体类

@Data
public class TemplateEntity {

    @ExcelProperty({"主标题", "标号"})
    private Integer label;

    @ExcelProperty({"主标题", "字符串"})
    private String str;

    @ExcelProperty({"主标题", "数字"})
    private Integer num;

    @ExcelProperty({"主标题", "时间"})
    @DateTimeFormat("yyyy-MM-dd")
    private String date;
}

写入后数据

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

多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();
}

写入后结果

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

写到不同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类的表头)

Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现

sheet3(OtherTemplateEntity类的表头)
Springboot + Easyexcel读取写入数据,多头行数,多sheet,复杂表头简单实现
收工!

相关文章

暂无评论

暂无评论...