• 导入导出Excel


    EasyExcel 的导出导入支持两种方式进行处理

    easyexcel 导出不用监听器,导入需要写监听器
    • 第一种是通过实体类注解方式来生成文件和反解析文件数据映射成对象
    • 第二种是通过动态参数化生成文件和反解析文件数据

    下面我们以用户信息的导出导入为例,分别介绍两种处理方式。

    一、导入:简单实现

    在这里插入图片描述

    1. 导入依赖,阿里的easyexcel插件

    
        com.alibaba
        easyexcel
        2.1.6
    
    • 1
    • 2
    • 3
    • 4
    • 5

    创建一个用来 读取 excel的实体类

    实体类的属性可以用

    • @ExcelProperty(index = 0),index=0,找的是上图 A列(第一列)

    • @ExcelProperty(value = “标号”)

    两种都可以用,但是不要两个一起用

    2. 程序

    2-1. 实体类:

    实体类中可以使用@DateFormat(阿里包下的)注解:

    要使用String类型来接收数据才有用

    
    @Data 
    public class TemplateEntity {
    
        @ExcelProperty("标号")
        private Integer label;
    
        @ExcelProperty("字符串")
        private String str;
    
        @ExcelProperty("数字")
        private Integer num;
     	
        @ExcelProperty("时间")
        // 这里需要用string接收才会格式化
        @DateTimeFormat("yyyy-MM-dd")
        private String date;
        
    }
    ————————————————
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    2-2. 定义一个 监听类:
    public class TemplateListener extends AnalysisEventListener {
    
        private List list = new ArrayList<>();
    
        // 一条一条读取数据,全部添加到list集合里
        @Override
        public void invoke(TemplateEntity data, AnalysisContext analysisContext) {
            list.add(data);
        }
        @Override
        public void doAfterAllAnalysed(AnalysisContext analysisContext) {}
    
        public List getData() {
            return list;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    2-3. 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 entities = getTemplateEntities(file);
            // 处理数据
            System.out.println(entities);
            return Result.success(entities);
        }
        // 读取 excel 数据
        private List getTemplateEntities(MultipartFile file) throws IOException {
            TemplateListener listener = new TemplateListener();	// 定义的 listener
            EasyExcel.read(file.getInputStream(), TemplateEntity.class, listener).sheet().doRead();
            
            // 返回 所有数据
            return listener.getData();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    2-4. 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);
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3. Postman测试

    {
        "code": 200,
        "msg": "处理成功",
        "data": [
            {
                "label": 1,
                "str": "a",
                "num": 20
            },
            {
                "label": 2,
                "str": "b",
                "num": 30
            },
            {
                "label": 3,
                "str": "c",
                "num": 40
            },
           ...
    }
    ————————————————
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    二、导入:多头行数,多sheet,复杂表头

    1. 两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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    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;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    监听类

    同上,只是写两个各自的

    controller层
    
    @PostMapping("/importMany")
    public R importMany(@RequestPart("file") MultipartFile file) throws IOException {
        return easyExcelService.importManyExcel(file);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    service实现层
    public R importManyExcel(MultipartFile file) throws IOException {
        Map map = getTemplateEntitiesMany(file);
        List data1 = (List) map.get("data1");
        List data2 = (List) map.get("data2");
        log.info("data1数据=={}", data1);
        log.info("data2数据=={}", data2);
        return R.success(map);
    }
    
    private Map getTemplateEntitiesMany(MultipartFile file) throws IOException {
            Map 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 data1 = listener.getData();
            List data2 = otherListener.getData();
            map.put("data1", data1);
            map.put("data2", data2);
    
            return map;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    {
        "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"
                }
                ......
            ]
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    多行头

    读取时设置头行数即可

    headRowNumber是头行数,如下是设置头行数2,那么读取时会从第三行开始读取数据

    private List 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();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    读取表头数据

    在监听类中重写invokeHeadMap方法,将表头数据也添加即可

    public class TemplateListener extends AnalysisEventListener {
    
        private List list = new ArrayList<>();
        @Override
        public void invoke(TemplateEntity data, AnalysisContext context) {
            list.add(data);
        }
    
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {}
    
        public List getData() {
            return list;
        }
    
        @Override
        public void invokeHeadMap(Map headMap, AnalysisContext context) {
            // 读取到头数据
            LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap))
        }
    ————————————————
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    三、导出:简单简单实现

    实体类省略,还是上面的TemplateEntity

    导出excel数据,这里有两种写法,拟定好文件名称直接传入方法,会自动创建一个文件

    1. 模拟数据 10条数据
    // 模拟数据
    private List exportData() {
        List 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    3. 程序
    
    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();
    }
    ————————————————
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    在这里插入图片描述

    3. 过滤导出列
    public R export() {
        String path = "C:\\Users\\EDZ\\Desktop\\";
        
        String fileName = path + System.currentTimeMillis() + ".xlsx";
        
        // 加入要忽略date字段
        Set excludeColumnFiledNames = new HashSet();
        excludeColumnFiledNames.add("date");
    	EasyExcel.write(fileName,TemplateEntity.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板").doWrite(exportData());   
        
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

    五、导入:复杂头 合并表头

    1. 实体类
    @Data
    public class TemplateEntity {
    
        @ExcelProperty({"主标题", "标号"})
        private Integer label;
    
        @ExcelProperty({"主标题", "字符串"})
        private String str;
    
        @ExcelProperty({"主标题", "数字"})
        private Integer num;
    
        @ExcelProperty({"主标题", "时间"})
        @DateTimeFormat("yyyy-MM-dd")
        private String date;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述

    六、动态自由导出导入

    在实际使用开发中,我们不可能每来一个 excel 导入导出需求,就编写一个实体类,很多业务需求需要根据不同的字段来动态导入导出,没办法基于实体类注解的方式来读取文件或者写入文件。

    因此,基于EasyExcel提供的动态参数化生成文件和动态监听器读取文件方法,我们可以单独封装一套动态导出导出工具类,省的我
    们每次都需要重新编写大量重复工作,我在实际使用过程,封装出来的工具类如下:

    
            
            
                com.google.guava
                guava
                20.0
            
    
    		
    		    com.alibaba
    		    easyexcel
    		    3.0.5
    		
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    1. 导出

    1-1. 编写一个动态导出工具类
    
    package com.ltkj.common.excel;
    
    import com.alibaba.excel.EasyExcel;
    import com.alibaba.excel.write.style.column.LongestMatchColumnWidthStyleStrategy;
    import com.google.common.collect.Lists;
    import com.google.common.collect.Maps;
    import com.ltkj.common.utils.JsonUtils;
    import org.apache.commons.collections4.CollectionUtils;
    import org.apache.commons.collections4.MapUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 动态导出工具类测试
     *
     * @author wangl
     * @date 2023-10-10
     */
    public class DynamicEasyExcelExportUtilTest {
    
        private static final Logger log = LoggerFactory.getLogger(DynamicEasyExcelExportUtilTest.class);
    
        private static final String DEFAULT_SHEET_NAME = "sheet1";
    
        /**
         * 动态生成导出模版(单表头)
         *
         * @param headColumns 列名称
         * @return excel文件流
         */
        public static byte[] exportTemplateExcelFile(List headColumns) {
            List> excelHead = Lists.newArrayList();
            byte[] stream = createExcelFile(excelHead, new ArrayList<>());
            return stream;
        }
    
        /**
         * 动态生成模版(复杂表头)
         *
         * @param excelHead 列名称
         * @return
         */
        public static byte[] exportTemplateExcelFileCustomHead(List> excelHead) {
            byte[] stream = createExcelFile(excelHead, new ArrayList<>());
            return stream;
        }
    
        /**
         * 动态导出文件(通过map方式计算)
         *
         * @param headColumnMap 有序列头部
         * @param dataList      数据体
         * @return
         */
        public static byte[] exportExcelFile(LinkedHashMap headColumnMap, List> dataList) {
            //获取列名称
            List> excelHead = new ArrayList<>();
            if (MapUtils.isNotEmpty(headColumnMap)) {
                //key为匹配符,value为列名,如果多级列名用逗号隔开
                headColumnMap.entrySet().forEach(entry -> {
                    excelHead.add(Lists.newArrayList(entry.getValue().split(",")));
                });
            }
            List> excelRows = new ArrayList<>();
            if (MapUtils.isNotEmpty(headColumnMap) && CollectionUtils.isNotEmpty(dataList)) {
                for (Map dataMap : dataList) {
                    List rows = new ArrayList<>();
                    headColumnMap.entrySet().forEach(headColumnEntry -> {
                        if (dataMap.containsKey(headColumnEntry.getKey())) {
                            Object data = dataMap.get(headColumnEntry.getKey());
                            rows.add(data);
                        }
                    });
                    excelRows.add(rows);
                }
            }
            byte[] stream = createExcelFile(excelHead, excelRows);
            return stream;
        }
    
    
        /**
         * 生成文件(自定义头部排列)
         *
         * @param rowHeads
         * @param excelRows
         * @return
         */
        public static byte[] customerExportExcelFile(List> rowHeads, List> excelRows) {
            //将行头部转成easyexcel能识别的部分
            List> excelHead = transferHead(rowHeads);
            return createExcelFile(excelHead, excelRows);
        }
    
        /**
         * 生成文件
         *
         * @param excelHead
         * @param excelRows
         * @return
         */
        private static byte[] createExcelFile(List> excelHead, List> excelRows) {
            try {
                if (CollectionUtils.isNotEmpty(excelHead)) {
                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                    EasyExcel.write(outputStream).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy())
                        .head(excelHead)
                        .sheet(DEFAULT_SHEET_NAME)
                        .doWrite(excelRows);
                    return outputStream.toByteArray();
                }
            } catch (Exception e) {
                log.error("动态生成excel文件失败,headColumns:" + JsonUtils.toJsonString(excelHead) + ",excelRows:" + JsonUtils.toJsonString(excelRows), e);
            }
            return null;
        }
    
        /**
         * 将行头部转成easyexcel能识别的部分
         *
         * @param rowHeads
         * @return
         */
        public static List> transferHead(List> rowHeads) {
            //将头部列进行反转
            List> realHead = new ArrayList<>();
            if (CollectionUtils.isNotEmpty(rowHeads)) {
                Map> cellMap = new LinkedHashMap<>();
                //遍历行
                for (List cells : rowHeads) {
                    //遍历列
                    for (int i = 0; i < cells.size(); i++) {
                        if (cellMap.containsKey(i)) {
                            cellMap.get(i).add(cells.get(i));
                        } else {
                            cellMap.put(i, Lists.newArrayList(cells.get(i)));
                        }
                    }
                }
                //将列一行一行加入realHead
                cellMap.entrySet().forEach(item -> realHead.add(item.getValue()));
            }
            return realHead;
        }
    
        /**
         * 导出文件测试
         *
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            //导出包含数据内容的文件(方式一)
            LinkedHashMap headColumnMap = Maps.newLinkedHashMap();
            headColumnMap.put("name", "姓名");
            headColumnMap.put("sex", "性别");
            headColumnMap.put("titleName", "职称信息一, 职称名称");
            headColumnMap.put("titleLevel", "职称信息一, 职称等级");
            headColumnMap.put("titleName_2", "职称信息二, 职称名称");
            headColumnMap.put("titleLevel_2", "职称信息二, 职称等级");
            List> dataList = new ArrayList<>();
            for (int i = 0; i < 5; i++) {
                Map dataMap = Maps.newHashMap();
                dataMap.put("name", "张三" + i);
                dataMap.put("sex", "男");
                dataMap.put("titleName", "会计师");
                dataMap.put("titleLevel", i + " 级");
                dataMap.put("titleName_2", "律师");
                dataMap.put("titleLevel_2", i * 10 + " 级");
                dataList.add(dataMap);
            }
            byte[] stream1 = exportExcelFile(headColumnMap, dataList);
            FileOutputStream outputStream1 = new FileOutputStream(new File("easyexcel-export-user1.xlsx"));
            outputStream1.write(stream1);
            outputStream1.close();
    
    
    
    
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    1-2. 测试: easyexcel-export-user1.xlsx

    在这里插入图片描述

    接上面同一个类里 方法二
    
            //导出包含数据内容的文件(方式二)
            //头部,第一层
            List head1 = new ArrayList<>();
            head1.add("第1行头部列1-序号");
            head1.add("第1行头部列2-缴纳单位");
            head1.add("第1行头部列3-姓名");
            head1.add("第1行头部列4-身份证号");
    
            // 第一行:一直是列1 列1 列1:就是合并列的意思
            head1.add("第1行头部列5-五险一金信息");
            head1.add("第1行头部列5-五险一金信息");
            head1.add("第1行头部列5-五险一金信息");
            head1.add("第1行头部列5-五险一金信息");
            head1.add("第1行头部列5-五险一金信息");
            head1.add("第1行头部列5-五险一金信息");
    
            //头部,第二层
            List head2 = new ArrayList<>();
            // 2行 和 1行 行头相同: 就是合并行的意思
            head2.add("第1行头部列1-序号");
            head2.add("第1行头部列2-缴纳单位");
            head2.add("第1行头部列3-姓名");
            // 2-3行合并,不和1行合并
            head2.add("第1行头部列3-身份证号");
    
            head2.add("第2行头部列5-养老保险");
            head2.add("第2行头部列5-养老保险");
            head2.add("第2行头部列5-养老保险");
    
            head2.add("第2行头部列8-医疗保险");
            head2.add("第2行头部列8-医疗保险");
            head2.add("第2行头部列8-医疗保险");
    
            //头部,第三层
            List head3 = new ArrayList<>();
            // 3行 和 2行 行头相同: 就是合并行的意思
            head3.add("第1行头部列1-序号");
            head3.add("第1行头部列2-缴纳单位");
            head3.add("第1行头部列3-姓名");
            // 2-3行合并,不和1行合并
            head3.add("第1行头部列3-身份证号");
    
            head3.add("第3行头部列5-缴费基数");
            head3.add("单位缴纳比例");
            head3.add("第3行头部列7-个人缴纳比例");
    
            head3.add("第3行头部列8-缴费基数");
            head3.add("单位缴纳比例");
            head3.add("第3行头部列10-个人缴纳比例");
    
            //封装头部
            List> allHead = new ArrayList<>();
            allHead.add(head1);
            allHead.add(head2);
            allHead.add(head3);
    
            //封装数据体
            //第一行数据
            List data1 = Lists.newArrayList("001", "旅投科技", "赵一", "130xxx1", 5000, 5, 6, 6000, 7, 8);
            //第二行数据
            List data2 = Lists.newArrayList("002", "三药集团", "孙二", "232xxx2", 8000, 8, 9, 9000, 10, 12);
            List> allData = Lists.newArrayList(data1, data2);
            byte[] stream2 = customerExportExcelFile(allHead, allData);
            FileOutputStream outputStream2 = new FileOutputStream(new File("easyexcel-export-user2.xlsx"));
            outputStream2.write(stream2);
            outputStream2.close();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    在这里插入图片描述

    2. 导入: EasyExcel 导入需要一个监听器,导出不需要

    
            
                com.alibaba
                fastjson
                2.0.1
            
    
            
            
                com.google.guava
                guava
                20.0
            
        
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    2-1. 编写一个动态导入监听器

    
    package com.ltkj.common.excel;
    
    import com.alibaba.excel.context.AnalysisContext;
    import com.alibaba.excel.event.AnalysisEventListener;
    import com.alibaba.fastjson2.JSON;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    /**
     * EasyExcel 导入需要一个监听器,导出不需要
     *
     * @author wangl
     * @date 2023-10-14
     */
    public class DynamicEasyExcelListener extends AnalysisEventListener> {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(DynamicEasyExcelListener.class);
    
        /**
         * 表头数据(存储所有的表头数据)
         */
        private List> headList = new ArrayList<>();
    
        /**
         * 数据体
         */
        private List> dataList = new ArrayList<>();
    
        /**
         * 这里会一行行的返回头
         *
         * @param headMap
         * @param context
         */
        @Override
        public void invokeHeadMap(Map headMap, AnalysisContext context) {
            LOGGER.info("解析到一条标题头数据:{}", JSON.toJSONString(headMap));
            //存储全部表头数据
            headList.add(headMap);
        }
    
        /**
         * 这个每一条数据解析都会来调用
         *
         * @param data    one row value. Is is same as {@link AnalysisContext#readRowHolder()}
         * @param context
         */
        @Override
        public void invoke(Map data, AnalysisContext context) {
            // 解析一条 放到 dataList里,最后返回 dataList 即可 
            LOGGER.info("解析到一条data数据:{}", JSON.toJSONString(data));
            dataList.add(data);
        }
    
        /**
         * 所有数据解析完成了 都会来调用
         *
         * @param context
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
            // 这里也要保存数据,确保最后遗留的数据也存储到数据库
            LOGGER.info("所有数据解析完成!");
        }
    
        public List> getHeadList() {
            return headList;
        }
    
        public List> getDataList() {
            return dataList;
        }
    }
    
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81

    2-2. 编写动态导入工具类

    package com.ltkj.common.excel;
    
    import com.ali
    baba.excel.EasyExcelFactory;
    import com.alibaba.excel.util.IoUtils;
    import com.alibaba.fastjson.JSONArray;
    import com.google.common.collect.Lists;
    import org.apache.commons.collections4.CollectionUtils;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import java.io.ByteArrayInputStream;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.util.LinkedHashMap;
    import java.util.List;
    import java.util.Map;
    
    /**
     * 编写导入工具类
     *
     * @author wangl
     * @date 2023-10-14
     */
    public class DynamicEasyExcelImportUtils {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(DynamicEasyExcelListener.class);
    
        /**
         * 动态获取全部列和数据体,默认只有1行标题
         *
         * @param stream
         * @return
         */
        public static List> parseExcelToView(byte[] stream) {
            return parseExcelToView(stream, 1);
        }
    
        /**
         * 动态获取全部列和数据体,指定有几行标题
         *
         * @param stream         excel文件流
         * @param parseRowNumber 指定有几行标题
         * @return
         */
        public static List> parseExcelToView(byte[] stream, Integer parseRowNumber) {
            LOGGER.info("指定有[" + parseRowNumber + "]行标题");
            DynamicEasyExcelListener readListener = new DynamicEasyExcelListener();
            EasyExcelFactory.read(new ByteArrayInputStream(stream)).registerReadListener(readListener).headRowNumber(parseRowNumber).sheet("sheet1").doRead();
            List> headList = readListener.getHeadList();
            if (CollectionUtils.isEmpty(headList)) {
                throw new RuntimeException("Excel未包含表头");
            }
            List> dataList = readListener.getDataList();
            if (CollectionUtils.isEmpty(dataList)) {
                throw new RuntimeException("Excel未包含数据");
            }
            //获取头部,取最后一次解析的列头数据
            Map excelHeadIdxNameMap = headList.get(headList.size() - 1);
            //封装数据体
            List> excelDataList = Lists.newArrayList();
            for (Map dataRow : dataList) {
                Map rowData = new LinkedHashMap<>();
                excelHeadIdxNameMap.entrySet().forEach(columnHead -> {
                    rowData.put(columnHead.getValue(), dataRow.get(columnHead.getKey()));
                });
                excelDataList.add(rowData);
            }
            return excelDataList;
        }
    
        /**
         * 文件导入测试
         *
         * @param args
         * @throws IOException
         */
        public static void main(String[] args) throws IOException {
            FileInputStream inputStream = new FileInputStream(new File("easyexcel-export-user1.xlsx"));
            byte[] stream = IoUtils.toByteArray(inputStream);
            List> dataList = parseExcelToView(stream, 2);
            // 打印最后结果  全部数据   不含标题
            System.out.println(JSONArray.toJSONString(dataList));
            inputStream.close();
        }
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    在这里插入图片描述
    在这里插入图片描述

    所有数据解析完成!
    [{"姓名":"张三0","性别":"男","职称名称":"律师","职称等级":"0 级"},
    {"姓名":"张三1","性别":"男","职称名称":"律师","职称等级":"10 级"},
    {"姓名":"张三2","性别":"男","职称名称":"律师","职称等级":"20 级"},
    {"姓名":"张三3","性别":"男","职称名称":"律师","职称等级":"30 级"},
    {"姓名":"张三4","性别":"男","职称名称":"律师","职称等级":"40 级"}]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    为了方便后续的操作流程,在解析数据的时候,会将列名作为key

    三、小结
    在实际的业务开发过程中,根据参数动态实现 Excel 的导出导入还是非常广的。

  • 相关阅读:
    点云目标检测——pointpillars环境配置与训练
    足底筋膜炎怎么治疗最快最有效
    springboot毕设项目超市进销存管理系统7cq1l(java+VUE+Mybatis+Maven+Mysql)
    进程与线程
    C语言程序环境和预处理
    Vue2 Element description组件 列合并
    [微前端实战]---040 子应用接入微前端-react15,react17
    形态学图像处理
    ArrayList 可以完全替代数组吗?
    Nacos源码 (7) Nacos与Spring
  • 原文地址:https://blog.csdn.net/nalanxiaoxiao2011/article/details/133749412