{"id":38814664,"url":"https://github.com/joker-pper/easy-excel-support","last_synced_at":"2026-01-17T12:58:58.711Z","repository":{"id":57733719,"uuid":"432637877","full_name":"joker-pper/easy-excel-support","owner":"joker-pper","description":"基于EasyExcel进行封装的项目,提供一定的常用读写能力,希望可以进一步简化EasyExcel的使用.","archived":false,"fork":false,"pushed_at":"2021-12-15T14:05:20.000Z","size":85,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-07-06T11:16:22.084Z","etag":null,"topics":["easyexcel","excel"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joker-pper.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-11-28T06:34:55.000Z","updated_at":"2024-03-07T13:37:53.000Z","dependencies_parsed_at":"2022-08-24T11:20:16.763Z","dependency_job_id":null,"html_url":"https://github.com/joker-pper/easy-excel-support","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/joker-pper/easy-excel-support","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joker-pper%2Feasy-excel-support","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joker-pper%2Feasy-excel-support/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joker-pper%2Feasy-excel-support/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joker-pper%2Feasy-excel-support/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joker-pper","download_url":"https://codeload.github.com/joker-pper/easy-excel-support/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joker-pper%2Feasy-excel-support/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28508903,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-17T11:50:55.898Z","status":"ssl_error","status_checked_at":"2026-01-17T11:50:55.569Z","response_time":85,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["easyexcel","excel"],"created_at":"2026-01-17T12:58:56.035Z","updated_at":"2026-01-17T12:58:58.700Z","avatar_url":"https://github.com/joker-pper.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\n# easy-excel-support\n\n    基于EasyExcel进行封装的项目,提供一定的常用读写能力,希望可以进一步简化EasyExcel的使用.\n\n## 版本\n\n+ java 1.8+\n\n+ EasyExcel 2.x\n\n## 项目版本\n\nhttps://search.maven.org/artifact/io.github.joker-pper/easy-excel-support\n\n```\n注: \n\n  1.x版本对应的为EasyExcel 2.x\n  \n  2.x版本对应的为EasyExcel 3.x\n```\n\n## easy-excel-read-support\n\n### 功能\n\n+ 简化使用\n\n+ 基于Options包含常规属性并提供入口设置其他属性\n\n+ 提供部分listener支持业务\n\n\n### 快速使用\n\n```\n\u003cdependency\u003e\n  \u003cgroupId\u003eio.github.joker-pper\u003c/groupId\u003e\n  \u003cartifactId\u003eeasy-excel-read-support\u003c/artifactId\u003e\n  \u003cversion\u003e${version}\u003c/version\u003e\n\u003c/dependency\u003e\n\n注: \n  当前release: 1.0.0\n```\n\n### 核心API\n\n```\n\n\u003cT\u003e void read(InputStream inputStream, ReadListener\u003cT\u003e readListener)\n\n\u003cT\u003e void read(InputStream inputStream, Class\u003cT\u003e headClass, ReadListener\u003cT\u003e readListener)\n\n\u003cT\u003e void read(InputStream inputStream, ReadListener\u003cT\u003e readListener, ExcelReadOptions\u003cT\u003e readOptions)\n\nvoid repeatedRead(InputStream inputStream, ExcelRepeatedReadOptions readOptions, List\u003cExcelReadSheetOptions\u003c?\u003e\u003e readSheetOptionsList)\n```\n\n\n### @ExcelProperty使用问题\n\n```\n1. 通过列名匹配(需一致,否则匹配不到值),如果名字重复会导致只有一个字段读取到数据\n\n2. 若涉及指定数据头行索引值非1时,须指定列索引进行匹配\n```\n\n\n### 常见场景示例\n\n\u003e 不创建映射类最简单的读\n\n```\n\n        File inputFile = new File(\"src/test/resources/files/read-001.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n        ExcelReadSupportUtils.read(inputStream, new DefaultReadListener\u003cMap\u003cInteger, Object\u003e\u003e() {\n\n            @Override\n            public void invoke(Map\u003cInteger, Object\u003e data, AnalysisContext context) {\n\n                System.out.println(String.format(\"当前行数据为: %s\", data));\n            }\n\n            @Override\n            public void doAfterAllAnalysed(AnalysisContext context) {\n                System.out.println(\"数据解析完毕...\");\n\n            }\n\n        });\n\n```\n\n\u003e 创建映射类最简单的读\n\n```\n\n        File inputFile = new File(\"src/test/resources/files/read-001.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        ExcelReadSupportUtils.read(inputStream, Read001.class, new DefaultReadListener\u003cRead001\u003e() {\n\n            @Override\n            public void invoke(Read001 data, AnalysisContext context) {\n                System.out.println(String.format(\"当前行数据为: %s\", data));\n            }\n\n            @Override\n            public void doAfterAllAnalysed(AnalysisContext context) {\n                System.out.println(\"数据解析完毕...\");\n\n            }\n        });\n\n```\n\n\u003e 通过BatchResolveReadListener读取进行批量处理\n\n```\n\n        File inputFile = new File(\"src/test/resources/files/read-001.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        BatchResolveReadListener\u003cRead001\u003e readListener = new BatchResolveReadListener\u003c\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库 (不能保证整批数据全是合法的,如有特殊需求需要额外处理)\n            System.out.println(String.format(\"当前要批量处理的数据为:\\n %s\", dataList));\n        });\n\n        ExcelReadSupportUtils.read(inputStream, Read001.class, readListener);\n        System.out.println(String.format(\"处理的总数据个数为: %s\", readListener.getTotalCount()));\n\n```\n\n\u003e 通过BatchResolveReadListener读取并验证数据\n\n```\n\n        File inputFile = new File(\"src/test/resources/files/read-001.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        //第一遍先校验数据(如果有要求是文件中必须不包含错误数据时)\n        BatchResolveReadListener\u003cRead001\u003e toValidateReadListener = new BatchResolveReadListener\u003cRead001\u003e(dataList -\u003e {\n            System.out.println(String.format(\"当前要批量处理的数据为:\\n %s\", dataList));\n        }) {\n            @Override\n            public void validate(Read001 data) {\n                if (data == null || data.getName() == null \u0026\u0026 data.getRemark() == null) {\n                    //校验数据(根据具体要求来校验)\n                    throw new IllegalArgumentException(\"excel has invalid data!\");\n                }\n            }\n        };\n        ExcelReadSupportUtils.read(inputStream, Read001.class, toValidateReadListener);\n        System.out.println(String.format(\"处理的总数据个数为: %s\", toValidateReadListener.getTotalCount()));\n\n        //(模拟)第二遍再进行真正的持久化操作(注: 也可以把之前的解析的数据保存到text、json等再做持久化操作)\n        inputStream = new FileInputStream(inputFile);\n        BatchResolveReadListener\u003cRead001\u003e toSaveReadListener = new BatchResolveReadListener\u003c\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库\n            System.out.println(String.format(\"(模拟)当前保存的数据为:\\n %s\", dataList));\n        });\n\n        ExcelReadSupportUtils.read(inputStream, Read001.class, toSaveReadListener);\n        System.out.println(String.format(\"(模拟)保存的总数据个数为: %s\", toSaveReadListener.getTotalCount()));\n    \n```\n\n\u003e 通过ValidateReadListener简单验证再通过BatchResolveReadListener读取数据\n\n```\n        File inputFile = new File(\"src/test/resources/files/read-001.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        //第一遍先校验数据(如果有要求是文件中必须不包含错误数据时)\n        ValidateReadListener\u003cRead001\u003e toValidateReadListener = data -\u003e {\n            if (data == null || data.getName() == null \u0026\u0026 data.getRemark() == null) {\n                //校验数据(根据具体要求来校验)\n                throw new IllegalArgumentException(\"excel has invalid data!\");\n            }\n        };\n        ExcelReadSupportUtils.read(inputStream, Read001.class, toValidateReadListener);\n\n        //(模拟)第二遍再进行真正的持久化操作(注: 也可以把之前的解析的数据保存到text、json等再做持久化操作)\n        inputStream = new FileInputStream(inputFile);\n        BatchResolveReadListener\u003cRead001\u003e toSaveReadListener = new BatchResolveReadListener\u003c\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库\n            System.out.println(String.format(\"(模拟)当前保存的数据为:\\n %s\", dataList));\n        });\n\n        ExcelReadSupportUtils.read(inputStream, Read001.class, toSaveReadListener);\n        System.out.println(String.format(\"(模拟)保存的总数据个数为: %s\", toSaveReadListener.getTotalCount()));\n    \n```\n\n\n\u003e 通过AbstractBatchResolveAndConvertReadListener自定义转换并批量处理\n\n```\n        \n        File inputFile = new File(\"src/test/resources/files/read-001.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n        AbstractBatchResolveAndConvertReadListener\u003cRead001\u003e readListener = new AbstractBatchResolveAndConvertReadListener\u003cRead001\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库 (不能保证整批数据全是合法的,如有特殊需求需要额外处理)\n            System.out.println(String.format(\"当前要批量处理的数据为:\\n %s\", dataList));\n        }) {\n            @Override\n            protected Read001 convert(Map\u003cInteger, Object\u003e data, AnalysisContext context) {\n                Read001 read001 = new Read001();\n                read001.setName((String) data.get(0));\n                read001.setAge(Optional.ofNullable(data.get(1)).map(String::valueOf).map(Integer::valueOf).orElse(null));\n                read001.setSex((String) data.get(2));\n                return read001;\n            }\n        };\n        ExcelReadSupportUtils.read(inputStream, readListener);\n\n        System.out.println(String.format(\"处理的总数据个数为: %s\", readListener.getTotalCount()));\n\n```\n\n\u003e 动态解析自定义映射结果 (列名 -\u003e 列值)\n\n```\n\n        File inputFile = new File(\"src/test/resources/files/read-001.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        ExcelReadOptions readOptions = ExcelReadOptions.builder().headRowNumber(0).build();\n\n        ReadListener readListener = new AbstractBatchResolveAndConvertReadListener\u003cMap\u003cString, String\u003e\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库 (不能保证整批数据全是合法的,如有特殊需求需要额外处理)\n            System.out.println(String.format(\"当前要批量处理的数据为:\\n %s\", dataList));\n        }) {\n\n            private Map\u003cInteger, String\u003e headMap = new HashMap\u003c\u003e(8);\n\n            @Override\n            protected Map\u003cString, String\u003e convert(Map\u003cInteger, Object\u003e data, AnalysisContext context) {\n                int rowIndex = context.readRowHolder().getRowIndex();\n                if (rowIndex == 0) {\n                    data.forEach((cellIndex, cellValue) -\u003e {\n                        //为表头时放入headMap, key: 列索引 value: 列名\n                        headMap.put(cellIndex, Optional.ofNullable(cellValue).map(String::valueOf).orElse(String.format(\"列%s(系统生成)\", cellIndex)));\n                    });\n                    return null;\n                }\n                Map\u003cString, String\u003e resultMap = new HashMap\u003c\u003e(8);\n                data.forEach((cellIndex, cellValue) -\u003e {\n                    //按照列名对应的值进行处理\n                    resultMap.put(headMap.get(cellIndex), Optional.ofNullable(cellValue).map(String::valueOf).orElse(null));\n                });\n                return resultMap;\n            }\n        };\n        ExcelReadSupportUtils.read(inputStream, readListener, readOptions);\n        \n```\n\n\u003e 验证表头是否合法(并在表头的最后一行时停止读取)\n\n```\n        \n        File inputFile = new File(\"src/test/resources/files/read-001-head-row-num.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        ExcelReadOptions\u003cRead001ByIndex\u003e readOptions = ExcelReadOptions.\u003cRead001ByIndex\u003ebuilder().headClass(Read001ByIndex.class)\n                .headRowNumber(2)\n                .build();\n\n        List\u003cList\u003cString\u003e\u003e headRowsList = new ArrayList\u003c\u003e(2);\n        headRowsList.add(Arrays.asList(\"姓名\", \"年龄\", \"性别\", \"备注\"));\n        headRowsList.add(Arrays.asList(\"制作时间\"));\n\n        ReadListener\u003cRead001ByIndex\u003e readListener = new BreakReadListener\u003cRead001ByIndex\u003e() {\n\n            @Override\n            public void invokeHeadByString(Map\u003cInteger, String\u003e headMap, AnalysisContext context) {\n                System.out.println(String.format(\"head: %s\", headMap));\n                //验证为正确的表头\n                int rowIndex = context.readRowHolder().getRowIndex();\n\n                int headEndIndex = headRowsList.size() - 1;\n\n                List\u003cString\u003e headRowList = headRowsList.get(rowIndex);\n\n                List\u003cString\u003e rowTextList = headMap.values().stream().filter(it -\u003e it != null \u0026\u0026 !it.isEmpty()).map(String::trim).collect(Collectors.toList());\n\n                if (rowIndex == headEndIndex) {\n                    //为表头的最后一行时,设置停止读取\n                    makeBreakRead();\n\n                    if (rowTextList.size() != headRowList.size() || Optional.ofNullable(headMap.get(0)).map(String::trim).map(it -\u003e !it.startsWith(headRowList.get(0))).orElse(true)) {\n                        //当size不一致或第一列不是以对应的字符串开始时\n                        throw new IllegalArgumentException(\"无法识别的Excel文件,请确认是否上传正确！\");\n                    }\n\n                } else {\n                    if (!headRowList.equals(rowTextList)) {\n                        //当结果不一致时\n                        throw new IllegalArgumentException(\"无法识别的Excel文件,请确认是否上传正确！\");\n                    }\n                }\n            }\n\n            @Override\n            public void invoke(Read001ByIndex data, AnalysisContext context) {\n                //这里输出结果,验证是否会停止读取数据\n                System.out.println(String.format(\"当前行数据为: %s\", data));\n                throw new RuntimeException(\"当前示例只是验证表头是否正确,但并未停止读取数据行!\");\n            }\n\n        };\n\n        ExcelReadSupportUtils.read(inputStream, readListener, readOptions);\n        \n```\n\n\u003e 读取多个表,一次全部读取(表格式内容需一致)\n\n```\n        File inputFile = new File(\"src/test/resources/files/read-001-more-sheet.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        ExcelReadOptions\u003cRead001\u003e readOptions = ExcelReadOptions.\u003cRead001\u003ebuilder().headClass(Read001.class).isReadAll(true).build();\n        ReadListener\u003cRead001\u003e readListener = new BatchResolveReadListener\u003c\u003e(10, dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库 (不能保证整批数据全是合法的,如有特殊需求需要额外处理)\n            System.out.println(String.format(\"当前要批量处理的数据为:\\n %s\", dataList));\n        });\n        ExcelReadSupportUtils.read(inputStream, readListener, readOptions);\n\n```\n\n\u003e 读取多个表 - 多次读取\n\n```\n        File inputFile = new File(\"src/test/resources/files/read-001-more-sheet.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        //读取表一的数据\n        ExcelReadOptions\u003cRead001\u003e readOptions = ExcelReadOptions.\u003cRead001\u003ebuilder().headClass(Read001.class).build();\n        ReadListener\u003cRead001\u003e readListener = new BatchResolveReadListener\u003c\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库 (不能保证整批数据全是合法的,如有特殊需求需要额外处理)\n            System.out.println(String.format(\"(表一)当前要批量处理的数据为:\\n %s\", dataList));\n        });\n        ExcelReadSupportUtils.read(inputStream, readListener, readOptions);\n\n        System.out.println(\"-------——分隔符-------——\");\n\n        //读取表二的数据\n        inputStream = new FileInputStream(inputFile);\n        readOptions = ExcelReadOptions.\u003cRead001\u003ebuilder().headClass(Read001.class).sheetNo(1).build();\n        readListener = new BatchResolveReadListener\u003c\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库 (不能保证整批数据全是合法的,如有特殊需求需要额外处理)\n            System.out.println(String.format(\"(表二)当前要批量处理的数据为:\\n %s\", dataList));\n        });\n        ExcelReadSupportUtils.read(inputStream, readListener, readOptions);\n    \n```\n\n\u003e 读取多个表 - 一次读取\n\n```\n        File inputFile = new File(\"src/test/resources/files/read-001-more-sheet-repeated.xlsx\");\n        InputStream inputStream = new FileInputStream(inputFile);\n\n        ExcelRepeatedReadOptions readOptions = ExcelRepeatedReadOptions.builder().build();\n        List\u003cExcelReadSheetOptions\u003c?\u003e\u003e readSheetOptionsList = new ArrayList\u003c\u003e(8);\n\n        //读取表一的数据\n        ReadListener\u003cRead001\u003e readListener1 = new BatchResolveReadListener\u003c\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库 (不能保证整批数据全是合法的,如有特殊需求需要额外处理)\n            System.out.println(String.format(\"(表一)当前要批量处理的数据为:\\n %s\", dataList));\n        });\n        readSheetOptionsList.add(ExcelReadSheetOptions.\u003cRead001\u003ebuilder().sheetNo(0).headClass(Read001.class).readListener(readListener1).build());\n\n        //读取表二的数据\n        ReadListener\u003cRead001ByIndex\u003e readListener2 = new BatchResolveReadListener\u003c\u003e(dataList -\u003e {\n            //进行处理该批数据,e.g: 持久化到数据库 (不能保证整批数据全是合法的,如有特殊需求需要额外处理)\n            System.out.println(String.format(\"(表二)当前要批量处理的数据为:\\n %s\", dataList));\n        });\n        readSheetOptionsList.add(ExcelReadSheetOptions.\u003cRead001ByIndex\u003ebuilder().sheetNo(1).headRowNumber(2).headClass(Read001ByIndex.class).readListener(readListener2).build());\n\n        ExcelReadSupportUtils.repeatedRead(inputStream, readOptions, readSheetOptionsList);\n    \n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoker-pper%2Feasy-excel-support","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoker-pper%2Feasy-excel-support","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoker-pper%2Feasy-excel-support/lists"}