From a5697c2ba8b385bf05feb90c1a0d74afcda5bfdc Mon Sep 17 00:00:00 2001 From: ls Date: Sun, 23 Feb 2025 12:03:06 +0800 Subject: [PATCH] update --- autopoi/.gitignore | 10 + autopoi/LICENSE | 191 +++ autopoi/autopoi-web/pom.xml | 43 + .../poi/excel/def/BasePOIConstants.java | 39 + .../poi/excel/def/MapExcelConstants.java | 37 + .../poi/excel/def/NormalExcelConstants.java | 43 + .../poi/excel/def/TemplateExcelConstants.java | 38 + .../poi/excel/def/TemplateWordConstants.java | 38 + .../poi/excel/view/JeecgEntityExcelView.java | 89 ++ .../poi/excel/view/JeecgMapExcelView.java | 71 ++ .../excel/view/JeecgTemplateExcelView.java | 69 ++ .../poi/excel/view/JeecgTemplateWordView.java | 67 ++ .../poi/excel/view/MiniAbstractExcelView.java | 43 + .../src/test/java/DaoChuBigDataTest.java | 80 ++ .../src/test/java/DaoChuSheetTest.java | 69 ++ .../autopoi-web/src/test/java/DaoChuTest.java | 55 + .../src/test/java/DaoChuWordTest.java | 57 + .../autopoi-web/src/test/java/TestEntity.java | 29 + .../src/test/resources/templates/test.xlsx | Bin 0 -> 11036 bytes .../resources/templates/testNextMarge.xlsx | Bin 0 -> 11137 bytes .../test/resources/templates/纳税信息.docx | Bin 0 -> 16080 bytes autopoi/autopoi/pom.xml | 73 ++ .../core/util/ApplicationContextUtil.java | 25 + .../dict/service/AutoPoiDictServiceI.java | 23 + .../jeecgframework/poi/cache/ExcelCache.java | 99 ++ .../jeecgframework/poi/cache/ImageCache.java | 99 ++ .../jeecgframework/poi/cache/WordCache.java | 53 + .../poi/cache/manager/FileLoade.java | 75 ++ .../poi/cache/manager/POICacheManager.java | 64 + .../poi/cache/package-info.java | 11 + .../poi/entity/ImageEntity.java | 104 ++ .../poi/excel/ExcelExportUtil.java | 243 ++++ .../poi/excel/ExcelImportCheckUtil.java | 457 ++++++++ .../poi/excel/ExcelImportUtil.java | 168 +++ .../poi/excel/ExcelToHtmlUtil.java | 67 ++ .../poi/excel/annotation/Excel.java | 206 ++++ .../poi/excel/annotation/ExcelCollection.java | 54 + .../poi/excel/annotation/ExcelEntity.java | 49 + .../poi/excel/annotation/ExcelIgnore.java | 34 + .../poi/excel/annotation/ExcelTarget.java | 36 + .../poi/excel/annotation/ExcelVerify.java | 95 ++ .../poi/excel/entity/ExcelBaseParams.java | 41 + .../poi/excel/entity/ExportParams.java | 294 +++++ .../poi/excel/entity/ImportParams.java | 206 ++++ .../excel/entity/TemplateExportParams.java | 218 ++++ .../poi/excel/entity/enmus/CellValueType.java | 28 + .../excel/entity/enmus/ExcelStyleType.java | 48 + .../poi/excel/entity/enmus/ExcelType.java | 28 + .../excel/entity/params/ExcelBaseEntity.java | 184 +++ .../entity/params/ExcelCollectionParams.java | 77 ++ .../entity/params/ExcelExportEntity.java | 306 +++++ .../entity/params/ExcelForEachParams.java | 125 ++ .../entity/params/ExcelImportEntity.java | 110 ++ .../entity/params/ExcelTemplateParams.java | 66 ++ .../entity/params/ExcelVerifyEntity.java | 159 +++ .../poi/excel/entity/params/MergeEntity.java | 84 ++ .../entity/result/ExcelImportResult.java | 79 ++ .../result/ExcelVerifyHanlderResult.java | 63 + .../excel/entity/sax/SaxReadCellEntity.java | 62 + .../poi/excel/entity/vo/PoiBaseConstants.java | 43 + .../excel/export/ExcelBatchExportServer.java | 200 ++++ .../poi/excel/export/ExcelExportServer.java | 454 ++++++++ .../excel/export/base/ExcelExportBase.java | 768 ++++++++++++ .../poi/excel/export/base/ExportBase.java | 552 +++++++++ .../styler/AbstractExcelExportStyler.java | 83 ++ .../styler/ExcelExportStylerBorderImpl.java | 81 ++ .../styler/ExcelExportStylerColorImpl.java | 89 ++ .../styler/ExcelExportStylerDefaultImpl.java | 76 ++ .../export/styler/IExcelExportStyler.java | 59 + .../template/ExcelExportOfTemplateUtil.java | 1026 +++++++++++++++++ .../graph/builder/ExcelChartBuildService.java | 263 +++++ .../graph/constant/ExcelGraphElementType.java | 15 + .../excel/graph/constant/ExcelGraphType.java | 16 + .../poi/excel/graph/entity/ExcelGraph.java | 20 + .../excel/graph/entity/ExcelGraphDefined.java | 74 ++ .../excel/graph/entity/ExcelGraphElement.java | 63 + .../excel/graph/entity/ExcelTitleCell.java | 43 + .../poi/excel/graph/package-info.java | 9 + .../poi/excel/html/ExcelToHtmlServer.java | 191 +++ .../excel/html/helper/CellValueHelper.java | 135 +++ .../excel/html/helper/MergedRegionHelper.java | 139 +++ .../poi/excel/html/helper/StylerHelper.java | 259 +++++ .../poi/excel/html/helper/excelStyle.css | 45 + .../poi/excel/imports/CellValueServer.java | 387 +++++++ .../poi/excel/imports/ExcelImportServer.java | 620 ++++++++++ .../excel/imports/base/ImportBaseService.java | 328 ++++++ .../imports/base/ImportFileServiceI.java | 20 + .../poi/excel/imports/package-info.java | 6 + .../poi/excel/imports/sax/SaxReadExcel.java | 91 ++ .../poi/excel/imports/sax/SheetHandler.java | 136 +++ .../excel/imports/sax/parse/ISaxRowRead.java | 39 + .../excel/imports/sax/parse/SaxRowRead.java | 213 ++++ .../imports/verifys/BaseVerifyHandler.java | 145 +++ .../imports/verifys/VerifyHandlerServer.java | 81 ++ .../exception/excel/ExcelExportException.java | 62 + .../exception/excel/ExcelImportException.java | 62 + .../excel/enums/ExcelExportEnum.java | 42 + .../excel/enums/ExcelImportEnum.java | 42 + .../exception/word/WordExportException.java | 42 + .../exception/word/enmus/WordExportEnum.java | 42 + .../impl/ExcelDataHandlerDefaultImpl.java | 64 + .../poi/handler/impl/package-info.java | 6 + .../poi/handler/inter/IExcelDataHandler.java | 87 ++ .../poi/handler/inter/IExcelDictHandler.java | 32 + .../poi/handler/inter/IExcelExportServer.java | 21 + .../handler/inter/IExcelReadRowHanlder.java | 33 + .../handler/inter/IExcelVerifyHandler.java | 55 + .../poi/handler/inter/IWriter.java | 35 + .../poi/handler/package-info.java | 6 + .../org/jeecgframework/poi/package-info.java | 13 + .../jeecgframework/poi/util/ExcelUtil.java | 327 ++++++ .../poi/util/MyX509TrustManager.java | 30 + .../jeecgframework/poi/util/PoiCellUtil.java | 134 +++ .../jeecgframework/poi/util/PoiElUtil.java | 278 +++++ .../poi/util/PoiExcelGraphDataUtil.java | 58 + .../poi/util/PoiExcelTempUtil.java | 102 ++ .../poi/util/PoiFunctionUtil.java | 167 +++ .../poi/util/PoiMergeCellUtil.java | 238 ++++ .../poi/util/PoiPublicUtil.java | 561 +++++++++ .../poi/util/PoiReflectorUtil.java | 374 ++++++ .../poi/util/PoiSheetUtility.java | 104 ++ .../poi/word/WordExportUtil.java | 62 + .../poi/word/entity/MyXWPFDocument.java | 115 ++ .../poi/word/entity/WordImageEntity.java | 101 ++ .../word/entity/params/ExcelListEntity.java | 98 ++ .../word/entity/params/ListParamEntity.java | 93 ++ .../poi/word/parse/ParseWord07.java | 301 +++++ .../word/parse/excel/ExcelEntityParse.java | 215 ++++ .../poi/word/parse/excel/ExcelMapParse.java | 80 ++ autopoi/pom.xml | 282 +++++ 130 files changed, 16414 insertions(+) create mode 100644 autopoi/.gitignore create mode 100644 autopoi/LICENSE create mode 100644 autopoi/autopoi-web/pom.xml create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/BasePOIConstants.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/MapExcelConstants.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/NormalExcelConstants.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/TemplateExcelConstants.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/TemplateWordConstants.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgEntityExcelView.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgMapExcelView.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgTemplateExcelView.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgTemplateWordView.java create mode 100644 autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/MiniAbstractExcelView.java create mode 100644 autopoi/autopoi-web/src/test/java/DaoChuBigDataTest.java create mode 100644 autopoi/autopoi-web/src/test/java/DaoChuSheetTest.java create mode 100644 autopoi/autopoi-web/src/test/java/DaoChuTest.java create mode 100644 autopoi/autopoi-web/src/test/java/DaoChuWordTest.java create mode 100644 autopoi/autopoi-web/src/test/java/TestEntity.java create mode 100644 autopoi/autopoi-web/src/test/resources/templates/test.xlsx create mode 100644 autopoi/autopoi-web/src/test/resources/templates/testNextMarge.xlsx create mode 100644 autopoi/autopoi-web/src/test/resources/templates/纳税信息.docx create mode 100644 autopoi/autopoi/pom.xml create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/core/util/ApplicationContextUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/dict/service/AutoPoiDictServiceI.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/ExcelCache.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/ImageCache.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/WordCache.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/manager/FileLoade.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/manager/POICacheManager.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/package-info.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/entity/ImageEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelExportUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelImportCheckUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelImportUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelToHtmlUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/Excel.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelCollection.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelIgnore.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelTarget.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelVerify.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ExcelBaseParams.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ExportParams.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ImportParams.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/TemplateExportParams.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/CellValueType.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/ExcelStyleType.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/ExcelType.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelBaseEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelCollectionParams.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelExportEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelForEachParams.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelImportEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelTemplateParams.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelVerifyEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/MergeEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/result/ExcelImportResult.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/result/ExcelVerifyHanlderResult.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/sax/SaxReadCellEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/vo/PoiBaseConstants.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/ExcelBatchExportServer.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/ExcelExportServer.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/base/ExcelExportBase.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/base/ExportBase.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/AbstractExcelExportStyler.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerBorderImpl.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerColorImpl.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerDefaultImpl.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/IExcelExportStyler.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/template/ExcelExportOfTemplateUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/builder/ExcelChartBuildService.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/constant/ExcelGraphElementType.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/constant/ExcelGraphType.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraph.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraphDefined.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraphElement.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelTitleCell.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/package-info.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/ExcelToHtmlServer.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/CellValueHelper.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/MergedRegionHelper.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/StylerHelper.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/excelStyle.css create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/CellValueServer.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/ExcelImportServer.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/base/ImportBaseService.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/base/ImportFileServiceI.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/package-info.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/SaxReadExcel.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/SheetHandler.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/parse/ISaxRowRead.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/parse/SaxRowRead.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/verifys/BaseVerifyHandler.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/verifys/VerifyHandlerServer.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/ExcelExportException.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/ExcelImportException.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/enums/ExcelExportEnum.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/enums/ExcelImportEnum.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/word/WordExportException.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/word/enmus/WordExportEnum.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/impl/ExcelDataHandlerDefaultImpl.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/impl/package-info.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelDataHandler.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelDictHandler.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelExportServer.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelReadRowHanlder.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelVerifyHandler.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IWriter.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/package-info.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/package-info.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/ExcelUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/MyX509TrustManager.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiCellUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiElUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiExcelGraphDataUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiExcelTempUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiFunctionUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiMergeCellUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiPublicUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiReflectorUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiSheetUtility.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/WordExportUtil.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/MyXWPFDocument.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/WordImageEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/params/ExcelListEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/params/ListParamEntity.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/ParseWord07.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/excel/ExcelEntityParse.java create mode 100644 autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/excel/ExcelMapParse.java create mode 100644 autopoi/pom.xml diff --git a/autopoi/.gitignore b/autopoi/.gitignore new file mode 100644 index 0000000..0d78ee0 --- /dev/null +++ b/autopoi/.gitignore @@ -0,0 +1,10 @@ +## ide +**/.idea +*.iml + +## backend +**/target +**/logs + +## front +**/*.lock diff --git a/autopoi/LICENSE b/autopoi/LICENSE new file mode 100644 index 0000000..187e0d7 --- /dev/null +++ b/autopoi/LICENSE @@ -0,0 +1,191 @@ +Apache License +Version 2.0, January 2004 +http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + +"License" shall mean the terms and conditions for use, reproduction, and +distribution as defined by Sections 1 through 9 of this document. + +"Licensor" shall mean the copyright owner or entity authorized by the copyright +owner that is granting the License. + +"Legal Entity" shall mean the union of the acting entity and all other entities +that control, are controlled by, or are under common control with that entity. +For the purposes of this definition, "control" means (i) the power, direct or +indirect, to cause the direction or management of such entity, whether by +contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the +outstanding shares, or (iii) beneficial ownership of such entity. + +"You" (or "Your") shall mean an individual or Legal Entity exercising +permissions granted by this License. + +"Source" form shall mean the preferred form for making modifications, including +but not limited to software source code, documentation source, and configuration +files. + +"Object" form shall mean any form resulting from mechanical transformation or +translation of a Source form, including but not limited to compiled object code, +generated documentation, and conversions to other media types. + +"Work" shall mean the work of authorship, whether in Source or Object form, made +available under the License, as indicated by a copyright notice that is included +in or attached to the work (an example is provided in the Appendix below). + +"Derivative Works" shall mean any work, whether in Source or Object form, that +is based on (or derived from) the Work and for which the editorial revisions, +annotations, elaborations, or other modifications represent, as a whole, an +original work of authorship. For the purposes of this License, Derivative Works +shall not include works that remain separable from, or merely link (or bind by +name) to the interfaces of, the Work and Derivative Works thereof. + +"Contribution" shall mean any work of authorship, including the original version +of the Work and any modifications or additions to that Work or Derivative Works +thereof, that is intentionally submitted to Licensor for inclusion in the Work +by the copyright owner or by an individual or Legal Entity authorized to submit +on behalf of the copyright owner. For the purposes of this definition, +"submitted" means any form of electronic, verbal, or written communication sent +to the Licensor or its representatives, including but not limited to +communication on electronic mailing lists, source code control systems, and +issue tracking systems that are managed by, or on behalf of, the Licensor for +the purpose of discussing and improving the Work, but excluding communication +that is conspicuously marked or otherwise designated in writing by the copyright +owner as "Not a Contribution." + +"Contributor" shall mean Licensor and any individual or Legal Entity on behalf +of whom a Contribution has been received by Licensor and subsequently +incorporated within the Work. + +2. Grant of Copyright License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable copyright license to reproduce, prepare Derivative Works of, +publicly display, publicly perform, sublicense, and distribute the Work and such +Derivative Works in Source or Object form. + +3. Grant of Patent License. + +Subject to the terms and conditions of this License, each Contributor hereby +grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, +irrevocable (except as stated in this section) patent license to make, have +made, use, offer to sell, sell, import, and otherwise transfer the Work, where +such license applies only to those patent claims licensable by such Contributor +that are necessarily infringed by their Contribution(s) alone or by combination +of their Contribution(s) with the Work to which such Contribution(s) was +submitted. If You institute patent litigation against any entity (including a +cross-claim or counterclaim in a lawsuit) alleging that the Work or a +Contribution incorporated within the Work constitutes direct or contributory +patent infringement, then any patent licenses granted to You under this License +for that Work shall terminate as of the date such litigation is filed. + +4. Redistribution. + +You may reproduce and distribute copies of the Work or Derivative Works thereof +in any medium, with or without modifications, and in Source or Object form, +provided that You meet the following conditions: + +You must give any other recipients of the Work or Derivative Works a copy of +this License; and +You must cause any modified files to carry prominent notices stating that You +changed the files; and +You must retain, in the Source form of any Derivative Works that You distribute, +all copyright, patent, trademark, and attribution notices from the Source form +of the Work, excluding those notices that do not pertain to any part of the +Derivative Works; and +If the Work includes a "NOTICE" text file as part of its distribution, then any +Derivative Works that You distribute must include a readable copy of the +attribution notices contained within such NOTICE file, excluding those notices +that do not pertain to any part of the Derivative Works, in at least one of the +following places: within a NOTICE text file distributed as part of the +Derivative Works; within the Source form or documentation, if provided along +with the Derivative Works; or, within a display generated by the Derivative +Works, if and wherever such third-party notices normally appear. The contents of +the NOTICE file are for informational purposes only and do not modify the +License. You may add Your own attribution notices within Derivative Works that +You distribute, alongside or as an addendum to the NOTICE text from the Work, +provided that such additional attribution notices cannot be construed as +modifying the License. +You may add Your own copyright statement to Your modifications and may provide +additional or different license terms and conditions for use, reproduction, or +distribution of Your modifications, or for any such Derivative Works as a whole, +provided Your use, reproduction, and distribution of the Work otherwise complies +with the conditions stated in this License. + +5. Submission of Contributions. + +Unless You explicitly state otherwise, any Contribution intentionally submitted +for inclusion in the Work by You to the Licensor shall be under the terms and +conditions of this License, without any additional terms or conditions. +Notwithstanding the above, nothing herein shall supersede or modify the terms of +any separate license agreement you may have executed with Licensor regarding +such Contributions. + +6. Trademarks. + +This License does not grant permission to use the trade names, trademarks, +service marks, or product names of the Licensor, except as required for +reasonable and customary use in describing the origin of the Work and +reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. + +Unless required by applicable law or agreed to in writing, Licensor provides the +Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, +including, without limitation, any warranties or conditions of TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are +solely responsible for determining the appropriateness of using or +redistributing the Work and assume any risks associated with Your exercise of +permissions under this License. + +8. Limitation of Liability. + +In no event and under no legal theory, whether in tort (including negligence), +contract, or otherwise, unless required by applicable law (such as deliberate +and grossly negligent acts) or agreed to in writing, shall any Contributor be +liable to You for damages, including any direct, indirect, special, incidental, +or consequential damages of any character arising as a result of this License or +out of the use or inability to use the Work (including but not limited to +damages for loss of goodwill, work stoppage, computer failure or malfunction, or +any and all other commercial damages or losses), even if such Contributor has +been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. + +While redistributing the Work or Derivative Works thereof, You may choose to +offer, and charge a fee for, acceptance of support, warranty, indemnity, or +other liability obligations and/or rights consistent with this License. However, +in accepting such obligations, You may act only on Your own behalf and on Your +sole responsibility, not on behalf of any other Contributor, and only if You +agree to indemnify, defend, and hold each Contributor harmless for any liability +incurred by, or claims asserted against, such Contributor by reason of your +accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work + +To apply the Apache License to your work, attach the following boilerplate +notice, with the fields enclosed by brackets "{}" replaced with your own +identifying information. (Don't include the brackets!) The text should be +enclosed in the appropriate comment syntax for the file format. We also +recommend that a file or class name and description of purpose be included on +the same "printed page" as the copyright notice for easier identification within +third-party archives. + + Copyright 2019 scott + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/autopoi/autopoi-web/pom.xml b/autopoi/autopoi-web/pom.xml new file mode 100644 index 0000000..a2aed2e --- /dev/null +++ b/autopoi/autopoi-web/pom.xml @@ -0,0 +1,43 @@ + + 4.0.0 + + org.jeecgframework.boot3 + autopoi-parent + 3.7.0 + + autopoi-web + + + + org.jeecgframework.boot3 + autopoi + ${autopoi.version} + + + + + org.springframework + spring-webmvc + true + + + + + jakarta.servlet + jakarta.servlet-api + 6.0.0 + provided + true + + + + org.apache.logging.log4j + log4j-to-slf4j + 2.11.2 + true + test + + + \ No newline at end of file diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/BasePOIConstants.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/BasePOIConstants.java new file mode 100644 index 0000000..33b46e1 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/BasePOIConstants.java @@ -0,0 +1,39 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.def; + +/** + * 基础POI常量 + * + * @author JEECG + * @date 2014年6月30日 下午9:23:37 + */ +interface BasePOIConstants { + + /** + * 注解对象 + */ + public final static String CLASS = "entity"; + /** + * 表格参数 + */ + public final static String PARAMS = "params"; + /** + * 下载文件名称 + */ + public final static String FILE_NAME = "fileName"; + +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/MapExcelConstants.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/MapExcelConstants.java new file mode 100644 index 0000000..1a18853 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/MapExcelConstants.java @@ -0,0 +1,37 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.def; + +/** + * 正常导出Excel + * + * @Author JEECG on 14-3-8. 静态常量 + */ +public interface MapExcelConstants extends BasePOIConstants { + /** + * 单Sheet导出 + */ + public final static String JEECG_MAP_EXCEL_VIEW = "jeecgMapExcelView"; + /** + * Entity List + */ + public final static String ENTITY_LIST = "data"; + /** + * 数据列表 + */ + public final static String MAP_LIST = "mapList"; + +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/NormalExcelConstants.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/NormalExcelConstants.java new file mode 100644 index 0000000..41a4ad9 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/NormalExcelConstants.java @@ -0,0 +1,43 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.def; + +/** + * 正常导出Excel + * + * @Author JEECG on 14-3-8. 静态常量 + */ +public interface NormalExcelConstants extends BasePOIConstants { + /** + * 单Sheet导出 + */ + public final static String JEECG_ENTITY_EXCEL_VIEW = "jeecgEntityExcelView"; + /** + * 数据列表 + */ + public final static String DATA_LIST = "data"; + + /** + * 多Sheet 对象 + */ + public final static String MAP_LIST = "mapList"; + + /** + * 导出字段自定义 + */ + public final static String EXPORT_FIELDS = "exportFields"; + +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/TemplateExcelConstants.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/TemplateExcelConstants.java new file mode 100644 index 0000000..cf777d7 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/TemplateExcelConstants.java @@ -0,0 +1,38 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.def; + +/** + * 模板Excel导出常量 + * + * @author JEECG + * @date 2014年6月30日 下午9:26:52 + */ +public interface TemplateExcelConstants extends BasePOIConstants { + /** + * 模板导出 + */ + public final static String JEECG_TEMPLATE_EXCEL_VIEW = "jeecgTemplateExcelView"; + /** + * 数据列表 + */ + public final static String LIST_DATA = "list"; + /** + * 模板参数 + */ + public final static String MAP_DATA = "map"; + +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/TemplateWordConstants.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/TemplateWordConstants.java new file mode 100644 index 0000000..4d44d83 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/def/TemplateWordConstants.java @@ -0,0 +1,38 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.def; + +/** + * Word 导出模板常量 + * + * @author JEECG + * @date 2014年7月24日 下午11:26:46 + */ +public interface TemplateWordConstants extends BasePOIConstants { + /** + * 模板导出 + */ + public final static String JEECG_TEMPLATE_WORD_VIEW = "jeecgTemplateWordView"; + /** + * 数据列表 + */ + public final static String URL = "url"; + /** + * 模板参数 + */ + public final static String MAP_DATA = "map"; + +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgEntityExcelView.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgEntityExcelView.java new file mode 100644 index 0000000..467bd64 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgEntityExcelView.java @@ -0,0 +1,89 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.view; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + + +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.ExcelExportUtil; +import org.jeecgframework.poi.excel.def.NormalExcelConstants; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.export.ExcelExportServer; +import org.springframework.stereotype.Controller; + +/** + * Entity 实体数据对象导出 + * @Author JEECG + * + */ +@SuppressWarnings("unchecked") +@Controller(NormalExcelConstants.JEECG_ENTITY_EXCEL_VIEW) +public class JeecgEntityExcelView extends MiniAbstractExcelView { + + public JeecgEntityExcelView() { + super(); + } + + @Override + protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + String codedFileName = "临时文件"; + Workbook workbook = null; + //---update-end-----autor:scott------date:20191016-------for:导出字段支持自定义-------- + String[] exportFields = null; + + Object exportFieldStr = model.get(NormalExcelConstants.EXPORT_FIELDS); + if(exportFieldStr!=null && exportFieldStr!=""){ + exportFields = exportFieldStr.toString().split(","); + } + //---update-end-----autor:scott------date:20191016-------for:导出字段支持自定义-------- + if (model.containsKey(NormalExcelConstants.MAP_LIST)) { + List> list = (List>) model.get(NormalExcelConstants.MAP_LIST); + if (list.size() == 0) { + throw new RuntimeException("MAP_LIST IS NULL"); + } + workbook = ExcelExportUtil.exportExcel((ExportParams) list.get(0).get(NormalExcelConstants.PARAMS), (Class) list.get(0).get(NormalExcelConstants.CLASS), (Collection) list.get(0).get(NormalExcelConstants.DATA_LIST),exportFields); + for (int i = 1; i < list.size(); i++) { + new ExcelExportServer().createSheet(workbook, (ExportParams) list.get(i).get(NormalExcelConstants.PARAMS), (Class) list.get(i).get(NormalExcelConstants.CLASS), (Collection) list.get(i).get(NormalExcelConstants.DATA_LIST),exportFields); + } + } else { + workbook = ExcelExportUtil.exportExcel((ExportParams) model.get(NormalExcelConstants.PARAMS), (Class) model.get(NormalExcelConstants.CLASS), (Collection) model.get(NormalExcelConstants.DATA_LIST),exportFields); + } + if (model.containsKey(NormalExcelConstants.FILE_NAME)) { + codedFileName = (String) model.get(NormalExcelConstants.FILE_NAME); + } + if (workbook instanceof HSSFWorkbook) { + codedFileName += HSSF; + } else { + codedFileName += XSSF; + } + if (isIE(request)) { + codedFileName = java.net.URLEncoder.encode(codedFileName, "UTF8"); + } else { + codedFileName = new String(codedFileName.getBytes("UTF-8"), "ISO-8859-1"); + } + response.setHeader("content-disposition", "attachment;filename=" + codedFileName); + ServletOutputStream out = response.getOutputStream(); + workbook.write(out); + out.flush(); + } +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgMapExcelView.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgMapExcelView.java new file mode 100644 index 0000000..e962d56 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgMapExcelView.java @@ -0,0 +1,71 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.view; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + + +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.ExcelExportUtil; +import org.jeecgframework.poi.excel.def.MapExcelConstants; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.springframework.stereotype.Controller; + +/** + * Map 数据对象接口导出 + * + * @author JEECG + * @date 2014年11月25日 下午3:26:32 + */ +@SuppressWarnings("unchecked") +@Controller(MapExcelConstants.JEECG_MAP_EXCEL_VIEW) +public class JeecgMapExcelView extends MiniAbstractExcelView { + + public JeecgMapExcelView() { + super(); + } + + @Override + protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + String codedFileName = "临时文件"; + Workbook workbook = ExcelExportUtil.exportExcel((ExportParams) model.get(MapExcelConstants.PARAMS), (List) model.get(MapExcelConstants.ENTITY_LIST), (Collection>) model.get(MapExcelConstants.MAP_LIST)); + if (model.containsKey(MapExcelConstants.FILE_NAME)) { + codedFileName = (String) model.get(MapExcelConstants.FILE_NAME); + } + if (workbook instanceof HSSFWorkbook) { + codedFileName += HSSF; + } else { + codedFileName += XSSF; + } + if (isIE(request)) { + codedFileName = java.net.URLEncoder.encode(codedFileName, "UTF8"); + } else { + codedFileName = new String(codedFileName.getBytes("UTF-8"), "ISO-8859-1"); + } + response.setHeader("content-disposition", "attachment;filename=" + codedFileName); + ServletOutputStream out = response.getOutputStream(); + workbook.write(out); + out.flush(); + } + +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgTemplateExcelView.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgTemplateExcelView.java new file mode 100644 index 0000000..c2df1ed --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgTemplateExcelView.java @@ -0,0 +1,69 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.view; + +import java.util.List; +import java.util.Map; + + +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.ExcelExportUtil; +import org.jeecgframework.poi.excel.def.NormalExcelConstants; +import org.jeecgframework.poi.excel.def.TemplateExcelConstants; +import org.jeecgframework.poi.excel.entity.TemplateExportParams; +import org.springframework.stereotype.Controller; + +/** + * Excel 模板导出 + * + * @author JEECG + * @date 2014年6月30日 下午9:15:49 + */ +@SuppressWarnings("unchecked") +@Controller(TemplateExcelConstants.JEECG_TEMPLATE_EXCEL_VIEW) +public class JeecgTemplateExcelView extends MiniAbstractExcelView { + + public JeecgTemplateExcelView() { + super(); + } + + @Override + protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + String codedFileName = "临时文件"; + Workbook workbook = ExcelExportUtil.exportExcel((TemplateExportParams) model.get(TemplateExcelConstants.PARAMS), (Class) model.get(TemplateExcelConstants.CLASS), (List) model.get(TemplateExcelConstants.LIST_DATA), (Map) model.get(TemplateExcelConstants.MAP_DATA)); + if (model.containsKey(NormalExcelConstants.FILE_NAME)) { + codedFileName = (String) model.get(NormalExcelConstants.FILE_NAME); + } + if (workbook instanceof HSSFWorkbook) { + codedFileName += HSSF; + } else { + codedFileName += XSSF; + } + if (isIE(request)) { + codedFileName = java.net.URLEncoder.encode(codedFileName, "UTF8"); + } else { + codedFileName = new String(codedFileName.getBytes("UTF-8"), "ISO-8859-1"); + } + response.setHeader("content-disposition", "attachment;filename=" + codedFileName); + ServletOutputStream out = response.getOutputStream(); + workbook.write(out); + out.flush(); + } +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgTemplateWordView.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgTemplateWordView.java new file mode 100644 index 0000000..22f4d51 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/JeecgTemplateWordView.java @@ -0,0 +1,67 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.view; + +import java.util.Map; + + +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.jeecgframework.poi.excel.def.TemplateWordConstants; +import org.jeecgframework.poi.word.WordExportUtil; +import org.springframework.stereotype.Controller; +import org.springframework.web.servlet.view.AbstractView; + +/** + * Word模板导出 + * + * @author JEECG + * @date 2014年6月30日 下午9:15:49 + */ +@SuppressWarnings("unchecked") +@Controller(TemplateWordConstants.JEECG_TEMPLATE_WORD_VIEW) +public class JeecgTemplateWordView extends AbstractView { + + private static final String CONTENT_TYPE = "application/msword"; + + public JeecgTemplateWordView() { + setContentType(CONTENT_TYPE); + } + + public boolean isIE(HttpServletRequest request) { + return (request.getHeader("USER-AGENT").toLowerCase().indexOf("msie") > 0 || request.getHeader("USER-AGENT").toLowerCase().indexOf("rv:11.0") > 0) ? true : false; + } + + @Override + protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response) throws Exception { + String codedFileName = "临时文件.docx"; + if (model.containsKey(TemplateWordConstants.FILE_NAME)) { + codedFileName = (String) model.get(TemplateWordConstants.FILE_NAME) + ".docx"; + } + if (isIE(request)) { + codedFileName = java.net.URLEncoder.encode(codedFileName, "UTF8"); + } else { + codedFileName = new String(codedFileName.getBytes("UTF-8"), "ISO-8859-1"); + } + response.setHeader("content-disposition", "attachment;filename=" + codedFileName); + XWPFDocument document = WordExportUtil.exportWord07((String) model.get(TemplateWordConstants.URL), (Map) model.get(TemplateWordConstants.MAP_DATA)); + ServletOutputStream out = response.getOutputStream(); + document.write(out); + out.flush(); + } +} diff --git a/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/MiniAbstractExcelView.java b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/MiniAbstractExcelView.java new file mode 100644 index 0000000..8f31187 --- /dev/null +++ b/autopoi/autopoi-web/src/main/java/org/jeecgframework/poi/excel/view/MiniAbstractExcelView.java @@ -0,0 +1,43 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.view; + + +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.web.servlet.view.AbstractView; + +/** + * 基础抽象Excel View + * + * @author JEECG + * @date 2015年2月28日 下午1:41:05 + */ +public abstract class MiniAbstractExcelView extends AbstractView { + + private static final String CONTENT_TYPE = "application/vnd.ms-excel"; + + protected static final String HSSF = ".xls"; + protected static final String XSSF = ".xlsx"; + + public MiniAbstractExcelView() { + setContentType(CONTENT_TYPE); + } + + protected boolean isIE(HttpServletRequest request) { + return (request.getHeader("USER-AGENT").toLowerCase().indexOf("msie") > 0 || request.getHeader("USER-AGENT").toLowerCase().indexOf("rv:11.0") > 0) ? true : false; + } + +} diff --git a/autopoi/autopoi-web/src/test/java/DaoChuBigDataTest.java b/autopoi/autopoi-web/src/test/java/DaoChuBigDataTest.java new file mode 100644 index 0000000..e596c35 --- /dev/null +++ b/autopoi/autopoi-web/src/test/java/DaoChuBigDataTest.java @@ -0,0 +1,80 @@ +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.ExcelExportUtil; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.handler.inter.IExcelExportServer; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @Description: 大数据导出示例 + * @author: liusq + * @date: 2022年1月4日 + */ +public class DaoChuBigDataTest { + /** + * 导出测试方法 + * 参考:http://doc.wupaas.com/docs/easypoi/easypoi-1c10lbsojh62f + * 参考:https://blog.csdn.net/weixin_45214729/article/details/118552415 + * @author liusq + * @date: 2022年1月4日 + * @throws Exception + */ + public static void bigDataExport() throws Exception { + Workbook workbook = null; + List aList = new ArrayList(); + ExportParams exportParams = new ExportParams(); + Date start = new Date(); + //模拟100w数据 + for(int j=0;j<1000000;j++){ + TestEntity testEntity = new TestEntity(); + testEntity.setName("李四"+j); + testEntity.setAge(j); + aList.add(testEntity); + } + //分别是 totalPage是总页数,pageSize 页码长度 + int totalPage = (aList.size() / 100000) + 1; + int pageSize = 100000; + /** + * params:(表格标题属性)筛选条件,sheet值 + * TestEntity:表格的实体类 + */ + workbook = ExcelExportUtil.exportBigExcel(exportParams,TestEntity.class, new IExcelExportServer() { + /** + * obj 就是下面的totalPage,限制条件 + * page 是页数,他是在分页进行文件转换,page每次+1 + */ + @Override + public List selectListForExcelExport(Object obj, int page) { + //很重要!!这里面整个方法体,其实就是将所有的数据aList分批返回处理 + //分批的方式很多,我直接用了subList。然后 每批不能太大。我试了30000一批, + //特别注意,最好每次10000条,否则,可能有内存溢出风险 + if (page > totalPage) { + return null; + } + // fromIndex开始索引,toIndex结束索引 + int fromIndex = (page - 1) * pageSize; + int toIndex = page != totalPage ? fromIndex + pageSize :aList.size(); + //不是空时:一直循环运行selectListForExcelExport。每次返回1万条数据。 + List list = new ArrayList<>(); + list.addAll(aList.subList(fromIndex, toIndex)); + return list; + } + }, totalPage); + File savefile = new File("D:/excel/"); + if (!savefile.exists()) { + savefile.mkdirs(); + } + FileOutputStream fos = new FileOutputStream("D:/excel/ExcelExportBigData.bigDataExport.xlsx"); + workbook.write(fos); + fos.close(); + System.out.println("耗时(秒):"+((new Date().getTime() - start.getTime())/ 1000)); + } + + public static void main(String[] args) throws Exception { + bigDataExport(); + } +} diff --git a/autopoi/autopoi-web/src/test/java/DaoChuSheetTest.java b/autopoi/autopoi-web/src/test/java/DaoChuSheetTest.java new file mode 100644 index 0000000..1cb9439 --- /dev/null +++ b/autopoi/autopoi-web/src/test/java/DaoChuSheetTest.java @@ -0,0 +1,69 @@ +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.ExcelExportUtil; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.TemplateExportParams; +import org.jeecgframework.poi.excel.entity.enmus.ExcelType; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: 参考文档:http://doc.jeecg.com/2044223 + * @author: scott + * @date: 2020年09月16日 11:46 + */ +public class DaoChuSheetTest { + private static final String basePath = "G:\\needtodeplay\\autopoi-framework-sy-4.0\\autopoi-web\\src\\test\\resources\\templates\\"; + + public static ExportParams getExportParams(String name) { + return new ExportParams(name,name,ExcelType.XSSF); + } + public static Workbook test() { + /** + * 多个Map + * title:对应表格Title + * entity:对应表格对应实体 + * data:Collection 数据 + */ + List> listMap = new ArrayList>(); + for(int i=0;i<3;i++){ + Map map = new HashMap(); + map.put("title", getExportParams("测试"+i));//表格Title + map.put("entity",TestEntity.class);//表格对应实体 + List ls=new ArrayList (); + for(int j=0;j<10;j++){ + TestEntity testEntity = new TestEntity(); + testEntity.setName("张三"+i+j); + testEntity.setAge(18+i+j); + ls.add(testEntity); + } + List ls2=new ArrayList (); + for(int j=0;j<10;j++){ + Map map1 = new HashMap(); + map1.put("name","李四"+i+j); + map1.put("age",18+i+j); + ls2.add(map1); + } + map.put("data", ls);//ls or ls2 + listMap.add(map); + } + Workbook workbook = ExcelExportUtil.exportExcel(listMap, ExcelType.XSSF); + return workbook; + } + + public static void main(String[] args) throws IOException { + Workbook workbook = test(); + File savefile = new File(basePath); + if (!savefile.exists()) { + savefile.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(basePath + "testSheet.xlsx"); + workbook.write(fos); + fos.close(); + } +} diff --git a/autopoi/autopoi-web/src/test/java/DaoChuTest.java b/autopoi/autopoi-web/src/test/java/DaoChuTest.java new file mode 100644 index 0000000..86c9bd8 --- /dev/null +++ b/autopoi/autopoi-web/src/test/java/DaoChuTest.java @@ -0,0 +1,55 @@ +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.ExcelExportUtil; +import org.jeecgframework.poi.excel.entity.TemplateExportParams; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @Description: TODO + * @author: scott + * @date: 2020年09月16日 11:46 + */ +public class DaoChuTest { + private static final String basePath = "G:\\needtodeplay\\autopoi-framework-sy-4.0\\autopoi-web\\src\\test\\resources\\templates\\"; + + public static TemplateExportParams getTemplateParams(String name) { + return new TemplateExportParams(basePath + name + ".xlsx"); + } + + public static Workbook test(String name) { + TemplateExportParams params = getTemplateParams(name); + Map map = new HashMap(); + List> listMap = new ArrayList>(); + for (int i = 0; i < 3; i++) { + Map lm = new HashMap(); + lm.put("name", "姓名1" + i); + lm.put("isTts", i); + lm.put("sname", "s姓名"); + lm.put("ttsContent", "ttsContent内容"); + lm.put("rate", 1000 + i); + listMap.add(lm); + } + map.put("autoList", listMap); + Workbook workbook = ExcelExportUtil.exportExcel(params, map); + return workbook; + } + + public static void main(String[] args) throws IOException { + String temName = "test"; + String temNameNextM = "testNextMarge"; + Workbook workbook = test(temNameNextM); + File savefile = new File(basePath); + if (!savefile.exists()) { + savefile.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(basePath + "testNew.xlsx"); + workbook.write(fos); + fos.close(); + } +} diff --git a/autopoi/autopoi-web/src/test/java/DaoChuWordTest.java b/autopoi/autopoi-web/src/test/java/DaoChuWordTest.java new file mode 100644 index 0000000..a4b5220 --- /dev/null +++ b/autopoi/autopoi-web/src/test/java/DaoChuWordTest.java @@ -0,0 +1,57 @@ +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.jeecgframework.poi.word.WordExportUtil; + +import java.io.File; +import java.io.FileOutputStream; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * @Description: TODO + * @author: scott + * @date: 2020年09月16日 11:46 + */ +public class DaoChuWordTest { + private static final String basePath = "G:\\needtodeplay\\autopoi-framework-sy-4.0\\autopoi-web\\src\\test\\resources\\templates\\"; + + public static void main(String[] args) throws Exception { + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + String curTime = format.format(new Date()); + + Map map = new HashMap(); + List> mapList = new ArrayList>(); +// Map map1 = new HashMap(); +// map1.put("type", "个人所得税"); +// map1.put("presum", "1580"); +// map1.put("thissum", "1750"); +// map1.put("curmonth", "1-11月"); +// map1.put("now", curTime); +// mapList.add(map1); +// Map map2 = new HashMap(); +// map2.put("type", "增值税"); +// map2.put("presum", "1080"); +// map2.put("thissum", "1650"); +// map2.put("curmonth", "1-11月"); +// map2.put("now", curTime); +// mapList.add(map2); + map.put("taxlist", mapList); + map.put("totalpreyear", "2660"); + map.put("totalthisyear", "3400"); + + map.put("type", "增值税"); + map.put("presum", "1080"); + map.put("thissum", "1650"); + map.put("curmonth", "1-11月"); + map.put("now", curTime); + + //单列 + XWPFDocument document = WordExportUtil.exportWord07(basePath + "纳税信息.docx", map); + File savefile = new File("D:\\poi"); + if (!savefile.exists()) { + savefile.mkdirs(); + } + FileOutputStream fos = new FileOutputStream(basePath + "纳税信息new.docx"); + document.write(fos); + fos.close(); + } +} diff --git a/autopoi/autopoi-web/src/test/java/TestEntity.java b/autopoi/autopoi-web/src/test/java/TestEntity.java new file mode 100644 index 0000000..a49fe51 --- /dev/null +++ b/autopoi/autopoi-web/src/test/java/TestEntity.java @@ -0,0 +1,29 @@ +import org.jeecgframework.poi.excel.annotation.Excel; + +/** + * @Description: TODO + * @author: lsq + * @date: 2021年02月02日 16:31 + */ +public class TestEntity { + @Excel(name = "姓名", width = 15) + private String name; + @Excel(name = "年龄", width = 15) + private Integer age; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Integer getAge() { + return age; + } + + public void setAge(Integer age) { + this.age = age; + } +} diff --git a/autopoi/autopoi-web/src/test/resources/templates/test.xlsx b/autopoi/autopoi-web/src/test/resources/templates/test.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..fa9e7c1d207a48654945fdb12efe4a6b1beac12a GIT binary patch literal 11036 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 Tvl!qefeI22obxQ{^WFaei$h$) literal 0 HcmV?d00001 diff --git a/autopoi/autopoi-web/src/test/resources/templates/纳税信息.docx b/autopoi/autopoi-web/src/test/resources/templates/纳税信息.docx new file mode 100644 index 0000000000000000000000000000000000000000..f4f900c2f498a8852054679c9563e3ebcce9a3b8 GIT binary patch literal 16080 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 LN@Z~U{OkV!>U9|a literal 0 HcmV?d00001 diff --git a/autopoi/autopoi/pom.xml b/autopoi/autopoi/pom.xml new file mode 100644 index 0000000..76f5581 --- /dev/null +++ b/autopoi/autopoi/pom.xml @@ -0,0 +1,73 @@ + + 4.0.0 + + org.jeecgframework.boot3 + autopoi-parent + 3.7.0 + + autopoi + + + + org.apache.poi + poi + + + org.apache.poi + poi-ooxml + + + xml-apis + xml-apis + + + + + + org.apache.poi + poi-ooxml-full + + + + + + + + xerces + xercesImpl + + + + org.apache.poi + poi-scratchpad + + + + + com.google.guava + guava + + + + org.apache.commons + commons-lang3 + + + + + + org.slf4j + slf4j-api + true + + + + + org.springframework + spring-webmvc + true + + + + \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/core/util/ApplicationContextUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/core/util/ApplicationContextUtil.java new file mode 100644 index 0000000..7ae2072 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/core/util/ApplicationContextUtil.java @@ -0,0 +1,25 @@ +package org.jeecgframework.core.util; + +import org.springframework.beans.BeansException; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationContextAware; + +/** + * + * @author 张代浩 + * + */ +public class ApplicationContextUtil implements ApplicationContextAware { + + private static ApplicationContext context; + + + public void setApplicationContext(ApplicationContext context) + throws BeansException { + this.context = context; + } + + public static ApplicationContext getContext() { + return context; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/dict/service/AutoPoiDictServiceI.java b/autopoi/autopoi/src/main/java/org/jeecgframework/dict/service/AutoPoiDictServiceI.java new file mode 100644 index 0000000..59d3424 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/dict/service/AutoPoiDictServiceI.java @@ -0,0 +1,23 @@ +package org.jeecgframework.dict.service; + + +/** + * 描述: + * @author:scott + * @since:2017-4-12 下午04:58:15 + * @version:1.0 + */ +public interface AutoPoiDictServiceI{ + /** + * 方法描述: 查询数据字典 + * 作 者: yiming.zhang + * 日 期: 2014年5月11日-下午4:22:42 + * @param dicTable + * @param dicCode + * @param dicText + * @return + * 返回类型: List + */ + public String[] queryDict(String dicTable,String dicCode, String dicText); + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/ExcelCache.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/ExcelCache.java new file mode 100644 index 0000000..d434089 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/ExcelCache.java @@ -0,0 +1,99 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.cache; + +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.jeecgframework.poi.cache.manager.POICacheManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.Arrays; +import java.util.List; + +/** + * Excel类型的缓存 + * + * @author JEECG + * @date 2014年2月11日 + * @version 1.0 + */ +public final class ExcelCache { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelCache.class); + + public static Workbook getWorkbook(String url, Integer[] sheetNums, boolean needAll) { + InputStream is = null; + List sheetList = Arrays.asList(sheetNums); + try { + is = POICacheManager.getFile(url); + Workbook wb = WorkbookFactory.create(is); + // 删除其他的sheet + if (!needAll) { + for (int i = wb.getNumberOfSheets() - 1; i >= 0; i--) { + if (!sheetList.contains(i)) { + wb.removeSheetAt(i); + } + } + } + return wb; + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + try { + is.close(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + } + return null; + } + //update-begin-author:wangshuai date:20200730 for:jar 包上传到服务器后 autopoi 读取不到excel模版文件 #1505 + public static Workbook getWorkbookByTemplate(String url, Integer[] sheetNums, boolean needAll) { + List sheetList = Arrays.asList(sheetNums); + InputStream fis = null; + try { + //update-begin----author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作-------- + //ClassPathResource resource = new ClassPathResource(url); + fis = new FileInputStream(url); + LOGGER.info(" >>> poi3升级到4兼容改造工作, url="+url); + //fis = resource.getInputStream(); + //update-end-----author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作-------- + Workbook wb = WorkbookFactory.create(fis); + // 删除其他的sheet + if (!needAll) { + for (int i = wb.getNumberOfSheets() - 1; i >= 0; i--) { + if (!sheetList.contains(i)) { + wb.removeSheetAt(i); + } + } + } + return wb; + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + try { + fis.close(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + } + return null; + } + //update-end-author:wangshuai date:20200730 for:jar 包上传到服务器后 autopoi 读取不到excel模版文件 #1505 +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/ImageCache.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/ImageCache.java new file mode 100644 index 0000000..333e07c --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/ImageCache.java @@ -0,0 +1,99 @@ +/** + * Copyright 2013-2015 JueYue (qrb.jueyue@gmail.com) + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.cache; + +import org.apache.poi.util.IOUtils; +import org.jeecgframework.poi.cache.manager.POICacheManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.imageio.ImageIO; +import javax.swing.*; +import java.awt.*; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; + +/** + * 图片缓存处理 + * + * @author liusq + * 2022-05-27 下午4:16:32 + */ +public class ImageCache { + + private static final Logger LOGGER = LoggerFactory + .getLogger(ImageCache.class); + + public static byte[] getImage(String imagePath) { + InputStream is = POICacheManager.getFile(imagePath); + ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); + final ByteArrayOutputStream swapStream = new ByteArrayOutputStream(); + try { + int ch; + while ((ch = is.read()) != -1) { + swapStream.write(ch); + } + Image image = Toolkit.getDefaultToolkit().createImage(swapStream.toByteArray()); + BufferedImage bufferImg = toBufferedImage(image); + ImageIO.write(bufferImg, + imagePath.substring(imagePath.lastIndexOf(".") + 1, imagePath.length()), + byteArrayOut); + return byteArrayOut.toByteArray(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + return null; + } finally { + IOUtils.closeQuietly(is); + IOUtils.closeQuietly(swapStream); + IOUtils.closeQuietly(byteArrayOut); + } + + } + + + public static BufferedImage toBufferedImage(Image image) { + if (image instanceof BufferedImage) { + return (BufferedImage) image; + } + // This code ensures that all the pixels in the image are loaded + image = new ImageIcon(image).getImage(); + BufferedImage bimage = null; + GraphicsEnvironment ge = GraphicsEnvironment + .getLocalGraphicsEnvironment(); + try { + int transparency = Transparency.OPAQUE; + GraphicsDevice gs = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gs.getDefaultConfiguration(); + bimage = gc.createCompatibleImage(image.getWidth(null), + image.getHeight(null), transparency); + } catch (HeadlessException e) { + // The system does not have a screen + } + if (bimage == null) { + // Create a buffered image using the default color model + int type = BufferedImage.TYPE_INT_RGB; + bimage = new BufferedImage(image.getWidth(null), + image.getHeight(null), type); + } + // Copy image to buffered image + Graphics g = bimage.createGraphics(); + // Paint the image onto the buffered image + g.drawImage(image, 0, 0, null); + g.dispose(); + return bimage; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/WordCache.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/WordCache.java new file mode 100644 index 0000000..d219f66 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/WordCache.java @@ -0,0 +1,53 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.cache; + +import java.io.InputStream; + +import org.jeecgframework.poi.cache.manager.POICacheManager; +import org.jeecgframework.poi.word.entity.MyXWPFDocument; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * word 缓存中心 + * + * @author JEECG + * @date 2014年7月24日 下午10:54:31 + */ +public class WordCache { + + private static final Logger LOGGER = LoggerFactory.getLogger(WordCache.class); + + public static MyXWPFDocument getXWPFDocumen(String url) { + InputStream is = null; + try { + is = POICacheManager.getFile(url); + MyXWPFDocument doc = new MyXWPFDocument(is); + return doc; + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + try { + is.close(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + } + return null; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/manager/FileLoade.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/manager/FileLoade.java new file mode 100644 index 0000000..c50e217 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/manager/FileLoade.java @@ -0,0 +1,75 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.cache.manager; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; + +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 文件加载类,根据路径加载指定文件 + * + * @author JEECG + * @date 2014年2月10日 + * @version 1.0 + */ +class FileLoade { + + private static final Logger LOGGER = LoggerFactory.getLogger(FileLoade.class); + + public byte[] getFile(String url) { + FileInputStream fileis = null; + ByteArrayOutputStream baos = null; + try { + // 先用绝对路径查询,再查询相对路径 + try { + fileis = new FileInputStream(url); + } catch (FileNotFoundException e) { + String path = PoiPublicUtil.getWebRootPath(url); + fileis = new FileInputStream(path); + } + baos = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = fileis.read(buffer)) > -1) { + baos.write(buffer, 0, len); + } + baos.flush(); + return baos.toByteArray(); + } catch (FileNotFoundException e) { + LOGGER.error(e.getMessage(), e); + } catch (IOException e) { + LOGGER.error(e.getMessage(), e); + } finally { + try { + if (fileis != null) + fileis.close(); + if (fileis != null) + baos.close(); + } catch (IOException e) { + LOGGER.error(e.getMessage(), e); + } + } + LOGGER.error(fileis + "这个路径文件没有找到,请查询"); + return null; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/manager/POICacheManager.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/manager/POICacheManager.java new file mode 100644 index 0000000..a08dbbb --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/manager/POICacheManager.java @@ -0,0 +1,64 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.cache.manager; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.util.Arrays; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; + +/** + * 缓存管理 + * + * @author JEECG + * @date 2014年2月10日 + * @version 1.0 + */ +public final class POICacheManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(POICacheManager.class); + + private static LoadingCache loadingCache; + + static { + loadingCache = CacheBuilder.newBuilder().expireAfterWrite(7, TimeUnit.DAYS).maximumSize(50).build(new CacheLoader() { + @Override + public byte[] load(String url) throws Exception { + return new FileLoade().getFile(url); + } + }); + } + + public static InputStream getFile(String id) { + try { + // 复杂数据,防止操作原数据 + byte[] result = Arrays.copyOf(loadingCache.get(id), loadingCache.get(id).length); + return new ByteArrayInputStream(result); + } catch (ExecutionException e) { + LOGGER.error(e.getMessage(), e); + } + return null; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/package-info.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/package-info.java new file mode 100644 index 0000000..ced2f8d --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/cache/package-info.java @@ -0,0 +1,11 @@ +/** + * 对POI用到的模板进行缓存,进行统一管理,缓存工具暂时使用guava(脱离配置文件) + * 缓存方式统一为byte[] 屏蔽文件类型的差异 + * 缓存获取方式,URL或者URL+index(EXcel的) + */ +/** + * @author JEECG + * @date 2014年2月10日 + * @version 1.0 + */ +package org.jeecgframework.poi.cache; \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/entity/ImageEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/entity/ImageEntity.java new file mode 100644 index 0000000..a30dd03 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/entity/ImageEntity.java @@ -0,0 +1,104 @@ +package org.jeecgframework.poi.entity; + +/** + * word导出,图片设置和图片信息 + * + * @author liusq + * @date 2022-5-27 + */ +public class ImageEntity { + + public static String URL = "url"; + public static String Data = "data"; + /** + * 图片输入方式 + */ + private String type = URL; + /** + * 图片宽度 + */ + private int width; + // 图片高度 + private int height; + // 图片地址 + private String url; + // 图片信息 + private byte[] data; + + private int rowspan = 1; + private int colspan = 1; + + + public ImageEntity() { + + } + + public ImageEntity(byte[] data, int width, int height) { + this.data = data; + this.width = width; + this.height = height; + this.type = Data; + } + + public ImageEntity(String url, int width, int height) { + this.url = url; + this.width = width; + this.height = height; + } + + public byte[] getData() { + return data; + } + + public int getHeight() { + return height; + } + + public String getType() { + return type; + } + + public String getUrl() { + return url; + } + + public int getWidth() { + return width; + } + + public void setData(byte[] data) { + this.data = data; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setType(String type) { + this.type = type; + } + + public void setUrl(String url) { + this.url = url; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getRowspan() { + return rowspan; + } + + public void setRowspan(int rowspan) { + this.rowspan = rowspan; + } + + public int getColspan() { + return colspan; + } + + public void setColspan(int colspan) { + this.colspan = colspan; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelExportUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelExportUtil.java new file mode 100644 index 0000000..938d80d --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelExportUtil.java @@ -0,0 +1,243 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.TemplateExportParams; +import org.jeecgframework.poi.excel.entity.enmus.ExcelType; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.excel.export.ExcelBatchExportServer; +import org.jeecgframework.poi.excel.export.ExcelExportServer; +import org.jeecgframework.poi.excel.export.template.ExcelExportOfTemplateUtil; +import org.jeecgframework.poi.handler.inter.IExcelExportServer; +import org.jeecgframework.poi.handler.inter.IWriter; + +/** + * excel 导出工具类 + * + * @author JEECG + * @version 1.0 + * @date 2013-10-17 + */ +//update-begin---author:chenrui ---date:20231221 for:[issue/#5248]加强继承扩展便利性(删除final)------------ +public class ExcelExportUtil { +//update-end---author:chenrui ---date:20231221 for:[issue/#5248]加强继承扩展便利性(删除final)------------ + //update-begin---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + //单sheet最大值 + public static int USE_SXSSF_LIMIT = 100000; + //update-end---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + private ExcelExportUtil() { + } + + //---update-begin-----autor:scott------date:20191016-------for:导出字段支持自定义-------- + /** + * 根据Entity创建对应的Excel + * + * @param entity + * 表格标题属性 + * @param pojoClass + * Excel对象Class + * @param dataSet + * Excel对象数据List + * @param exportFields + * 自定义导出Excel字段数组 + */ + public static Workbook exportExcel(ExportParams entity, Class pojoClass, Collection dataSet,String[] exportFields) { + Workbook workbook; + if (ExcelType.HSSF.equals(entity.getType())) { + workbook = new HSSFWorkbook(); + } else if (dataSet.size() < 1000) { + workbook = new XSSFWorkbook(); + } else { + workbook = new SXSSFWorkbook(); + } + new ExcelExportServer().createSheet(workbook, entity, pojoClass, dataSet,exportFields); + return workbook; + } + //---update-end-----autor:scott------date:20191016-------for:导出字段支持自定义-------- + + + /** + * 根据Entity创建对应的Excel + * + * @param entity + * 表格标题属性 + * @param pojoClass + * Excel对象Class + * @param dataSet + * Excel对象数据List + */ + public static Workbook exportExcel(ExportParams entity, Class pojoClass, Collection dataSet) { + Workbook workbook; + if (ExcelType.HSSF.equals(entity.getType())) { + workbook = new HSSFWorkbook(); + } else if (dataSet.size() < 1000) { + workbook = new XSSFWorkbook(); + } else { + workbook = new SXSSFWorkbook(); + } + new ExcelExportServer().createSheet(workbook, entity, pojoClass, dataSet,null); + return workbook; + } + + /** + * 根据Map创建对应的Excel + * + * @param entity + * 表格标题属性 + * @param pojoClass + * Excel对象Class + * @param dataSet + * Excel对象数据List + */ + public static Workbook exportExcel(ExportParams entity, List entityList, Collection> dataSet) { + Workbook workbook; + if (ExcelType.HSSF.equals(entity.getType())) { + workbook = new HSSFWorkbook(); + } else if (dataSet.size() < 1000) { + workbook = new XSSFWorkbook(); + } else { + workbook = new SXSSFWorkbook(); + } + new ExcelExportServer().createSheetForMap(workbook, entity, entityList, dataSet); + return workbook; + } + + /** + * 一个excel 创建多个sheet + * + * @param list + * 多个Map key title 对应表格Title key entity 对应表格对应实体 key data + * Collection 数据 + * @return + */ + public static Workbook exportExcel(List> list, ExcelType type) { + Workbook workbook; + if (ExcelType.HSSF.equals(type)) { + workbook = new HSSFWorkbook(); + } else { + workbook = new XSSFWorkbook(); + } + for (Map map : list) { + ExcelExportServer server = new ExcelExportServer(); + server.createSheet(workbook, (ExportParams) map.get("title"), (Class) map.get("entity"), (Collection) map.get("data"),null); + } + return workbook; + } + + /** + * 导出文件通过模板解析,不推荐这个了,推荐全部通过模板来执行处理 + * + * @param params + * 导出参数类 + * @param pojoClass + * 对应实体 + * @param dataSet + * 实体集合 + * @param map + * + * 模板集合 + * @return + */ + public static Workbook exportExcel(TemplateExportParams params, Class pojoClass, Collection dataSet, Map map) { + return new ExcelExportOfTemplateUtil().createExcleByTemplate(params, pojoClass, dataSet, map); + } + + /** + * 导出文件通过模板解析只有模板,没有集合 + * + * @param params + * 导出参数类 + * @param map + * 模板集合 + * @return + */ + public static Workbook exportExcel(TemplateExportParams params, Map map) { + return new ExcelExportOfTemplateUtil().createExcleByTemplate(params, null, null, map); + } + + + //update-begin---author:liusq Date:20211227 for:[LOWCOD-2521]大数据导出方法【全局】---- + /** + * 大数据量导出 + * + * @param entity 表格标题属性 + * @param pojoClass Excel对象Class + * @date 2022年1月4号 + * @return ExcelBatchExportServer 批处理服务 + */ + public static IWriter exportBigExcel(ExportParams entity, Class pojoClass) { + ExcelBatchExportServer batchServer = new ExcelBatchExportServer(); + batchServer.init(entity, pojoClass); + return batchServer; + } + + /** + * 大数据量导出 + * + * @param entity + * @param excelParams + * @date 2022年1月4号 + * @return ExcelBatchExportServer 批处理服务 + */ + public static IWriter exportBigExcel(ExportParams entity, List excelParams) { + ExcelBatchExportServer batchServer = new ExcelBatchExportServer(); + batchServer.init(entity, excelParams); + return batchServer; + } + + /** + * 大数据量导出 + * + * @param entity 导出参数属性 + * @param pojoClass Excel对象Class + * @param server 查询数据的接口 + * @param queryParams 查询数据的参数 + * @date 2022年1月4号 + * @return Workbook + */ + public static Workbook exportBigExcel(ExportParams entity, Class pojoClass, + IExcelExportServer server, Object queryParams) { + ExcelBatchExportServer batchServer = new ExcelBatchExportServer(); + batchServer.init(entity, pojoClass); + return batchServer.exportBigExcel(server, queryParams); + } + + /** + * 大数据量导出 + * @param entity + * @param excelParams + * @param server 查询数据的接口 + * @param queryParams 查询数据的参数 + * @date 2022年1月4号 + * @return Workbook + */ + public static Workbook exportBigExcel(ExportParams entity, List excelParams, + IExcelExportServer server, Object queryParams) { + ExcelBatchExportServer batchServer = new ExcelBatchExportServer(); + batchServer.init(entity, excelParams); + return batchServer.exportBigExcel(server, queryParams); + } + //update-end---author:liusq Date:20211227 for:[LOWCOD-2521]大数据导出方法【全局】---- +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelImportCheckUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelImportCheckUtil.java new file mode 100644 index 0000000..6f13dab --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelImportCheckUtil.java @@ -0,0 +1,457 @@ +package org.jeecgframework.poi.excel; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.jeecgframework.core.util.ApplicationContextUtil; +import org.jeecgframework.dict.service.AutoPoiDictServiceI; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.jeecgframework.poi.excel.annotation.ExcelCollection; +import org.jeecgframework.poi.excel.annotation.ExcelTarget; +import org.jeecgframework.poi.excel.annotation.ExcelVerify; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.entity.params.ExcelCollectionParams; +import org.jeecgframework.poi.excel.entity.params.ExcelImportEntity; +import org.jeecgframework.poi.excel.entity.params.ExcelVerifyEntity; +import org.jeecgframework.poi.excel.imports.ExcelImportServer; +import org.jeecgframework.poi.exception.excel.ExcelImportException; +import org.jeecgframework.poi.exception.excel.enums.ExcelImportEnum; +import org.jeecgframework.poi.util.ExcelUtil; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.math.BigDecimal; +import java.util.*; + +/** + * EXCEL INCLUE CHECK + * 验证excel标题是否存在,当前默认有0.8(80%)即可通过验证 + */ +public class ExcelImportCheckUtil { + private final static Logger LOGGER = LoggerFactory.getLogger(ExcelImportCheckUtil.class); + + /**当有标题到达多少可以通过验证*/ + public static final Double defScreenRate = 0.8; + + /** + * check inclue filed match rate + * @param inputstream + * @param pojoClass + * @param params + * @return + */ + public static Boolean check(InputStream inputstream, Class pojoClass, ImportParams params) { + return check(inputstream,pojoClass,params,defScreenRate); + } + /** + * check inclue filed match rate + * @param inputstream + * @param pojoClass + * @param params + * @param screenRate field match rate (defalut:0.8) + * @return + */ + public static Boolean check(InputStream inputstream, Class pojoClass, ImportParams params, Double screenRate) { + Workbook book = null; + int errorNum = 0; + int successNum = 0; + if (!(inputstream.markSupported())) { + inputstream = new PushbackInputStream(inputstream, 8); + } + try { +// if (POIFSFileSystem.hasPOIFSHeader(inputstream)) { +// book = new HSSFWorkbook(inputstream); +// } else if (POIXMLDocument.hasOOXMLHeader(inputstream)) { +// book = new XSSFWorkbook(OPCPackage.open(inputstream)); +// } + book = WorkbookFactory.create(inputstream); + LOGGER.info(" >>> poi3升级到4兼容改造工作, pojoClass="+pojoClass); + } catch (Exception e) { + e.printStackTrace(); + } + for (int i = 0; i < params.getSheetNum(); i++) { + Row row = null; + //跳过表头和标题行 + Iterator rows; + try{ + rows= book.getSheetAt(i).rowIterator(); + }catch (Exception e){ + //为空说明读取不到,故不是excel + throw new RuntimeException("请导入正确格式的excel文件!"); + } + + + for (int j = 0; j < params.getTitleRows() + params.getHeadRows(); j++) { + try{ + row = rows.next(); + }catch (NoSuchElementException e){ + //为空说明标题不出在,excel格式错误 + throw new RuntimeException("请填写内容标题!"); + } + } + Sheet sheet = book.getSheetAt(i); + Map titlemap = null; + try { + titlemap = getTitleMap(sheet, params); + } catch (Exception e) { + e.printStackTrace(); + } + Set columnIndexSet = titlemap.keySet(); + Integer maxColumnIndex = Collections.max(columnIndexSet); + Integer minColumnIndex = Collections.min(columnIndexSet); + while (rows.hasNext() && (row == null || sheet.getLastRowNum() - row.getRowNum() > params.getLastOfInvalidRow())) { + row = rows.next(); + Map excelParams = new HashMap(); + List excelCollection = new ArrayList(); + String targetId = null; + if (!Map.class.equals(pojoClass)) { + Field fileds[] = PoiPublicUtil.getClassFields(pojoClass); + ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); + if (etarget != null) { + targetId = etarget.value(); + } + try { + getAllExcelField(targetId, fileds, excelParams, excelCollection, pojoClass, null); + } catch (Exception e) { + e.printStackTrace(); + } + } + try { + int firstCellNum = row.getFirstCellNum(); + if (firstCellNum > minColumnIndex) { + firstCellNum = minColumnIndex; + } + int lastCellNum = row.getLastCellNum(); + if (lastCellNum < maxColumnIndex + 1) { + lastCellNum = maxColumnIndex + 1; + } + for (int j = firstCellNum, le = lastCellNum; j < le; j++) { + String titleString = (String) titlemap.get(j); + if (excelParams.containsKey(titleString) || Map.class.equals(pojoClass)) { + successNum+=1; + }else{ + if(excelCollection.size()>0){ + Iterator var33 = excelCollection.iterator(); + ExcelCollectionParams param = (ExcelCollectionParams)var33.next(); + if (param.getExcelParams().containsKey(titleString)) { + successNum+=1; + }else{ + errorNum+=1; + } + }else{ + errorNum+=1; + } + } + } + if(successNumerrorNum){ + if(errorNum>0){ + double newNumber = (double) successNum / (successNum + errorNum); + BigDecimal bg = new BigDecimal(newNumber); + double f1 = bg.setScale(1, BigDecimal.ROUND_HALF_UP).doubleValue(); + if(f1 getTitleMap(Sheet sheet, ImportParams params) throws Exception { + Map titlemap = new HashMap(); + Iterator cellTitle = null; + String collectionName = null; + Row headRow = null; + int headBegin = params.getTitleRows(); + int allRowNum = sheet.getPhysicalNumberOfRows(); + while(headRow == null && headBegin < allRowNum){ + headRow = sheet.getRow(headBegin++); + } + if(headRow==null){ + throw new Exception("不识别该文件"); + } + if (ExcelUtil.isMergedRegion(sheet, headRow.getRowNum(), 0)) { + params.setHeadRows(2); + }else{ + params.setHeadRows(1); + } + cellTitle = headRow.cellIterator(); + while (cellTitle.hasNext()) { + Cell cell = cellTitle.next(); + String value = getKeyValue(cell); + if (StringUtils.isNotEmpty(value)) { + titlemap.put(cell.getColumnIndex(), value);//加入表头列表 + } + } + + //多行表头 + for (int j = headBegin; j < headBegin + params.getHeadRows()-1; j++) { + headRow = sheet.getRow(j); + cellTitle = headRow.cellIterator(); + while (cellTitle.hasNext()) { + Cell cell = cellTitle.next(); + String value = getKeyValue(cell); + if (StringUtils.isNotEmpty(value)) { + int columnIndex = cell.getColumnIndex(); + //当前cell的上一行是否为合并单元格 + if(ExcelUtil.isMergedRegion(sheet, cell.getRowIndex()-1, columnIndex)){ + collectionName = ExcelUtil.getMergedRegionValue(sheet, cell.getRowIndex()-1, columnIndex); + if(params.isIgnoreHeader(collectionName)){ + titlemap.put(cell.getColumnIndex(), value); + }else{ + titlemap.put(cell.getColumnIndex(), collectionName + "_" + value); + } + }else{ + titlemap.put(cell.getColumnIndex(), value); + } + } + } + } + return titlemap; + } + /** + * 获取key的值,针对不同类型获取不同的值 + * + * @Author JEECG + * @date 20201023 + * @param cell + * @return + */ + private static String getKeyValue(Cell cell) { + if(cell==null){ + return null; + } + Object obj = null; + switch (cell.getCellType()) { + case STRING: + obj = cell.getStringCellValue(); + break; + case BOOLEAN: + obj = cell.getBooleanCellValue(); + break; + case NUMERIC: + obj = cell.getNumericCellValue(); + break; + case FORMULA: + obj = cell.getCellFormula(); + break; + } + return obj == null ? null : obj.toString().trim(); + } + + /** + * 获取需要导出的全部字段 + * + * + * + * @param targetId + * 目标ID + * @param fields + * @param excelCollection + * @throws Exception + */ + public static void getAllExcelField(String targetId, Field[] fields, Map excelParams, List excelCollection, Class pojoClass, List getMethods) throws Exception { + ExcelImportEntity excelEntity = null; + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (PoiPublicUtil.isNotUserExcelUserThis(null, field, targetId)) { + continue; + } + if (PoiPublicUtil.isCollection(field.getType())) { + // 集合对象设置属性 + ExcelCollectionParams collection = new ExcelCollectionParams(); + collection.setName(field.getName()); + Map temp = new HashMap(); + ParameterizedType pt = (ParameterizedType)field.getGenericType(); + Class clz = (Class)pt.getActualTypeArguments()[0]; + collection.setType(clz); + getExcelFieldList(targetId, PoiPublicUtil.getClassFields(clz), clz, temp, (List)null); + collection.setExcelParams(temp); + collection.setExcelName(((ExcelCollection)field.getAnnotation(ExcelCollection.class)).name()); + additionalCollectionName(collection); + excelCollection.add(collection); + } else if (PoiPublicUtil.isJavaClass(field)) { + addEntityToMap(targetId, field, (ExcelImportEntity)excelEntity, pojoClass, getMethods, excelParams); + } else { + List newMethods = new ArrayList(); + if (getMethods != null) { + newMethods.addAll(getMethods); + } + newMethods.add(PoiPublicUtil.getMethod(field.getName(), pojoClass)); + getAllExcelField(targetId, PoiPublicUtil.getClassFields(field.getType()), excelParams, excelCollection, field.getType(), newMethods); + } + } + } + public static void getExcelFieldList(String targetId, Field[] fields, Class pojoClass, Map temp, List getMethods) throws Exception { + ExcelImportEntity excelEntity = null; + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (!PoiPublicUtil.isNotUserExcelUserThis((List)null, field, targetId)) { + if (PoiPublicUtil.isJavaClass(field)) { + addEntityToMap(targetId, field, (ExcelImportEntity)excelEntity, pojoClass, getMethods, temp); + } else { + List newMethods = new ArrayList(); + if (getMethods != null) { + newMethods.addAll(getMethods); + } + + newMethods.add(PoiPublicUtil.getMethod(field.getName(), pojoClass, field.getType())); + getExcelFieldList(targetId, PoiPublicUtil.getClassFields(field.getType()), field.getType(), temp, newMethods); + } + } + } + } + /** + * 追加集合名称到前面 + * + * @param collection + */ + private static void additionalCollectionName(ExcelCollectionParams collection) { + Set keys = new HashSet(); + keys.addAll(collection.getExcelParams().keySet()); + Iterator var3 = keys.iterator(); + + while(var3.hasNext()) { + String key = (String)var3.next(); + collection.getExcelParams().put(collection.getExcelName() + "_" + key, collection.getExcelParams().get(key)); + collection.getExcelParams().remove(key); + } + } + /** + * 把这个注解解析放到类型对象中 + * + * @param targetId + * @param field + * @param excelEntity + * @param pojoClass + * @param getMethods + * @param temp + * @throws Exception + */ + public static void addEntityToMap(String targetId, Field field, ExcelImportEntity excelEntity, Class pojoClass, List getMethods, Map temp) throws Exception { + Excel excel = field.getAnnotation(Excel.class); + excelEntity = new ExcelImportEntity(); + excelEntity.setType(excel.type()); + excelEntity.setSaveUrl(excel.savePath()); + excelEntity.setSaveType(excel.imageType()); + excelEntity.setReplace(excel.replace()); + excelEntity.setDatabaseFormat(excel.databaseFormat()); + excelEntity.setVerify(getImportVerify(field)); + excelEntity.setSuffix(excel.suffix()); + excelEntity.setNumFormat(excel.numFormat()); + excelEntity.setGroupName(excel.groupName()); + //update-begin-author:taoYan date:20180202 for:TASK #2067 【bug excel 问题】excel导入字典文本翻译问题 + excelEntity.setMultiReplace(excel.multiReplace()); + if(StringUtils.isNotEmpty(excel.dicCode())){ + AutoPoiDictServiceI jeecgDictService = null; + try { + jeecgDictService = ApplicationContextUtil.getContext().getBean(AutoPoiDictServiceI.class); + } catch (Exception e) { + } + if(jeecgDictService!=null){ + String[] dictReplace = jeecgDictService.queryDict(excel.dictTable(), excel.dicCode(), excel.dicText()); + if(excelEntity.getReplace()!=null && dictReplace!=null && dictReplace.length!=0){ + excelEntity.setReplace(dictReplace); + } + } + } + //update-end-author:taoYan date:20180202 for:TASK #2067 【bug excel 问题】excel导入字典文本翻译问题 + getExcelField(targetId, field, excelEntity, excel, pojoClass); + if (getMethods != null) { + List newMethods = new ArrayList(); + newMethods.addAll(getMethods); + newMethods.add(excelEntity.getMethod()); + excelEntity.setMethods(newMethods); + } + temp.put(excelEntity.getName(), excelEntity); + + } + public static void getExcelField(String targetId, Field field, ExcelImportEntity excelEntity, Excel excel, Class pojoClass) throws Exception { + excelEntity.setName(getExcelName(excel.name(), targetId)); + String fieldname = field.getName(); + //update-begin-author:taoyan for:TASK #2798 【例子】导入扩展方法,支持自定义导入字段转换规则 + excelEntity.setMethod(PoiPublicUtil.getMethod(fieldname, pojoClass, field.getType(),excel.importConvert())); + //update-end-author:taoyan for:TASK #2798 【例子】导入扩展方法,支持自定义导入字段转换规则 + if (StringUtils.isNotEmpty(excel.importFormat())) { + excelEntity.setFormat(excel.importFormat()); + } else { + excelEntity.setFormat(excel.format()); + } + } + /** + * 判断在这个单元格显示的名称 + * + * @param exportName + * @param targetId + * @return + */ + public static String getExcelName(String exportName, String targetId) { + if (exportName.indexOf("_") < 0) { + return exportName; + } + String[] arr = exportName.split(","); + for (String str : arr) { + if (str.indexOf(targetId) != -1) { + return str.split("_")[0]; + } + } + return null; + } + /** + * 获取导入校验参数 + * + * @param field + * @return + */ + public static ExcelVerifyEntity getImportVerify(Field field) { + ExcelVerify verify = field.getAnnotation(ExcelVerify.class); + if (verify != null) { + ExcelVerifyEntity entity = new ExcelVerifyEntity(); + entity.setEmail(verify.isEmail()); + entity.setInterHandler(verify.interHandler()); + entity.setMaxLength(verify.maxLength()); + entity.setMinLength(verify.minLength()); + entity.setMobile(verify.isMobile()); + entity.setNotNull(verify.notNull()); + entity.setRegex(verify.regex()); + entity.setRegexTip(verify.regexTip()); + entity.setTel(verify.isTel()); + return entity; + } + return null; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelImportUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelImportUtil.java new file mode 100644 index 0000000..d3aeef7 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelImportUtil.java @@ -0,0 +1,168 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.List; + +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.entity.result.ExcelImportResult; +import org.jeecgframework.poi.excel.imports.ExcelImportServer; +import org.jeecgframework.poi.excel.imports.sax.SaxReadExcel; +import org.jeecgframework.poi.excel.imports.sax.parse.ISaxRowRead; +import org.jeecgframework.poi.handler.inter.IExcelReadRowHanlder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Excel 导入工具 + * + * @author JEECG + * @date 2013-9-24 + * @version 1.0 + */ +@SuppressWarnings({ "unchecked" }) +public final class ExcelImportUtil { + + private ExcelImportUtil() { + } + + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelImportUtil.class); + + /** + * Excel 导入 数据源本地文件,不返回校验结果 导入 字 段类型 Integer,Long,Double,Date,String,Boolean + * + * @param file + * @param pojoClass + * @param params + * @return + * @throws Exception + */ + public static List importExcel(File file, Class pojoClass, ImportParams params) { + FileInputStream in = null; + List result = null; + try { + in = new FileInputStream(file); + result = new ExcelImportServer().importExcelByIs(in, pojoClass, params).getList(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + try { + in.close(); + } catch (IOException e) { + LOGGER.error(e.getMessage(), e); + } + } + return result; + } + + /** + * Excel 导入 数据源IO流,不返回校验结果 导入 字段类型 Integer,Long,Double,Date,String,Boolean + * + * @param file + * @param pojoClass + * @param params + * @return + * @throws Exception + */ + public static List importExcel(InputStream inputstream, Class pojoClass, ImportParams params) throws Exception { + return new ExcelImportServer().importExcelByIs(inputstream, pojoClass, params).getList(); + } + + /** + * Excel 导入 数据源IO流,返回校验结果 字段类型 Integer,Long,Double,Date,String,Boolean + * + * @param file + * @param pojoClass + * @param params + * @return + * @throws Exception + */ + public static ExcelImportResult importExcelVerify(InputStream inputstream, Class pojoClass, ImportParams params) throws Exception { + return new ExcelImportServer().importExcelByIs(inputstream, pojoClass, params); + } + + /** + * Excel 导入 数据源本地文件,返回校验结果 字段类型 Integer,Long,Double,Date,String,Boolean + * + * @param file + * @param pojoClass + * @param params + * @return + * @throws Exception + */ + public static ExcelImportResult importExcelVerify(File file, Class pojoClass, ImportParams params) { + FileInputStream in = null; + try { + in = new FileInputStream(file); + return new ExcelImportServer().importExcelByIs(in, pojoClass, params); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } finally { + try { + in.close(); + } catch (IOException e) { + LOGGER.error(e.getMessage(), e); + } + } + return null; + } + + /** + * Excel 通过SAX解析方法,适合大数据导入,不支持图片 导入 数据源IO流,不返回校验结果 导入 字段类型 + * Integer,Long,Double,Date,String,Boolean + * + * @param inputstream + * @param pojoClass + * @param params + * @return + * @throws Exception + */ + public static List importExcelBySax(InputStream inputstream, Class pojoClass, ImportParams params) { + return new SaxReadExcel().readExcel(inputstream, pojoClass, params, null, null); + } + + /** + * Excel 通过SAX解析方法,适合大数据导入,不支持图片 导入 数据源本地文件,不返回校验结果 导入 字 段类型 + * Integer,Long,Double,Date,String,Boolean + * + * @param file + * @param rowRead + * @return + * @throws Exception + */ + @SuppressWarnings("rawtypes") + public static void importExcelBySax(InputStream inputstream, Class pojoClass, ImportParams params, IExcelReadRowHanlder hanlder) { + new SaxReadExcel().readExcel(inputstream, pojoClass, params, null, hanlder); + } + + /** + * Excel 通过SAX解析方法,适合大数据导入,不支持图片 导入 数据源IO流,不返回校验结果 导入 字段类型 + * Integer,Long,Double,Date,String,Boolean + * + * @param file + * @param rowRead + * @return + * @throws Exception + */ + public static List importExcelBySax(InputStream inputstream, ISaxRowRead rowRead) { + return new SaxReadExcel().readExcel(inputstream, null, null, rowRead, null); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelToHtmlUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelToHtmlUtil.java new file mode 100644 index 0000000..e9927fd --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/ExcelToHtmlUtil.java @@ -0,0 +1,67 @@ +package org.jeecgframework.poi.excel; + +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.html.ExcelToHtmlServer; + +/** + * Excel 变成界面 + * + * @author JEECG + * @date 2015年5月10日 上午11:51:48 + */ +public final class ExcelToHtmlUtil { + + private ExcelToHtmlUtil() { + } + + /** + * 转换成为Table + * + * @param wb + * Excel + * @return + */ + public static String toTableHtml(Workbook wb) { + return new ExcelToHtmlServer(wb, false, 0).printPage(); + } + + /** + * 转换成为Table + * + * @param wb + * Excel + * @param sheetNum + * sheetNum + * @return + */ + public static String toTableHtml(Workbook wb, int sheetNum) { + return new ExcelToHtmlServer(wb, false, sheetNum).printPage(); + } + + /** + * 转换成为完整界面 + * + * @param wb + * Excel + * @param sheetNum + * sheetNum + * @return + */ + public static String toAllHtml(Workbook wb) { + return new ExcelToHtmlServer(wb, true, 0).printPage(); + } + + /** + * 转换成为完整界面 + * + * @param wb + * Excel + * @param sheetNum + * sheetNum + * @return + */ + public static String toAllHtml(Workbook wb, int sheetNum) { + return new ExcelToHtmlServer(wb, true, sheetNum).printPage(); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/Excel.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/Excel.java new file mode 100644 index 0000000..06310c0 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/Excel.java @@ -0,0 +1,206 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.annotation.Inherited; + +/** + * Excel 导出基本注释 + * + * @author JEECG + * @date 2014年6月20日 下午10:25:12 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +//update-begin---author:chenrui ---date:20231221 for:[issue/#5248]加强继承扩展便利性------------ +@Inherited +//update-end---author:chenrui ---date:20231221 for:[issue/#5248]加强继承扩展便利性------------ +public @interface Excel { + + /** + * 导出时间设置,如果字段是Date类型则不需要设置 数据库如果是string 类型,这个需要设置这个数据库格式 + */ + public String databaseFormat() default "yyyyMMddHHmmss"; + + /** + * 导出的时间格式,以这个是否为空来判断是否需要格式化日期 + */ + public String exportFormat() default ""; + + /** + * 时间格式,相当于同时设置了exportFormat 和 importFormat + */ + public String format() default ""; + + /** + * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 + */ + public double height() default 10; + + /** + * 导出类型 1 从file读取_old ,2 是从数据库中读取字节文件, 3文件地址_new, 4网络地址 同样导入也是一样的 + * + */ + public int imageType() default 3; + + /** + * 导入的时间格式,以这个是否为空来判断是否需要格式化日期 + */ + public String importFormat() default ""; + + /** + * 文字后缀,如% 90 变成90% + */ + public String suffix() default ""; + + /** + * 是否换行 即支持\n + */ + public boolean isWrap() default true; + + /** + * 合并单元格依赖关系,比如第二列合并是基于第一列 则{1}就可以了 + */ + public int[] mergeRely() default {}; + + /** + * 纵向合并内容相同的单元格 + */ + public boolean mergeVertical() default false; + + /** + * 导出时,对应数据库的字段 主要是用户区分每个字段, 不能有annocation重名的 导出时的列名 + * 导出排序跟定义了annotation的字段的顺序有关 可以使用a_id,b_id来确实是否使用 + */ + public String name(); + + /** + * 是否需要纵向合并单元格(用于含有list中,单个的单元格,合并list创建的多个row) + */ + public boolean needMerge() default false; + + /** + * 展示到第几个可以使用a_id,b_id来确定不同排序 + */ + public String orderNum() default "0"; + + /** + * 值得替换 导出是{"男_1","女_0"} 导入反过来,所以只用写一个 + */ + public String[] replace() default {}; + + /** + * 导入路径,如果是图片可以填写,默认是upload/className/ IconEntity这个类对应的就是upload/Icon/ + * + */ + public String savePath() default "upload"; + + /** + * 导出类型 1 是文本 2 是图片,3是函数,4是数字 默认是文本 + */ + public int type() default 1; + + /** + * 导出时在excel中每个列的宽 单位为字符,一个汉字=2个字符 如 以列名列内容中较合适的长度 例如姓名列6 【姓名一般三个字】 + * 性别列4【男女占1,但是列标题两个汉字】 限制1-255 + */ + public double width() default 10; + + /** + * 是否自动统计数据,如果是统计,true的话在最后追加一行统计,把所有数据都和 这个处理会吞没异常,请注意这一点 + * + * @return + */ + public boolean isStatistics() default false; + + /** + * 方法描述: 数据字典表 + * 作 者: yiming.zhang + * 日 期: 2014年5月11日-下午5:26:40 + * @return + * 返回类型: String + */ + public String dictTable() default ""; + + /** + * 方法描述: 数据code + * 作 者: yiming.zhang + * 日 期: 2014年5月13日-下午9:37:16 + * @return + * 返回类型: String + */ + public String dicCode() default ""; + + /** + * 方法描述: 数据Text + * 作 者: yiming.zhang + * 日 期: 2014年5月11日-下午5:29:05 + * @return + * 返回类型: String + */ + public String dicText() default ""; + + /** + * 导入数据是否需要转化 + * 若是为true,则需要在pojo中加入 方法:convertset字段名(String text) + * @return + */ + public boolean importConvert() default false; + /** + * 导出数据是否需要转化 + * 若是为true,则需要在pojo中加入方法:convertget字段名() + * @return + */ + public boolean exportConvert() default false; + + /** + * 值的替换是否支持替换多个(默认true,若数据库值本来就包含逗号则需要配置该值为false) + * @author taoYan + * @since 2018年8月1日 + */ + public boolean multiReplace() default true; + + /** + * 父表头 + * @return + */ + String groupName() default ""; + + /** + * 数字格式化,参数是Pattern,使用的对象是DecimalFormat + * @return + */ + String numFormat() default ""; + /** + * 是否需要隐藏该列 + * @return + */ + public boolean isColumnHidden() default false; + /** + * 固定的某一列,解决不好解析的问题 + * @return + */ + public int fixedIndex() default -1; + /** + * 这个是不是超链接,如果是需要实现接口返回对象 + * @return + */ + public boolean isHyperlink() default false; +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelCollection.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelCollection.java new file mode 100644 index 0000000..4285e19 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelCollection.java @@ -0,0 +1,54 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.ArrayList; + +/** + * 导出的集合 + * + * @author JEECG 2013年8月24日 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ExcelCollection { + + /** + * 定义excel导出ID 来限定导出字段,处理一个类对应多个不同名称的情况 + */ + public String id() default ""; + + /** + * 导出时,对应数据库的字段 主要是用户区分每个字段, 不能有annocation重名的 导出时的列名 + * 导出排序跟定义了annotation的字段的顺序有关 可以使用a_id,b_id来确实是否使用 + */ + public String name(); + + /** + * 展示到第几个同样可以使用a_id,b_id + * + */ + public String orderNum() default "0"; + + /** + * 创建时创建的类型 默认值是 arrayList + */ + public Class type() default ArrayList.class; +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelEntity.java new file mode 100644 index 0000000..6e59673 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelEntity.java @@ -0,0 +1,49 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标记是不是导出excel 标记为实体类 + * + * @author JEECG + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ExcelEntity { + + /** + * 定义excel导出ID 来限定导出字段,处理一个类对应多个不同名称的情况 + */ + public String id() default ""; + + /** + * 导出时,对应数据库的字段 主要是用户区分每个字段, 不能有annocation重名的 导出时的列名 + * 导出排序跟定义了annotation的字段的顺序有关 可以使用a_id,b_id来确实是否使用 + */ + public String name() default ""; + + /** + * 导出时,是否展示name对应的文本 + * @return + */ + boolean show() default false; +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelIgnore.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelIgnore.java new file mode 100644 index 0000000..e63791c --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelIgnore.java @@ -0,0 +1,34 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * 标记为excel 创建实体忽略,放置死循环的造成 + * + * @author JEECG + * @date 2013-9-24 + * @version 1.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ExcelIgnore { + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelTarget.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelTarget.java new file mode 100644 index 0000000..49191a8 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelTarget.java @@ -0,0 +1,36 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * excel 导出是用于标记id的 + * + * @author JEECG + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE }) +public @interface ExcelTarget { + /** + * 定义excel导出ID 来限定导出字段 + */ + public String value(); +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelVerify.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelVerify.java new file mode 100644 index 0000000..64af075 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/annotation/ExcelVerify.java @@ -0,0 +1,95 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Excel 导入校验 + * + * @author JEECG + * @date 2014年6月23日 下午10:46:26 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ExcelVerify { + /** + * 接口校验 + * + * @return + */ + public boolean interHandler() default false; + + /** + * 是电子邮件 + * + * @return + */ + public boolean isEmail() default false; + + /** + * 是13位移动电话 + * + * @return + */ + public boolean isMobile() default false; + + /** + * 是座机号码 + * + * @return + */ + public boolean isTel() default false; + + /** + * 最大长度 + * + * @return + */ + public int maxLength() default -1; + + /** + * 最小长度 + * + * @return + */ + public int minLength() default -1; + + /** + * 不允许空 + * + * @return + */ + public boolean notNull() default false; + + /** + * 正在表达式 + * + * @return + */ + public String regex() default ""; + + /** + * 正在表达式,错误提示信息 + * + * @return + */ + public String regexTip() default "数据不符合规范"; + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ExcelBaseParams.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ExcelBaseParams.java new file mode 100644 index 0000000..3c84d8a --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ExcelBaseParams.java @@ -0,0 +1,41 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity; + +import org.jeecgframework.poi.handler.inter.IExcelDataHandler; + +/** + * 基础参数 + * + * @author JEECG + * @date 2014年6月20日 下午1:56:52 + */ +public class ExcelBaseParams { + + /** + * 数据处理接口,以此为主,replace,format都在这后面 + */ + private IExcelDataHandler dataHanlder; + + public IExcelDataHandler getDataHanlder() { + return dataHanlder; + } + + public void setDataHanlder(IExcelDataHandler dataHanlder) { + this.dataHanlder = dataHanlder; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ExportParams.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ExportParams.java new file mode 100644 index 0000000..ef41d25 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ExportParams.java @@ -0,0 +1,294 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity; + +import org.apache.poi.ss.usermodel.IndexedColors; +import org.jeecgframework.poi.excel.entity.enmus.ExcelType; +import org.jeecgframework.poi.excel.export.styler.ExcelExportStylerDefaultImpl; + +/** + * Excel 导出参数 + * + * @author JEECG + * @version 1.0 2013年8月24日 + */ +public class ExportParams extends ExcelBaseParams { + + /** + * 表格名称 + */ + private String title; + + /** + * 表格名称 + */ + private short titleHeight = 10; + + /** + * 第二行名称 + */ + private String secondTitle; + + /** + * 表格名称 + */ + private short secondTitleHeight = 8; + /** + * sheetName + */ + private String sheetName; + /** + * 过滤的属性 + */ + private String[] exclusions; + /** + * 是否添加需要需要 + */ + private boolean addIndex; + /** + * 是否添加需要需要 + */ + private String indexName = "序号"; + /** + * 冰冻列 + */ + private int freezeCol; + /** + * 表头颜色 + */ + private short color = IndexedColors.WHITE.index; + /** + * 属性说明行的颜色 例如:HSSFColor.SKY_BLUE.index 默认 + */ + private short headerColor = IndexedColors.SKY_BLUE.index; + /** + * Excel 导出版本 + */ + private ExcelType type = ExcelType.HSSF; + /** + * Excel 导出style + */ + private Class style = ExcelExportStylerDefaultImpl.class; + /** + * 是否创建表头 + */ + private boolean isCreateHeadRows = true; + + /** + * 本地文件存储根路径 base path + */ + private String imageBasePath; +//update-begin---author:liusq Date:20220104 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + /** + * 是否固定表头 + */ + private boolean isFixedTitle = true; + /** + * 单sheet最大值 + * 03版本默认6W行,07默认100W + */ + private int maxNum = 0; + /** + * 导出时在excel中每个列的高度 单位为字符,一个汉字=2个字符 + * 全局设置,优先使用 + */ + private short height = 0; + + /** + * 只读 + */ + private boolean readonly = false; +//update-end---author:liusq Date:20220104 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + public ExportParams() { + + } + + public ExportParams(String title, String sheetName) { + this.title = title; + this.sheetName = sheetName; + } + + public ExportParams(String title, String sheetName, ExcelType type) { + this.title = title; + this.sheetName = sheetName; + this.type = type; + } + + public ExportParams(String title, String secondTitle, String sheetName) { + this.title = title; + this.secondTitle = secondTitle; + this.sheetName = sheetName; + } + + public ExportParams(String title, String secondTitle, String sheetName,String imageBasePath) { + this.title = title; + this.secondTitle = secondTitle; + this.sheetName = sheetName; + this.imageBasePath = imageBasePath; + } + + public short getColor() { + return color; + } + + public String[] getExclusions() { + return exclusions; + } + + public short getHeaderColor() { + return headerColor; + } + + public String getSecondTitle() { + return secondTitle; + } + + public short getSecondTitleHeight() { + return (short) (secondTitleHeight * 50); + } + + public String getSheetName() { + return sheetName; + } + + public String getTitle() { + return title; + } + + public short getTitleHeight() { + return (short) (titleHeight * 50); + } + + public boolean isAddIndex() { + return addIndex; + } + + public void setAddIndex(boolean addIndex) { + this.addIndex = addIndex; + } + + public void setColor(short color) { + this.color = color; + } + + public void setExclusions(String[] exclusions) { + this.exclusions = exclusions; + } + + public void setHeaderColor(short headerColor) { + this.headerColor = headerColor; + } + + public void setSecondTitle(String secondTitle) { + this.secondTitle = secondTitle; + } + + public void setSecondTitleHeight(short secondTitleHeight) { + this.secondTitleHeight = secondTitleHeight; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setTitleHeight(short titleHeight) { + this.titleHeight = titleHeight; + } + + public ExcelType getType() { + return type; + } + + public void setType(ExcelType type) { + this.type = type; + } + + public String getIndexName() { + return indexName; + } + + public void setIndexName(String indexName) { + this.indexName = indexName; + } + + public Class getStyle() { + return style; + } + + public void setStyle(Class style) { + this.style = style; + } + + public int getFreezeCol() { + return freezeCol; + } + + public void setFreezeCol(int freezeCol) { + this.freezeCol = freezeCol; + } + + public boolean isCreateHeadRows() { + return isCreateHeadRows; + } + + public void setCreateHeadRows(boolean isCreateHeadRows) { + this.isCreateHeadRows = isCreateHeadRows; + } + + public String getImageBasePath() { + return imageBasePath; + } + + public void setImageBasePath(String imageBasePath) { + this.imageBasePath = imageBasePath; + } + + public int getMaxNum() { + return maxNum; + } + + public void setMaxNum(int maxNum) { + this.maxNum = maxNum; + } + + public short getHeight() { + return height == -1 ? -1 : (short) (height * 50); + } + + public void setHeight(short height) { + this.height = height; + } + + public boolean isFixedTitle() { + return isFixedTitle; + } + + public void setFixedTitle(boolean fixedTitle) { + isFixedTitle = fixedTitle; + } + + public boolean isReadonly() { + return readonly; + } + + public void setReadonly(boolean readonly) { + this.readonly = readonly; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ImportParams.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ImportParams.java new file mode 100644 index 0000000..599706d --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/ImportParams.java @@ -0,0 +1,206 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity; + +import org.jeecgframework.poi.handler.inter.IExcelVerifyHandler; + +import java.util.List; + +/** + * 导入参数设置 + * + * @author JEECG + * @date 2013-9-24 + * @version 1.0 + */ +public class ImportParams extends ExcelBaseParams { + /** + * 表格标题行数,默认0 + */ + private int titleRows = 0; + /** + * 表头行数,默认1 + */ + private int headRows = 1; + /** + * 字段真正值和列标题之间的距离 默认0 + */ + private int startRows = 0; + /** + * 主键设置,如何这个cell没有值,就跳过 或者认为这个是list的下面的值 + */ + private int keyIndex = 0; + //update-begin-author:liusq date:20220605 for:https://gitee.com/jeecg/jeecg-boot/issues/I57UPC 导入 ImportParams 中没有startSheetIndex参数 + /** + * 开始读取的sheet位置,默认为0 + */ + private int startSheetIndex = 0; + //update-end-author:liusq date:20220605 for:https://gitee.com/jeecg/jeecg-boot/issues/I57UPC 导入 ImportParams 中没有startSheetIndex参数 + + //update-begin-author:taoyan date:20211210 for:https://gitee.com/jeecg/jeecg-boot/issues/I45C32 导入空白sheet报错 + /** + * 上传表格需要读取的sheet 数量,默认为0 + */ + private int sheetNum = 0; + //update-end-author:taoyan date:20211210 for:https://gitee.com/jeecg/jeecg-boot/issues/I45C32 导入空白sheet报错 + /** + * 是否需要保存上传的Excel,默认为false + */ + private boolean needSave = false; + /** + * 保存上传的Excel目录,默认是 如 TestEntity这个类保存路径就是 + * upload/excelUpload/Test/yyyyMMddHHmss_***** 保存名称上传时间_五位随机数 + */ + private String saveUrl = "upload/excelUpload"; + /** + * 校验处理接口 + */ + private IExcelVerifyHandler verifyHanlder; + /** + * 最后的无效行数 + */ + private int lastOfInvalidRow = 0; + + /** + * 不需要解析的表头 只作为多表头展示,无字段与其绑定 + */ + private List ignoreHeaderList; + + /** + * 指定导入的sheetName + */ + private String sheetName; + + /** + * 图片列 集合 + */ + private List imageList; + + public int getHeadRows() { + return headRows; + } + + public int getKeyIndex() { + return keyIndex; + } + + public String getSaveUrl() { + return saveUrl; + } + + public int getSheetNum() { + return sheetNum; + } + + public int getStartRows() { + return startRows; + } + + public int getTitleRows() { + return titleRows; + } + + public IExcelVerifyHandler getVerifyHanlder() { + return verifyHanlder; + } + + public boolean isNeedSave() { + return needSave; + } + + public void setHeadRows(int headRows) { + this.headRows = headRows; + } + + public void setKeyIndex(int keyIndex) { + this.keyIndex = keyIndex; + } + + public void setNeedSave(boolean needSave) { + this.needSave = needSave; + } + + public void setSaveUrl(String saveUrl) { + this.saveUrl = saveUrl; + } + + public void setSheetNum(int sheetNum) { + this.sheetNum = sheetNum; + } + + public void setStartRows(int startRows) { + this.startRows = startRows; + } + + public void setTitleRows(int titleRows) { + this.titleRows = titleRows; + } + + public void setVerifyHanlder(IExcelVerifyHandler verifyHanlder) { + this.verifyHanlder = verifyHanlder; + } + + public int getLastOfInvalidRow() { + return lastOfInvalidRow; + } + + public void setLastOfInvalidRow(int lastOfInvalidRow) { + this.lastOfInvalidRow = lastOfInvalidRow; + } + + public List getImageList() { + return imageList; + } + + public void setImageList(List imageList) { + this.imageList = imageList; + } + + public List getIgnoreHeaderList() { + return ignoreHeaderList; + } + + public void setIgnoreHeaderList(List ignoreHeaderList) { + this.ignoreHeaderList = ignoreHeaderList; + } + + public String getSheetName() { + return sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = sheetName; + } + + /** + * 根据表头显示的文字 判断是否忽略该表头 + * @param text + * @return + */ + public boolean isIgnoreHeader(String text){ + if(ignoreHeaderList!=null && ignoreHeaderList.indexOf(text)>=0){ + return true; + } + return false; + } + public int getStartSheetIndex() { + return startSheetIndex; + } + + public void setStartSheetIndex(int startSheetIndex) { + this.startSheetIndex = startSheetIndex; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/TemplateExportParams.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/TemplateExportParams.java new file mode 100644 index 0000000..6282389 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/TemplateExportParams.java @@ -0,0 +1,218 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity; + +import org.jeecgframework.poi.excel.export.styler.ExcelExportStylerDefaultImpl; + +/** + * 模板导出参数设置 + * + * @author JEECG + * @date 2013-10-17 + * @version 1.0 + */ +public class TemplateExportParams extends ExcelBaseParams { + + /** + * 输出全部的sheet + */ + private boolean scanAllsheet = false; + /** + * 模板的路径 + */ + private String templateUrl; + + /** + * 需要导出的第几个 sheetNum,默认是第0个 + */ + private Integer[] sheetNum = new Integer[] { 0 }; + + /** + * 这只sheetName 不填就使用原来的 + */ + private String[] sheetName; + + /** + * 表格列标题行数,默认1 + */ + private int headingRows = 1; + + /** + * 表格列标题开始行,默认1 + */ + private int headingStartRow = 1; + /** + * 设置数据源的NUM + */ + private int dataSheetNum = 0; + /** + * Excel 导出style + */ + private Class style = ExcelExportStylerDefaultImpl.class; + /** + * FOR EACH 用到的局部变量 + */ + private String tempParams = "t"; + //列循环支持 + private boolean colForEach = false; + + /** + * 默认构造器 + */ + public TemplateExportParams() { + + } + + /** + * 构造器 + * + * @param templateUrl + * 模板路径 + * @param scanAllsheet + * 是否输出全部的sheet + * @param sheetName + * sheet的名称,可不填 + */ + public TemplateExportParams(String templateUrl, boolean scanAllsheet, String... sheetName) { + this.templateUrl = templateUrl; + this.scanAllsheet = scanAllsheet; + if (sheetName != null && sheetName.length > 0) { + this.sheetName = sheetName; + + } + } + + /** + * 构造器 + * + * @param templateUrl + * 模板路径 + * @param sheetNum + * sheet 的位置,可不填 + */ + public TemplateExportParams(String templateUrl, Integer... sheetNum) { + this.templateUrl = templateUrl; + if (sheetNum != null && sheetNum.length > 0) { + this.sheetNum = sheetNum; + } + } + + /** + * 单个sheet输出构造器 + * + * @param templateUrl + * 模板路径 + * @param sheetName + * sheet的名称 + * @param sheetNum + * sheet的位置,可不填 + */ + public TemplateExportParams(String templateUrl, String sheetName, Integer... sheetNum) { + this.templateUrl = templateUrl; + this.sheetName = new String[] { sheetName }; + if (sheetNum != null && sheetNum.length > 0) { + this.sheetNum = sheetNum; + } + } + + public int getHeadingRows() { + return headingRows; + } + + public int getHeadingStartRow() { + return headingStartRow; + } + + public String[] getSheetName() { + return sheetName; + } + + public Integer[] getSheetNum() { + return sheetNum; + } + + public String getTemplateUrl() { + return templateUrl; + } + + public void setHeadingRows(int headingRows) { + this.headingRows = headingRows; + } + + public void setHeadingStartRow(int headingStartRow) { + this.headingStartRow = headingStartRow; + } + + public void setSheetName(String[] sheetName) { + this.sheetName = sheetName; + } + + public void setSheetName(String sheetName) { + this.sheetName = new String[] { sheetName }; + } + + public void setSheetNum(Integer[] sheetNum) { + this.sheetNum = sheetNum; + } + + public void setSheetNum(Integer sheetNum) { + this.sheetNum = new Integer[] { sheetNum }; + } + + public void setTemplateUrl(String templateUrl) { + this.templateUrl = templateUrl; + } + + public Class getStyle() { + return style; + } + + public void setStyle(Class style) { + this.style = style; + } + + public int getDataSheetNum() { + return dataSheetNum; + } + + public void setDataSheetNum(int dataSheetNum) { + this.dataSheetNum = dataSheetNum; + } + + public boolean isScanAllsheet() { + return scanAllsheet; + } + + public void setScanAllsheet(boolean scanAllsheet) { + this.scanAllsheet = scanAllsheet; + } + + public String getTempParams() { + return tempParams; + } + + public void setTempParams(String tempParams) { + this.tempParams = tempParams; + } + + public boolean isColForEach() { + return colForEach; + } + + public void setColForEach(boolean colForEach) { + this.colForEach = colForEach; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/CellValueType.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/CellValueType.java new file mode 100644 index 0000000..bbd3ede --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/CellValueType.java @@ -0,0 +1,28 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.enmus; + +/** + * Cell 值得类型 + * + * @author JEECG + * @date 2014年12月29日 下午10:20:49 + */ +public enum CellValueType { + + String, Number, Boolean, Date, TElement, Null, None; + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/ExcelStyleType.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/ExcelStyleType.java new file mode 100644 index 0000000..65fbf36 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/ExcelStyleType.java @@ -0,0 +1,48 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.enmus; + +import org.jeecgframework.poi.excel.export.styler.ExcelExportStylerBorderImpl; +import org.jeecgframework.poi.excel.export.styler.ExcelExportStylerColorImpl; +import org.jeecgframework.poi.excel.export.styler.ExcelExportStylerDefaultImpl; + +/** + * 插件提供的几个默认样式 + * + * @author JEECG + * @date 2015年1月9日 下午9:02:24 + */ +public enum ExcelStyleType { + + NONE("默认样式", ExcelExportStylerDefaultImpl.class), BORDER("边框样式", ExcelExportStylerBorderImpl.class), COLOR("间隔行样式", ExcelExportStylerColorImpl.class); + + private String name; + private Class clazz; + + ExcelStyleType(String name, Class clazz) { + this.name = name; + this.clazz = clazz; + } + + public Class getClazz() { + return clazz; + } + + public String getName() { + return name; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/ExcelType.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/ExcelType.java new file mode 100644 index 0000000..c4e6b36 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/enmus/ExcelType.java @@ -0,0 +1,28 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.enmus; + +/** + * Excel Type + * + * @author JEECG + * @date 2014年12月29日 下午9:08:21 + */ +public enum ExcelType { + + HSSF, XSSF; + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelBaseEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelBaseEntity.java new file mode 100644 index 0000000..f67a36e --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelBaseEntity.java @@ -0,0 +1,184 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.params; + +import java.lang.reflect.Method; +import java.util.List; + +/** + * Excel 导入导出基础对象类 + * + * @author JEECG + * @date 2014年6月20日 下午2:26:09 + */ +public class ExcelBaseEntity { + /** + * 对应name + */ + protected String name; + /** + * 对应type + */ + private int type = 1; + /** + * 数据库格式 + */ + private String databaseFormat; + /** + * 导出日期格式 + */ + private String format; + + /** + * 数字格式化,参数是Pattern,使用的对象是DecimalFormat + */ + private String numFormat; + /** + * 替换值表达式 :"男_1","女_0" + */ + private String[] replace; + /** + * 替换是否是替换多个值 + */ + private boolean multiReplace; + + /** + * 表头组名称 + */ + private String groupName; + + /** + * set/get方法 + */ + private Method method; + /** + * 固定的列 + */ + private Integer fixedIndex; + /** + * 字典名称 + */ + private String dict; + /** + * 这个是不是超链接,如果是需要实现接口返回对象 + */ + private boolean hyperlink; + + private List methods; + + public String getDatabaseFormat() { + return databaseFormat; + } + + public String getFormat() { + return format; + } + + public Method getMethod() { + return method; + } + + public List getMethods() { + return methods; + } + + public String getName() { + return name; + } + + public String[] getReplace() { + return replace; + } + + public int getType() { + return type; + } + + public void setDatabaseFormat(String databaseFormat) { + this.databaseFormat = databaseFormat; + } + + public void setFormat(String format) { + this.format = format; + } + + public void setMethod(Method method) { + this.method = method; + } + + public void setMethods(List methods) { + this.methods = methods; + } + + public void setName(String name) { + this.name = name; + } + + public void setReplace(String[] replace) { + this.replace = replace; + } + + public void setType(int type) { + this.type = type; + } + + public boolean isMultiReplace() { + return multiReplace; + } + public void setMultiReplace(boolean multiReplace) { + this.multiReplace = multiReplace; + } + + public String getNumFormat() { + return numFormat; + } + + public void setNumFormat(String numFormat) { + this.numFormat = numFormat; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public Integer getFixedIndex() { + return fixedIndex; + } + + public void setFixedIndex(Integer fixedIndex) { + this.fixedIndex = fixedIndex; + } + + public String getDict() { + return dict; + } + + public void setDict(String dict) { + this.dict = dict; + } + + public boolean isHyperlink() { + return hyperlink; + } + + public void setHyperlink(boolean hyperlink) { + this.hyperlink = hyperlink; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelCollectionParams.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelCollectionParams.java new file mode 100644 index 0000000..fefbc8a --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelCollectionParams.java @@ -0,0 +1,77 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.params; + +import java.util.Map; + +/** + * Excel 对于的 Collection + * + * @author JEECG + * @date 2013-9-26 + * @version 1.0 + */ +public class ExcelCollectionParams { + + /** + * 集合对应的名称 + */ + private String name; + /** + * Excel 列名称 + */ + private String excelName; + /** + * 实体对象 + */ + private Class type; + /** + * 这个list下面的参数集合实体对象 + */ + private Map excelParams; + + public Map getExcelParams() { + return excelParams; + } + + public String getName() { + return name; + } + + public Class getType() { + return type; + } + + public void setExcelParams(Map excelParams) { + this.excelParams = excelParams; + } + + public void setName(String name) { + this.name = name; + } + + public void setType(Class type) { + this.type = type; + } + + public String getExcelName() { + return excelName; + } + + public void setExcelName(String excelName) { + this.excelName = excelName; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelExportEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelExportEntity.java new file mode 100644 index 0000000..4d8cc8f --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelExportEntity.java @@ -0,0 +1,306 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.params; + +import java.util.ArrayList; +import java.util.List; + +/** + * excel 导出工具类,对cell类型做映射 + * + * @author JEECG + * @version 1.0 2013年8月24日 + */ +public class ExcelExportEntity extends ExcelBaseEntity implements Comparable { + + /** + * 如果是MAP导出,这个是map的key + */ + private Object key; + + private double width = 10; + + private double height = 10; + + /** + * 图片的类型,1是文件地址(class目录),2是数据库字节,3是文件地址(磁盘目录),4网络图片 + */ + private int exportImageType = 3; + + /** + * 图片储存位置(磁盘目录) 用于导出获取图片绝对路径 + */ + private String imageBasePath; + + /** + * 排序顺序 + */ + private int orderNum = 0; + + /** + * 是否支持换行 + */ + private boolean isWrap; + + /** + * 是否需要合并 + */ + private boolean needMerge; + /** + * 单元格纵向合并 + */ + private boolean mergeVertical; + /** + * 合并依赖 + */ + private int[] mergeRely; + /** + * 后缀 + */ + private String suffix; + /** + * 统计 + */ + private boolean isStatistics; + + /** + * 是否横向合并 + */ + private boolean colspan; + + /** + * 被横向合并的列名称 + */ + private List subColumnList; + + /** + * 父表头的名称 + */ + private String groupName; + /** + * 是否隐藏列 + */ + private boolean isColumnHidden; + + private List list; + + public ExcelExportEntity() { + + } + + public ExcelExportEntity(String name) { + super.name = name; + } + + public ExcelExportEntity(String name, Object key) { + super.name = name; + this.key = key; + } + + /** + * 构造器 + * @param name 描述-文字 + * @param key 存储key 如果是MAP导出,这个是map的key + * @param colspan 是否为合并列(a,b列公用一个表头c,则a,b,c都需要设置为true) + */ + public ExcelExportEntity(String name, Object key, boolean colspan) { + super.name = name; + this.key = key; + this.colspan = colspan; + this.needMerge = colspan; + } + + public ExcelExportEntity(String name, Object key, int width) { + super.name = name; + this.width = width; + this.key = key; + } + + public int getExportImageType() { + return exportImageType; + } + + public double getHeight() { + return height; + } + + public Object getKey() { + return key; + } + + public List getList() { + return list; + } + + public int[] getMergeRely() { + return mergeRely == null ? new int[0] : mergeRely; + } + + public int getOrderNum() { + return orderNum; + } + + public double getWidth() { + return width; + } + + public boolean isMergeVertical() { + return mergeVertical; + } + + public boolean isNeedMerge() { + return needMerge; + } + + public boolean isWrap() { + return isWrap; + } + + public void setExportImageType(int exportImageType) { + this.exportImageType = exportImageType; + } + + public void setHeight(double height) { + this.height = height; + } + + public void setKey(Object key) { + this.key = key; + } + + public void setList(List list) { + this.list = list; + } + + public void setMergeRely(int[] mergeRely) { + this.mergeRely = mergeRely; + } + + public void setMergeVertical(boolean mergeVertical) { + this.mergeVertical = mergeVertical; + } + + public void setNeedMerge(boolean needMerge) { + this.needMerge = needMerge; + } + + public void setOrderNum(int orderNum) { + this.orderNum = orderNum; + } + + public void setWidth(double width) { + this.width = width; + } + + public void setWrap(boolean isWrap) { + this.isWrap = isWrap; + } + + public String getSuffix() { + return suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } + + public boolean isStatistics() { + return isStatistics; + } + + public void setStatistics(boolean isStatistics) { + this.isStatistics = isStatistics; + } + + public String getImageBasePath() { + return imageBasePath; + } + + public void setImageBasePath(String imageBasePath) { + this.imageBasePath = imageBasePath; + } + + public boolean isColspan() { + return colspan; + } + + public void setColspan(boolean colspan) { + this.colspan = colspan; + } + + public List getSubColumnList() { + return subColumnList; + } + + public void setSubColumnList(List subColumnList) { + this.subColumnList = subColumnList; + } + + public String getGroupName() { + return groupName; + } + + public void setGroupName(String groupName) { + this.groupName = groupName; + } + + public boolean isColumnHidden() { + return isColumnHidden; + } + + public void setColumnHidden(boolean columnHidden) { + isColumnHidden = columnHidden; + } + + /** + * 是否为合并子列 + * @return + */ + public boolean isSubColumn(){ + return this.colspan && (this.subColumnList==null || this.subColumnList.size()==0); + } + + /** + * 是否为合并父列 + * @return + */ + public boolean isMergeColumn(){ + return this.colspan && this.subColumnList!=null && this.subColumnList.size()>0; + } + + + /** + * 获取被合并的子列 + * @param all + * @return + */ + public List initSubExportEntity(List all){ + List sub = new ArrayList(); + for (ExcelExportEntity temp : all) { + if(this.subColumnList.contains(temp.getKey())){ + sub.add(temp); + } + } + this.setList(sub); + return sub; + } + + @Override + public int compareTo(ExcelExportEntity prev) { + return this.getOrderNum() - prev.getOrderNum(); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelForEachParams.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelForEachParams.java new file mode 100644 index 0000000..449fed2 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelForEachParams.java @@ -0,0 +1,125 @@ +package org.jeecgframework.poi.excel.entity.params; + +import java.io.Serializable; +import java.util.Stack; + +import org.apache.poi.ss.usermodel.CellStyle; + +/** + * 模板for each是的参数 + * @author JueYue + * @date 2015年4月29日 下午9:22:48 + */ +public class ExcelForEachParams implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + /** + * key + */ + private String name; + /** + * key + */ + private Stack tempName; + /** + * 模板的cellStyle + */ + private CellStyle cellStyle; + /** + * 行高 + */ + private short height; + /** + * 常量值 + */ + private String constValue; + /** + * 列合并 + */ + private int colspan = 1; + /** + * 行合并 + */ + private int rowspan = 1; + /** + * 行合并 + */ + private boolean collectCell; + + public ExcelForEachParams() { + + } + + public ExcelForEachParams(String name, CellStyle cellStyle, short height) { + this.name = name; + this.cellStyle = cellStyle; + this.height = height; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public CellStyle getCellStyle() { + return cellStyle; + } + + public void setCellStyle(CellStyle cellStyle) { + this.cellStyle = cellStyle; + } + + public short getHeight() { + return height; + } + + public void setHeight(short height) { + this.height = height; + } + + public String getConstValue() { + return constValue; + } + + public void setConstValue(String constValue) { + this.constValue = constValue; + } + + public int getColspan() { + return colspan; + } + + public void setColspan(int colspan) { + this.colspan = colspan; + } + + public int getRowspan() { + return rowspan; + } + + public void setRowspan(int rowspan) { + this.rowspan = rowspan; + } + + public boolean isCollectCell() { + return collectCell; + } + + public void setCollectCell(boolean collectCell) { + this.collectCell = collectCell; + } + + public Stack getTempName() { + return tempName; + } + + public void setTempName(Stack tempName) { + this.tempName = tempName; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelImportEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelImportEntity.java new file mode 100644 index 0000000..58d05f5 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelImportEntity.java @@ -0,0 +1,110 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.params; + +import java.util.List; + +/** + * excel 导入工具类,对cell类型做映射 + * + * @author JEECG + * @version 1.0 2013年8月24日 + */ +public class ExcelImportEntity extends ExcelBaseEntity { + /** + * 对应 Collection NAME + */ + private String collectionName; + /** + * 保存图片的地址 当saveType设置为3/4时,此值可以设置为:local,minio,alioss + */ + private String saveUrl; + /** + * 保存图片的类型,1是文件_old,2是数据库字节,3文件地址_new,4网络地址 + */ + private int saveType; + /** + * 对应exportType + */ + private String classType; + /** + * 校驗參數 + */ + private ExcelVerifyEntity verify; + /** + * 后缀 + */ + private String suffix; + + private List list; + + public String getClassType() { + return classType; + } + + public String getCollectionName() { + return collectionName; + } + + public List getList() { + return list; + } + + public int getSaveType() { + return saveType; + } + + public String getSaveUrl() { + return saveUrl; + } + + public ExcelVerifyEntity getVerify() { + return verify; + } + + public void setClassType(String classType) { + this.classType = classType; + } + + public void setCollectionName(String collectionName) { + this.collectionName = collectionName; + } + + public void setList(List list) { + this.list = list; + } + + public void setSaveType(int saveType) { + this.saveType = saveType; + } + + public void setSaveUrl(String saveUrl) { + this.saveUrl = saveUrl; + } + + public void setVerify(ExcelVerifyEntity verify) { + this.verify = verify; + } + + public String getSuffix() { + return suffix; + } + + public void setSuffix(String suffix) { + this.suffix = suffix; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelTemplateParams.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelTemplateParams.java new file mode 100644 index 0000000..619bea6 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelTemplateParams.java @@ -0,0 +1,66 @@ +package org.jeecgframework.poi.excel.entity.params; + +import java.io.Serializable; + +import org.apache.poi.ss.usermodel.CellStyle; + +/** + * 模板便利是的参数 + * + * @author JEECG + * @date 2015年4月29日 下午9:22:48 + */ +public class ExcelTemplateParams implements Serializable { + + /** + * + */ + private static final long serialVersionUID = 1L; + /** + * key + */ + private String name; + /** + * 模板的cellStyle + */ + private CellStyle cellStyle; + /** + * 行高 + */ + private short height; + + public ExcelTemplateParams() { + + } + + public ExcelTemplateParams(String name, CellStyle cellStyle, short height) { + this.name = name; + this.cellStyle = cellStyle; + this.height = height; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public CellStyle getCellStyle() { + return cellStyle; + } + + public void setCellStyle(CellStyle cellStyle) { + this.cellStyle = cellStyle; + } + + public short getHeight() { + return height; + } + + public void setHeight(short height) { + this.height = height; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelVerifyEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelVerifyEntity.java new file mode 100644 index 0000000..7cdc386 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/ExcelVerifyEntity.java @@ -0,0 +1,159 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.params; + +/** + * Excel 校验对象 + * + * @author JEECG + * @date 2014年6月29日 下午4:24:59 + */ +public class ExcelVerifyEntity { + + /** + * 接口校验 + * + * @return + */ + private boolean interHandler; + + /** + * 不允许空 + * + * @return + */ + private boolean notNull; + + /** + * 是13位移动电话 + * + * @return + */ + private boolean isMobile; + /** + * 是座机号码 + * + * @return + */ + private boolean isTel; + + /** + * 是电子邮件 + * + * @return + */ + private boolean isEmail; + + /** + * 最小长度 + * + * @return + */ + private int minLength; + + /** + * 最大长度 + * + * @return + */ + private int maxLength; + + /** + * 正在表达式 + * + * @return + */ + private String regex; + /** + * 正在表达式,错误提示信息 + * + * @return + */ + private String regexTip; + + public int getMaxLength() { + return maxLength; + } + + public int getMinLength() { + return minLength; + } + + public String getRegex() { + return regex; + } + + public String getRegexTip() { + return regexTip; + } + + public boolean isEmail() { + return isEmail; + } + + public boolean isInterHandler() { + return interHandler; + } + + public boolean isMobile() { + return isMobile; + } + + public boolean isNotNull() { + return notNull; + } + + public boolean isTel() { + return isTel; + } + + public void setEmail(boolean isEmail) { + this.isEmail = isEmail; + } + + public void setInterHandler(boolean interHandler) { + this.interHandler = interHandler; + } + + public void setMaxLength(int maxLength) { + this.maxLength = maxLength; + } + + public void setMinLength(int minLength) { + this.minLength = minLength; + } + + public void setMobile(boolean isMobile) { + this.isMobile = isMobile; + } + + public void setNotNull(boolean notNull) { + this.notNull = notNull; + } + + public void setRegex(String regex) { + this.regex = regex; + } + + public void setRegexTip(String regexTip) { + this.regexTip = regexTip; + } + + public void setTel(boolean isTel) { + this.isTel = isTel; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/MergeEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/MergeEntity.java new file mode 100644 index 0000000..e23b69a --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/params/MergeEntity.java @@ -0,0 +1,84 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.params; + +import java.util.List; + +/** + * 合并单元格使用对象 + * + * Created by jue on 14-6-11. + */ +public class MergeEntity { + /** + * 合并开始行 + */ + private int startRow; + /** + * 合并结束行 + */ + private int endRow; + /** + * 文字 + */ + private String text; + /** + * 依赖关系文本 + */ + private List relyList; + + public MergeEntity() { + + } + + public MergeEntity(String text, int startRow, int endRow) { + this.text = text; + this.endRow = endRow; + this.startRow = startRow; + } + + public int getEndRow() { + return endRow; + } + + public List getRelyList() { + return relyList; + } + + public int getStartRow() { + return startRow; + } + + public String getText() { + return text; + } + + public void setEndRow(int endRow) { + this.endRow = endRow; + } + + public void setRelyList(List relyList) { + this.relyList = relyList; + } + + public void setStartRow(int startRow) { + this.startRow = startRow; + } + + public void setText(String text) { + this.text = text; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/result/ExcelImportResult.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/result/ExcelImportResult.java new file mode 100644 index 0000000..835163d --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/result/ExcelImportResult.java @@ -0,0 +1,79 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.result; + +import java.util.List; + +import org.apache.poi.ss.usermodel.Workbook; + +/** + * 导入返回类 + * + * @author JEECG + * @date 2014年6月29日 下午5:12:10 + */ +public class ExcelImportResult { + + /** + * 结果集 + */ + private List list; + + /** + * 是否存在校验失败 + */ + private boolean verfiyFail; + + /** + * 数据源 + */ + private Workbook workbook; + + public ExcelImportResult() { + + } + + public ExcelImportResult(List list, boolean verfiyFail, Workbook workbook) { + this.list = list; + this.verfiyFail = verfiyFail; + this.workbook = workbook; + } + + public List getList() { + return list; + } + + public Workbook getWorkbook() { + return workbook; + } + + public boolean isVerfiyFail() { + return verfiyFail; + } + + public void setList(List list) { + this.list = list; + } + + public void setVerfiyFail(boolean verfiyFail) { + this.verfiyFail = verfiyFail; + } + + public void setWorkbook(Workbook workbook) { + this.workbook = workbook; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/result/ExcelVerifyHanlderResult.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/result/ExcelVerifyHanlderResult.java new file mode 100644 index 0000000..d24a19d --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/result/ExcelVerifyHanlderResult.java @@ -0,0 +1,63 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.result; + +/** + * Excel导入处理返回结果 + * + * @author JEECG + * @date 2014年6月23日 下午11:03:29 + */ +public class ExcelVerifyHanlderResult { + /** + * 是否正确 + */ + private boolean success; + /** + * 错误信息 + */ + private String msg; + + public ExcelVerifyHanlderResult() { + + } + + public ExcelVerifyHanlderResult(boolean success) { + this.success = success; + } + + public ExcelVerifyHanlderResult(boolean success, String msg) { + this.success = success; + this.msg = msg; + } + + public String getMsg() { + return msg; + } + + public boolean isSuccess() { + return success; + } + + public void setMsg(String msg) { + this.msg = msg; + } + + public void setSuccess(boolean success) { + this.success = success; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/sax/SaxReadCellEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/sax/SaxReadCellEntity.java new file mode 100644 index 0000000..36223bb --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/sax/SaxReadCellEntity.java @@ -0,0 +1,62 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.sax; + +import org.jeecgframework.poi.excel.entity.enmus.CellValueType; + +/** + * Cell 对象 + * + * @author JEECG + * @date 2014年12月29日 下午10:12:57 + */ +public class SaxReadCellEntity { + /** + * 值类型 + */ + private CellValueType cellType; + /** + * 值 + */ + private Object value; + + public SaxReadCellEntity(CellValueType cellType, Object value) { + this.cellType = cellType; + this.value = value; + } + + public CellValueType getCellType() { + return cellType; + } + + public void setCellType(CellValueType cellType) { + this.cellType = cellType; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + @Override + public String toString() { + return "[type=" + cellType.toString() + ",value=" + value + "]"; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/vo/PoiBaseConstants.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/vo/PoiBaseConstants.java new file mode 100644 index 0000000..22cf8b8 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/entity/vo/PoiBaseConstants.java @@ -0,0 +1,43 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.entity.vo; + +/** + * 基础常量 Created by jue on 14-4-21. + */ +public interface PoiBaseConstants { + /** + * 字段属性对应方法 + */ + public static String GET = "get"; + /** + * 字段属性对应方法 + */ + public static String SET = "set"; + /** + * 字段属性对应方法 + */ + public static String IS = "is"; + /** + * 是否增加属性列 + */ + public static String IS_ADD_INDEX = "isAddIndex"; + /** + * 字段属性对应convert方法 + */ + public static String CONVERT = "convert"; + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/ExcelBatchExportServer.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/ExcelBatchExportServer.java new file mode 100644 index 0000000..a054b93 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/ExcelBatchExportServer.java @@ -0,0 +1,200 @@ +package org.jeecgframework.poi.excel.export; +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.streaming.SXSSFWorkbook; +import org.jeecgframework.poi.excel.annotation.ExcelTarget; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.enmus.ExcelType; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.excel.entity.vo.PoiBaseConstants; +import org.jeecgframework.poi.excel.export.styler.IExcelExportStyler; +import org.jeecgframework.poi.exception.excel.ExcelExportException; +import org.jeecgframework.poi.exception.excel.enums.ExcelExportEnum; +import org.jeecgframework.poi.handler.inter.IExcelExportServer; +import org.jeecgframework.poi.handler.inter.IWriter; +import org.jeecgframework.poi.util.PoiExcelGraphDataUtil; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Field; +import java.util.*; + +import static org.jeecgframework.poi.excel.ExcelExportUtil.USE_SXSSF_LIMIT; + +/** + * 提供批次插入服务 + * @author liusq + * @date 2022年1月4日 + */ +public class ExcelBatchExportServer extends ExcelExportServer implements IWriter { + + private final static Logger LOGGER = LoggerFactory.getLogger(ExcelBatchExportServer.class); + + private Workbook workbook; + private Sheet sheet; + private List excelParams; + private ExportParams entity; + private int titleHeight; + private Drawing patriarch; + private short rowHeight; + private int index; + + public void init(ExportParams entity, Class pojoClass) { + List excelParams = createExcelExportEntityList(entity, pojoClass); + init(entity, excelParams); + } + + /** + * 初始化数据 + * @param entity 导出参数 + * @param excelParams + */ + public void init(ExportParams entity, List excelParams) { + LOGGER.debug("ExcelBatchExportServer only support SXSSFWorkbook"); + entity.setType(ExcelType.XSSF); + workbook = new SXSSFWorkbook(); + this.entity = entity; + this.excelParams = excelParams; + super.type = entity.getType(); + createSheet(workbook, entity, excelParams); + if (entity.getMaxNum() == 0) { + entity.setMaxNum(USE_SXSSF_LIMIT); + } + insertDataToSheet(workbook, entity, excelParams, null, sheet); + } + + public List createExcelExportEntityList(ExportParams entity, Class pojoClass) { + try { + List excelParams = new ArrayList(); + if (entity.isAddIndex()) { + excelParams.add(indexExcelEntity(entity)); + } + // 得到所有字段 + Field[] fileds = PoiPublicUtil.getClassFields(pojoClass); + ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); + String targetId = etarget == null ? null : etarget.value(); + getAllExcelField(entity.getExclusions(), targetId, fileds, excelParams, pojoClass, + null); + sortAllParams(excelParams); + + return excelParams; + } catch (Exception e) { + throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e); + } + } + + public void createSheet(Workbook workbook, ExportParams entity, List excelParams) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Excel export start ,List is {}", excelParams); + LOGGER.debug("Excel version is {}", + entity.getType().equals(ExcelType.HSSF) ? "03" : "07"); + } + if (workbook == null || entity == null || excelParams == null) { + throw new ExcelExportException(ExcelExportEnum.PARAMETER_ERROR); + } + try { + try { + sheet = workbook.createSheet(entity.getSheetName()); + } catch (Exception e) { + // 重复遍历,出现了重名现象,创建非指定的名称Sheet + sheet = workbook.createSheet(); + } + } catch (Exception e) { + throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e); + } + } + + @Override + protected void insertDataToSheet(Workbook workbook, ExportParams entity, + List entityList, Collection> dataSet, + Sheet sheet) { + try { + dataHanlder = entity.getDataHanlder(); + if (dataHanlder != null && dataHanlder.getNeedHandlerFields() != null) { + needHanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields()); + } + // 创建表格样式 + setExcelExportStyler((IExcelExportStyler) entity.getStyle() + .getConstructor(Workbook.class).newInstance(workbook)); + patriarch = PoiExcelGraphDataUtil.getDrawingPatriarch(sheet); + List excelParams = new ArrayList(); + if (entity.isAddIndex()) { + excelParams.add(indexExcelEntity(entity)); + } + excelParams.addAll(entityList); + sortAllParams(excelParams); + this.index = entity.isCreateHeadRows() + ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0; + titleHeight = index; + setCellWith(excelParams, sheet); + setColumnHidden(excelParams, sheet); + rowHeight = getRowHeight(excelParams); + setCurrentIndex(1); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause()); + } + } + + public Workbook exportBigExcel(IExcelExportServer server, Object queryParams) { + int page = 1; + List list = server + .selectListForExcelExport(queryParams, page++); + while (list != null && list.size() > 0) { + write(list); + list = server.selectListForExcelExport(queryParams, page++); + } + return close(); + } + + @Override + public Workbook get() { + return this.workbook; + } + + @Override + public IWriter write(Collection data) { + if (sheet.getLastRowNum() + data.size() > entity.getMaxNum()) { + sheet = workbook.createSheet(); + index = 0; + } + Iterator its = data.iterator(); + while (its.hasNext()) { + Object t = its.next(); + try { + index += createCells(patriarch, index, t, excelParams, sheet, workbook, rowHeight, 0)[0]; + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e); + } + } + return this; + } + + @Override + public Workbook close() { + if (entity.getFreezeCol() != 0) { + sheet.createFreezePane(entity.getFreezeCol(), titleHeight, entity.getFreezeCol(), titleHeight); + } + mergeCells(sheet, excelParams, titleHeight); + // 创建合计信息 + addStatisticsRow(getExcelExportStyler().getStyles(true, null), sheet); + return workbook; + } + /** + * 添加Index列 + */ + @Override + public ExcelExportEntity indexExcelEntity(ExportParams entity) { + ExcelExportEntity exportEntity = new ExcelExportEntity(); + //保证是第一排 + exportEntity.setOrderNum(Integer.MIN_VALUE); + exportEntity.setNeedMerge(true); + exportEntity.setName(entity.getIndexName()); + exportEntity.setWidth(10); + exportEntity.setFormat(PoiBaseConstants.IS_ADD_INDEX); + return exportEntity; + } +} \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/ExcelExportServer.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/ExcelExportServer.java new file mode 100644 index 0000000..67abc39 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/ExcelExportServer.java @@ -0,0 +1,454 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export; + +import java.lang.reflect.Field; +import java.util.*; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.jeecgframework.poi.excel.annotation.ExcelTarget; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.enmus.ExcelType; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.excel.entity.vo.PoiBaseConstants; +import org.jeecgframework.poi.excel.export.base.ExcelExportBase; +import org.jeecgframework.poi.excel.export.styler.IExcelExportStyler; +import org.jeecgframework.poi.exception.excel.ExcelExportException; +import org.jeecgframework.poi.exception.excel.enums.ExcelExportEnum; +import org.jeecgframework.poi.util.PoiExcelGraphDataUtil; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Excel导出服务 + * + * @author JEECG + * @date 2014年6月17日 下午5:30:54 + */ +public class ExcelExportServer extends ExcelExportBase { + + private final static Logger LOGGER = LoggerFactory.getLogger(ExcelExportServer.class); + + // 最大行数,超过自动多Sheet + private int MAX_NUM = 60000; + + protected int createHeaderAndTitle(ExportParams entity, Sheet sheet, Workbook workbook, List excelParams) { + int rows = 0, feildWidth = getFieldWidth(excelParams); + if (entity.getTitle() != null) { + rows += createHeaderRow(entity, sheet, workbook, feildWidth); + } + rows += createTitleRow(entity, sheet, workbook, rows, excelParams); + //update-begin---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + if (entity.isFixedTitle()) { + sheet.createFreezePane(0, rows, 0, rows); + } + //update-begin---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + return rows; + } + + /** + * 创建 表头改变 + * + * @param entity + * @param sheet + * @param workbook + * @param feildWidth + */ + public int createHeaderRow(ExportParams entity, Sheet sheet, Workbook workbook, int feildWidth) { + Row row = sheet.createRow(0); + row.setHeight(entity.getTitleHeight()); + createStringCell(row, 0, entity.getTitle(), getExcelExportStyler().getHeaderStyle(entity.getHeaderColor()), null); + for (int i = 1; i <= feildWidth; i++) { + createStringCell(row, i, "", getExcelExportStyler().getHeaderStyle(entity.getHeaderColor()), null); + } + //update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + try { + sheet.addMergedRegion(new CellRangeAddress(0, 0, 0, feildWidth)); + }catch (IllegalArgumentException e){ + LOGGER.error("合并单元格错误日志:"+e.getMessage()); + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + if (entity.getSecondTitle() != null) { + row = sheet.createRow(1); + row.setHeight(entity.getSecondTitleHeight()); + //update-begin-author:liusq date:20230407 for:[issue/4342]autopoi导出带副标题的数据表,副标题缺左边框 + CellStyle style = getExcelExportStyler().getHeaderStyle(entity.getHeaderColor()); + style.setAlignment(HorizontalAlignment.RIGHT); + //update-end-author:liusq date:20230407 for:[issue/4342]autopoi导出带副标题的数据表,副标题缺左边框 + createStringCell(row, 0, entity.getSecondTitle(), style, null); + for (int i = 1; i <= feildWidth; i++) { + createStringCell(row, i, "", getExcelExportStyler().getHeaderStyle(entity.getHeaderColor()), null); + } + //update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + try{ + sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, feildWidth)); + }catch (IllegalArgumentException e){ + LOGGER.error("合并单元格错误日志:"+e.getMessage()); + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + return 2; + } + return 1; + } + + public void createSheet(Workbook workbook, ExportParams entity, Class pojoClass, Collection dataSet, String[] exportFields) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Excel export start ,class is {}", pojoClass); + LOGGER.debug("Excel version is {}", entity.getType().equals(ExcelType.HSSF) ? "03" : "07"); + } + if (workbook == null || entity == null || pojoClass == null || dataSet == null) { + throw new ExcelExportException(ExcelExportEnum.PARAMETER_ERROR); + } + super.type = entity.getType(); + if (type.equals(ExcelType.XSSF)) { + MAX_NUM = 1000000; + } + Sheet sheet = null; + try { + sheet = workbook.createSheet(entity.getSheetName()); + } catch (Exception e) { + // 重复遍历,出现了重名现象,创建非指定的名称Sheet + sheet = workbook.createSheet(); + } + try { + dataHanlder = entity.getDataHanlder(); + if (dataHanlder != null) { + String[] needHandlerFields = dataHanlder.getNeedHandlerFields(); + if(needHandlerFields!=null && needHandlerFields.length>0){ + needHanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields()); + } + } + // 创建表格样式 + setExcelExportStyler((IExcelExportStyler) entity.getStyle().getConstructor(Workbook.class).newInstance(workbook)); + Drawing patriarch = sheet.createDrawingPatriarch(); + List excelParams = new ArrayList(); + if (entity.isAddIndex()) { + excelParams.add(indexExcelEntity(entity)); + } + // 得到所有字段 + Field fileds[] = PoiPublicUtil.getClassFields(pojoClass); + + //---update-begin-----autor:scott------date:20191016-------for:导出字段支持自定义-------- + //支持自定义导出字段 + if (exportFields != null) { + List list = new ArrayList(Arrays.asList(fileds)); + for (int i = 0; i < list.size(); i++) { + if (!Arrays.asList(exportFields).contains(list.get(i).getName())) { + list.remove(i); + i--; + } + } + + if (list != null && list.size() > 0) { + fileds = list.toArray(new Field[0]); + } else { + fileds = null; + } + } + //---update-end-----autor:scott------date:20191016-------for:导出字段支持自定义-------- + + ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); + String targetId = etarget == null ? null : etarget.value(); + getAllExcelField(entity.getExclusions(), targetId, fileds, excelParams, pojoClass, null); + //update-begin-author:taoyan date:20200304 for:在此方法循环内设置一下图片磁盘目录,便于导出 + reConfigExcelExportParams(excelParams,entity); + //update-end-author:taoyan date:20200304 for:在此方法循环内设置一下图片磁盘目录,便于导出 + int index = entity.isCreateHeadRows() ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0; + int titleHeight = index; + setCellWith(excelParams, sheet); + //update-begin-author:liusq date:20210723 for:设置隐藏列 + setColumnHidden(excelParams, sheet); + //update-end-author:liusq date:20210723 for:设置隐藏列 + + short rowHeight = getRowHeight(excelParams); + setCurrentIndex(1); + Iterator its = dataSet.iterator(); + List tempList = new ArrayList(); + while (its.hasNext()) { + Object t = its.next(); + index += createCells(patriarch, index, t, excelParams, sheet, workbook, rowHeight); + tempList.add(t); + if (index >= MAX_NUM) + break; + } + mergeCells(sheet, excelParams, titleHeight); + + if (entity.getFreezeCol() != 0) { + sheet.createFreezePane(entity.getFreezeCol(), 0, entity.getFreezeCol(), 0); + } + + its = dataSet.iterator(); + for (int i = 0, le = tempList.size(); i < le; i++) { + its.next(); + its.remove(); + } + // 创建合计信息 + addStatisticsRow(getExcelExportStyler().getStyles(true, null), sheet); + + // 发现还有剩余list 继续循环创建Sheet + if (dataSet.size() > 0) { + createSheet(workbook, entity, pojoClass, dataSet,exportFields); + } + + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause()); + } + } + + public void createSheetForMap(Workbook workbook, ExportParams entity, List entityList, Collection> dataSet) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Excel version is {}", entity.getType().equals(ExcelType.HSSF) ? "03" : "07"); + } + if (workbook == null || entity == null || entityList == null || dataSet == null) { + throw new ExcelExportException(ExcelExportEnum.PARAMETER_ERROR); + } + super.type = entity.getType(); + if (type.equals(ExcelType.XSSF)) { + MAX_NUM = 1000000; + } + Sheet sheet = null; + try { + sheet = workbook.createSheet(entity.getSheetName()); + } catch (Exception e) { + // 重复遍历,出现了重名现象,创建非指定的名称Sheet + sheet = workbook.createSheet(); + } + try { + dataHanlder = entity.getDataHanlder(); + if (dataHanlder != null) { + needHanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields()); + } + // 创建表格样式 + setExcelExportStyler((IExcelExportStyler) entity.getStyle().getConstructor(Workbook.class).newInstance(workbook)); + Drawing patriarch = sheet.createDrawingPatriarch(); + List excelParams = new ArrayList(); + if (entity.isAddIndex()) { + excelParams.add(indexExcelEntity(entity)); + } + excelParams.addAll(entityList); + sortAllParams(excelParams); + int index = entity.isCreateHeadRows() ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0; + int titleHeight = index; + setCellWith(excelParams, sheet); + //update-begin-author:liusq date:20210723 for:设置隐藏列 + setColumnHidden(excelParams, sheet); + //update-end-author:liusq date:20210723 for:设置隐藏列 + short rowHeight = getRowHeight(excelParams); + setCurrentIndex(1); + Iterator its = dataSet.iterator(); + List tempList = new ArrayList(); + while (its.hasNext()) { + Object t = its.next(); + index += createCells(patriarch, index, t, excelParams, sheet, workbook, rowHeight); + tempList.add(t); + if (index >= MAX_NUM) + break; + } + if (entity.getFreezeCol() != 0) { + sheet.createFreezePane(entity.getFreezeCol(), 0, entity.getFreezeCol(), 0); + } + + mergeCells(sheet, excelParams, titleHeight); + + its = dataSet.iterator(); + for (int i = 0, le = tempList.size(); i < le; i++) { + its.next(); + its.remove(); + } + // 发现还有剩余list 继续循环创建Sheet + if (dataSet.size() > 0) { + createSheetForMap(workbook, entity, entityList, dataSet); + } + + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause()); + } + } + + /** + * 创建表头 + * + * @param title + * @param index + */ + private int createTitleRow(ExportParams title, Sheet sheet, Workbook workbook, int index, List excelParams) { + Row row = sheet.createRow(index); + int rows = getRowNums(excelParams); + row.setHeight((short) 450); + Row listRow = null; + if (rows == 2) { + listRow = sheet.createRow(index + 1); + listRow.setHeight((short) 450); + } + int cellIndex = 0; + CellStyle titleStyle = getExcelExportStyler().getTitleStyle(title.getColor()); + for (int i = 0, exportFieldTitleSize = excelParams.size(); i < exportFieldTitleSize; i++) { + ExcelExportEntity entity = excelParams.get(i); + //update-begin-author:taoyan date:20200319 for:建议autoPoi升级,优化数据返回List Map格式下的复合表头导出excel的体验 #873 + if(entity.isColspan()){ + List subList = entity.getSubColumnList(); + if(subList==null || subList.size()==0){ + continue; + }else{ + entity.initSubExportEntity(excelParams); + } + } + //update-end-author:taoyan date:20200319 for:建议autoPoi升级,优化数据返回List Map格式下的复合表头导出excel的体验 #873 + if (StringUtils.isNotBlank(entity.getName())) { + createStringCell(row, cellIndex, entity.getName(), titleStyle, entity); + } + if (entity.getList() != null) { + List sTitel = entity.getList(); + //update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + if (StringUtils.isNotBlank(entity.getName())) { + try { + sheet.addMergedRegion(new CellRangeAddress(index, index, cellIndex, cellIndex + sTitel.size() - 1)); + }catch (IllegalArgumentException e){ + LOGGER.error("合并单元格错误日志:"+e.getMessage()); + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + } + for (int j = 0, size = sTitel.size(); j < size; j++) { + createStringCell(rows == 2 ? listRow : row, cellIndex, sTitel.get(j).getName(), titleStyle, entity); + cellIndex++; + } + cellIndex--; + } else if (rows == 2) { + createStringCell(listRow, cellIndex, "", titleStyle, entity); + //update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + try{ + sheet.addMergedRegion(new CellRangeAddress(index, index + 1, cellIndex, cellIndex)); + }catch (IllegalArgumentException e){ + LOGGER.error("合并单元格错误日志:"+e.getMessage()); + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + } + cellIndex++; + } + return rows; + + } + + /** + * 判断表头是只有一行还是两行 + * + * @param excelParams + * @return + */ + private int getRowNums(List excelParams) { + for (int i = 0; i < excelParams.size(); i++) { + //update-begin-author:taoyan date:20200319 for:建议autoPoi升级,优化数据返回List Map格式下的复合表头导出excel的体验 #873 + ExcelExportEntity temp = excelParams.get(i); + if ((temp.getList() != null || temp.isColspan()) && StringUtils.isNotBlank(temp.getName())) { + return 2; + } + //update-end-author:taoyan date:20200319 for:建议autoPoi升级,优化数据返回List Map格式下的复合表头导出excel的体验 #873 + } + return 1; + } + + protected ExcelExportEntity indexExcelEntity(ExportParams entity) { + ExcelExportEntity exportEntity = new ExcelExportEntity(); + exportEntity.setOrderNum(0); + exportEntity.setName(entity.getIndexName()); + exportEntity.setWidth(10); + exportEntity.setFormat(PoiBaseConstants.IS_ADD_INDEX); + return exportEntity; + } + //update-begin---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + /** + * 添加数据到sheet + * @param workbook + * @param entity 导出参数 + * @param entityList + * @param dataSet 导出数据 + * @param sheet + * @date 2022年1月4号 + */ + protected void insertDataToSheet(Workbook workbook, ExportParams entity, + List entityList,Collection> dataSet, + Sheet sheet) { + try { + dataHanlder = entity.getDataHanlder(); + if (dataHanlder != null && dataHanlder.getNeedHandlerFields() != null) { + needHanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields()); + } + // 创建表格样式 + setExcelExportStyler((IExcelExportStyler) entity.getStyle() + .getConstructor(Workbook.class).newInstance(workbook)); + Drawing patriarch = PoiExcelGraphDataUtil.getDrawingPatriarch(sheet); + List excelParams = new ArrayList(); + if (entity.isAddIndex()) { + excelParams.add(indexExcelEntity(entity)); + } + excelParams.addAll(entityList); + sortAllParams(excelParams); + int index = entity.isCreateHeadRows() + ? createHeaderAndTitle(entity, sheet, workbook, excelParams) : 0; + int titleHeight = index; + setCellWith(excelParams, sheet); + setColumnHidden(excelParams, sheet); + short rowHeight = entity.getHeight() != 0 ? entity.getHeight() : getRowHeight(excelParams); + setCurrentIndex(1); + Iterator its = dataSet.iterator(); + List tempList = new ArrayList(); + while (its.hasNext()) { + Object t = its.next(); + index += createCells(patriarch, index, t, excelParams, sheet, workbook, rowHeight, 0)[0]; + tempList.add(t); + if (index >= MAX_NUM) { + break; + } + } + if (entity.getFreezeCol() != 0) { + sheet.createFreezePane(entity.getFreezeCol(), 0, entity.getFreezeCol(), 0); + } + + mergeCells(sheet, excelParams, titleHeight); + + its = dataSet.iterator(); + for (int i = 0, le = tempList.size(); i < le; i++) { + its.next(); + its.remove(); + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("List data more than max ,data size is {}", + dataSet.size()); + } + // 发现还有剩余list 继续循环创建Sheet + if (dataSet.size() > 0) { + createSheetForMap(workbook, entity, entityList, dataSet); + } else { + // 创建合计信息 + addStatisticsRow(getExcelExportStyler().getStyles(true, null), sheet); + } + + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e.getCause()); + } + } + //update-end---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/base/ExcelExportBase.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/base/ExcelExportBase.java new file mode 100644 index 0000000..e8f8ba8 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/base/ExcelExportBase.java @@ -0,0 +1,768 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export.base; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.apache.poi.hssf.usermodel.HSSFClientAnchor; +import org.apache.poi.hssf.usermodel.HSSFRichTextString; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.jeecgframework.poi.excel.ExcelImportUtil; +import org.jeecgframework.poi.excel.entity.enmus.ExcelType; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.excel.entity.vo.PoiBaseConstants; +import org.jeecgframework.poi.excel.export.styler.IExcelExportStyler; +import org.jeecgframework.poi.exception.excel.ExcelExportException; +import org.jeecgframework.poi.exception.excel.enums.ExcelExportEnum; +import org.jeecgframework.poi.util.MyX509TrustManager; +import org.jeecgframework.poi.util.PoiMergeCellUtil; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.imageio.ImageIO; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.security.SecureRandom; +import java.text.DecimalFormat; +import java.util.*; + +/** + * 提供POI基础操作服务 + * + * @author JEECG + * @date 2014年6月17日 下午6:15:13 + */ +public abstract class ExcelExportBase extends ExportBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelExportBase.class); + + private int currentIndex = 0; + + protected ExcelType type = ExcelType.HSSF; + + private Map statistics = new HashMap(); + + private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00"); + + //update-begin-author:liusq---date:20220527--for: 修改成protected,列循环时继承类需要用到 --- + protected IExcelExportStyler excelExportStyler; + //update-end-author:liusq---date:20220527--for: 修改成protected,列循环时继承类需要用到 --- + + + /** + * 创建 最主要的 Cells + * + * @param styles + * @param rowHeight + * @throws Exception + */ + public int createCells(Drawing patriarch, int index, Object t, List excelParams, Sheet sheet, Workbook workbook, short rowHeight) throws Exception { + ExcelExportEntity entity; + Row row = sheet.createRow(index); + DataFormat df = workbook.createDataFormat(); + row.setHeight(rowHeight); + int maxHeight = 1, cellNum = 0; + int indexKey = createIndexCell(row, index, excelParams.get(0)); + cellNum += indexKey; + for (int k = indexKey, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + //update-begin-author:taoyan date:20200319 for:建议autoPoi升级,优化数据返回List Map格式下的复合表头导出excel的体验 #873 + if(entity.isSubColumn()){ + continue; + } + if(entity.isMergeColumn()){ + Map subColumnMap = new HashMap<>(); + List mapKeys = entity.getSubColumnList(); + for (String subKey : mapKeys) { + Object subKeyValue = null; + if (t instanceof Map) { + subKeyValue = ((Map) t).get(subKey); + }else{ + subKeyValue = PoiPublicUtil.getParamsValue(subKey,t); + } + subColumnMap.put(subKey,subKeyValue); + } + createListCells(patriarch, index, cellNum, subColumnMap, entity.getList(), sheet, workbook); + cellNum += entity.getSubColumnList().size(); + //update-end-author:taoyan date:20200319 for:建议autoPoi升级,优化数据返回List Map格式下的复合表头导出excel的体验 #873 + } else if (entity.getList() != null) { + Collection list = getListCellValue(entity, t); + int listC = 0; + for (Object obj : list) { + createListCells(patriarch, index + listC, cellNum, obj, entity.getList(), sheet, workbook); + listC++; + } + cellNum += entity.getList().size(); + if (list != null && list.size() > maxHeight) { + maxHeight = list.size(); + } + } else { + Object value = getCellValue(entity, t); + //update-begin--Author:xuelin Date:20171018 for:TASK #2372 【excel】AutoPoi 导出类型,type增加数字类型-------------------- + if (entity.getType() == 1) { + createStringCell(row, cellNum++, value == null ? "" : value.toString(), index % 2 == 0 ? getStyles(false, entity) : getStyles(true, entity), entity); + } else if (entity.getType() == 4){ + createNumericCell(row, cellNum++, value == null ? "" : value.toString(), getNumberCellStyle(index, df, entity), entity); + } else { + createImageCell(patriarch, entity, row, cellNum++, value == null ? "" : value.toString(), t); + } + //update-end--Author:xuelin Date:20171018 for:TASK #2372 【excel】AutoPoi 导出类型,type增加数字类型-------------------- + + //update-begin-author:liusq---date:20220728--for:[issues/I5I840] @Excel注解中不支持超链接,但文档中支持 --- + if (entity.isHyperlink()) { + row.getCell(cellNum - 1) + .setHyperlink(dataHanlder.getHyperlink( + row.getSheet().getWorkbook().getCreationHelper(), t, + entity.getName(), value)); + } + //update-end-author:liusq---date:20220728--for:[issues/I5I840] @Excel注解中不支持超链接,但文档中支持 --- + } + } + // 合并需要合并的单元格 + cellNum = 0; + for (int k = indexKey, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + if (entity.getList() != null) { + cellNum += entity.getList().size(); + } else if (entity.isNeedMerge()) { + for (int i = index + 1; i < index + maxHeight; i++) { + sheet.getRow(i).createCell(cellNum); + sheet.getRow(i).getCell(cellNum).setCellStyle(getStyles(false, entity)); + } + //update-begin-author:wangshuai date:20201116 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + try { + if (maxHeight > 1) { + sheet.addMergedRegion(new CellRangeAddress(index, index + maxHeight - 1, cellNum, cellNum)); + } + }catch (IllegalArgumentException e){ + LOGGER.error("合并单元格错误日志:"+e.getMessage()); + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201116 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + cellNum++; + } + } + return maxHeight; + + } + + /** + * 获取数值单元格样式 + * @param index + * @param df + * @param entity + * @return + */ + private CellStyle getNumberCellStyle(int index,DataFormat df, ExcelExportEntity entity) { + //update-begin-author:liusq---date:2023-12-07--for: [issues/5538]导出表格设置了数字格式导出之后仍然是文本格式,并且无法进行计算 + CellStyle cellStyle = index % 2 == 0 ? getStyles(false, entity) : getStyles(true, entity); + String numFormat = StringUtils.isNotBlank(entity.getNumFormat())? entity.getNumFormat():"0.00_ "; + cellStyle.setDataFormat(df.getFormat(numFormat)); + return cellStyle; + //update-end-author:liusq---date:2023-12-07--for:[issues/5538]导出表格设置了数字格式导出之后仍然是文本格式,并且无法进行计算 + } + /** + * 通过https地址获取图片数据 + * @param imagePath + * @return + * @throws Exception + */ + private byte[] getImageDataByHttps(String imagePath) throws Exception { + SSLContext sslcontext = SSLContext.getInstance("SSL","SunJSSE"); + sslcontext.init(null, new TrustManager[]{new MyX509TrustManager()}, new SecureRandom()); + URL url = new URL(imagePath); + HttpsURLConnection conn = (HttpsURLConnection) url.openConnection(); + conn.setSSLSocketFactory(sslcontext.getSocketFactory()); + conn.setRequestMethod("GET"); + conn.setConnectTimeout(5 * 1000); + InputStream inStream = conn.getInputStream(); + byte[] value = readInputStream(inStream); + return value; + } + + /** + * 通过http地址获取图片数据 + * @param imagePath + * @return + * @throws Exception + */ + private byte[] getImageDataByHttp(String imagePath) throws Exception { + URL url = new URL(imagePath); + HttpURLConnection conn = (HttpURLConnection) url.openConnection(); + conn.setRequestMethod("GET"); + conn.setConnectTimeout(5 * 1000); + InputStream inStream = conn.getInputStream(); + byte[] value = readInputStream(inStream); + return value; + } + + /** + * 图片类型的Cell + * + * @param patriarch + * @param entity + * @param row + * @param i + * @param imagePath + * @param obj + * @throws Exception + */ + public void createImageCell(Drawing patriarch, ExcelExportEntity entity, Row row, int i, String imagePath, Object obj) throws Exception { + row.setHeight((short) (50 * entity.getHeight())); + row.createCell(i); + ClientAnchor anchor; + if (type.equals(ExcelType.HSSF)) { + anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) i, row.getRowNum(), (short) (i + 1), row.getRowNum() + 1); + } else { + anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) i, row.getRowNum(), (short) (i + 1), row.getRowNum() + 1); + } + + if (StringUtils.isEmpty(imagePath)) { + return; + } + + //update-beign-author:taoyan date:20200302 for:【多任务】online 专项集中问题 LOWCOD-159 + int imageType = entity.getExportImageType(); + byte[] value = null; + if(imageType == 2){ + //原来逻辑 2 + value = (byte[]) (entity.getMethods() != null ? getFieldBySomeMethod(entity.getMethods(), obj) : entity.getMethod().invoke(obj, new Object[] {})); + } else if(imageType==4 || imagePath.startsWith("http")){ + //新增逻辑 网络图片4 + try { + if (imagePath.indexOf(",") != -1) { + if(imagePath.startsWith(",")){ + imagePath = imagePath.substring(1); + } + String[] images = imagePath.split(","); + imagePath = images[0]; + } + if(imagePath.startsWith("https")){ + value = getImageDataByHttps(imagePath); + }else{ + value = getImageDataByHttp(imagePath); + } + } catch (Exception exception) { + LOGGER.warn(exception.getMessage()); + //exception.printStackTrace(); + } + } else { + ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); + BufferedImage bufferImg; + String path = null; + if(imageType == 1){ + //原来逻辑 1 + path = PoiPublicUtil.getWebRootPath(imagePath); + LOGGER.debug("--- createImageCell getWebRootPath ----filePath--- "+ path); + path = path.replace("WEB-INF/classes/", ""); + path = path.replace("file:/", ""); + }else if(imageType==3){ + //新增逻辑 本地图片3 + //begin-------author:liusq---data:2021-01-27----for:本地图片ImageBasePath为空报错的问题 + if(StringUtils.isNotBlank(entity.getImageBasePath())){ + if(!entity.getImageBasePath().endsWith(File.separator) && !imagePath.startsWith(File.separator)){ + path = entity.getImageBasePath()+File.separator+imagePath; + }else{ + path = entity.getImageBasePath()+imagePath; + } + }else{ + path = imagePath; + } + //end-------author:liusq---data:2021-01-27----for:本地图片ImageBasePath为空报错的问题 + } + try { + bufferImg = ImageIO.read(new File(path)); + //update-begin-author:taoYan date:20211203 for: Excel 导出图片的文件带小数点符号 导出报错 https://gitee.com/jeecg/jeecg-boot/issues/I4JNHR + ImageIO.write(bufferImg, imagePath.substring(imagePath.lastIndexOf(".") + 1, imagePath.length()), byteArrayOut); + //update-end-author:taoYan date:20211203 for: Excel 导出图片的文件带小数点符号 导出报错 https://gitee.com/jeecg/jeecg-boot/issues/I4JNHR + value = byteArrayOut.toByteArray(); + } catch (Exception e) { + LOGGER.error(e.getMessage()); + } + } + if (value != null) { + patriarch.createPicture(anchor, row.getSheet().getWorkbook().addPicture(value, getImageType(value))); + } + //update-end-author:taoyan date:20200302 for:【多任务】online 专项集中问题 LOWCOD-159 + + + } + + /** + * inStream读取到字节数组 + * @param inStream + * @return + * @throws Exception + */ + private byte[] readInputStream(InputStream inStream) throws Exception { + if(inStream==null){ + return null; + } + ByteArrayOutputStream outStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len = 0; + //每次读取的字符串长度,如果为-1,代表全部读取完毕 + while ((len = inStream.read(buffer)) != -1) { + outStream.write(buffer, 0, len); + } + inStream.close(); + return outStream.toByteArray(); + } + + private int createIndexCell(Row row, int index, ExcelExportEntity excelExportEntity) { + if (excelExportEntity.getName().equals("序号") && PoiBaseConstants.IS_ADD_INDEX.equals(excelExportEntity.getFormat())) { + createStringCell(row, 0, currentIndex + "", index % 2 == 0 ? getStyles(false, null) : getStyles(true, null), null); + currentIndex = currentIndex + 1; + return 1; + } + return 0; + } + + /** + * 创建List之后的各个Cells + * @param patriarch + * @param index + * @param cellNum + * @param obj + * @param excelParams + * @param sheet + * @param workbook + * @throws Exception + */ + public void createListCells(Drawing patriarch, int index, int cellNum, Object obj, List excelParams, Sheet sheet, Workbook workbook) throws Exception { + ExcelExportEntity entity; + Row row; + DataFormat df = workbook.createDataFormat(); + if (sheet.getRow(index) == null) { + row = sheet.createRow(index); + row.setHeight(getRowHeight(excelParams)); + } else { + row = sheet.getRow(index); + } + for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + Object value = getCellValue(entity, obj); + //update-begin--Author:xuelin Date:20171018 for:TASK #2372 【excel】AutoPoi 导出类型,type增加数字类型-------------------- + if (entity.getType() == 1) { + createStringCell(row, cellNum++, value == null ? "" : value.toString(), row.getRowNum() % 2 == 0 ? getStyles(false, entity) : getStyles(true, entity), entity); + //update-begin-author:liusq---date:20220728--for: 新增isHyperlink属性 --- + if (entity.isHyperlink()) { + row.getCell(cellNum - 1) + .setHyperlink(dataHanlder.getHyperlink( + row.getSheet().getWorkbook().getCreationHelper(), obj, entity.getName(), + value)); + } + //update-end-author:liusq---date:20220728--for: 新增isHyperlink属性 --- + } else if (entity.getType() == 4){ + createNumericCell(row, cellNum++, value == null ? "" : value.toString(), getNumberCellStyle(index, df, entity), entity); + //update-begin-author:liusq---date:20220728--for: 新增isHyperlink属性 --- + if (entity.isHyperlink()) { + row.getCell(cellNum - 1) + .setHyperlink(dataHanlder.getHyperlink( + row.getSheet().getWorkbook().getCreationHelper(), obj, entity.getName(), + value)); + } + //update-end-author:liusq---date:20220728--for: 新增isHyperlink属性 --- + } else{ + createImageCell(patriarch, entity, row, cellNum++, value == null ? "" : value.toString(), obj); + } + //update-end--Author:xuelin Date:20171018 for:TASK #2372 【excel】AutoPoi 导出类型,type增加数字类型-------------------- + } + } + + //update-begin--Author:xuelin Date:20171018 for:TASK #2372 【excel】AutoPoi 导出类型,type增加数字类型-------------------- + public void createNumericCell (Row row, int index, String text, CellStyle style, ExcelExportEntity entity) { + Cell cell = row.createCell(index); + if (style != null) { + cell.setCellStyle(style); + } + if(StringUtils.isEmpty(text)){ + cell.setCellValue(""); + cell.setCellType(CellType.BLANK); + }else{ + cell.setCellValue(Double.parseDouble(text)); + cell.setCellType(CellType.NUMERIC); + } + addStatisticsData(index, text, entity); + } + + /** + * 创建文本类型的Cell + * + * @param row + * @param index + * @param text + * @param style + * @param entity + */ + public void createStringCell(Row row, int index, String text, CellStyle style, ExcelExportEntity entity) { + Cell cell = row.createCell(index); + if (style != null && style.getDataFormat() > 0 && style.getDataFormat() < 12) { + cell.setCellValue(Double.parseDouble(text)); + cell.setCellType(CellType.NUMERIC); + }else{ + RichTextString Rtext; + if (type.equals(ExcelType.HSSF)) { + Rtext = new HSSFRichTextString(text); + } else { + Rtext = new XSSFRichTextString(text); + } + cell.setCellValue(Rtext); + } + if (style != null) { + cell.setCellStyle(style); + } + addStatisticsData(index, text, entity); + } + + /** + * 设置字段下划线 + * @param row + * @param index + * @param text + * @param style + * @param entity + * @param workbook + */ + /*public void createStringCell(Row row, int index, String text, CellStyle style, ExcelExportEntity entity, Workbook workbook) { + Cell cell = row.createCell(index); + if (style != null && style.getDataFormat() > 0 && style.getDataFormat() < 12) { + cell.setCellValue(Double.parseDouble(text)); + cell.setCellType(CellType.NUMERIC); + }else{ + RichTextString Rtext; + if (type.equals(ExcelType.HSSF)) { + Rtext = new HSSFRichTextString(text); + } else { + Rtext = new XSSFRichTextString(text); + } + cell.setCellValue(Rtext); + } + if (style != null) { + Font font = workbook.createFont(); + font.setUnderline(Font.U_SINGLE); + style.setFont(font); + cell.setCellStyle(style); + } + addStatisticsData(index, text, entity); + }*/ + //update-end--Author:xuelin Date:20171018 for:TASK #2372 【excel】AutoPoi 导出类型,type增加数字类型---------------------- + + /** + * 创建统计行 + * + * @param styles + * @param sheet + */ + public void addStatisticsRow(CellStyle styles, Sheet sheet) { + if (statistics.size() > 0) { + Row row = sheet.createRow(sheet.getLastRowNum() + 1); + Set keys = statistics.keySet(); + createStringCell(row, 0, "合计", styles, null); + for (Integer key : keys) { + createStringCell(row, key, DOUBLE_FORMAT.format(statistics.get(key)), styles, null); + } + statistics.clear(); + } + + } + + /** + * 合计统计信息 + * + * @param index + * @param text + * @param entity + */ + private void addStatisticsData(Integer index, String text, ExcelExportEntity entity) { + if (entity != null && entity.isStatistics()) { + Double temp = 0D; + if (!statistics.containsKey(index)) { + statistics.put(index, temp); + } + try { + temp = Double.valueOf(text); + } catch (NumberFormatException e) { + } + statistics.put(index, statistics.get(index) + temp); + } + } + + /** + * 获取导出报表的字段总长度 + * + * @param excelParams + * @return + */ + public int getFieldWidth(List excelParams) { + int length = -1;// 从0开始计算单元格的 + for (ExcelExportEntity entity : excelParams) { + //update-begin---author:liusq Date:20200909 for:AutoPoi多表头导出,会多出一列空白列 #1513------------ + if(entity.getGroupName()!=null){ + continue; + }else if (entity.getSubColumnList()!=null&&entity.getSubColumnList().size()>0){ + length += entity.getSubColumnList().size(); + }else{ + length += entity.getList() != null ? entity.getList().size() : 1; + } + //update-end---author:liusq Date:20200909 for:AutoPoi多表头导出,会多出一列空白列 #1513------------ + } + return length; + } + + /** + * 获取图片类型,设置图片插入类型 + * + * @param value + * @return + * @Author JEECG + * @date 2013年11月25日 + */ + public int getImageType(byte[] value) { + String type = PoiPublicUtil.getFileExtendName(value); + if (type.equalsIgnoreCase("JPG")) { + return Workbook.PICTURE_TYPE_JPEG; + } else if (type.equalsIgnoreCase("PNG")) { + return Workbook.PICTURE_TYPE_PNG; + } + return Workbook.PICTURE_TYPE_JPEG; + } + + private Map getMergeDataMap(List excelParams) { + Map mergeMap = new HashMap(); + // 设置参数顺序,为之后合并单元格做准备 + int i = 0; + for (ExcelExportEntity entity : excelParams) { + if (entity.isMergeVertical()) { + mergeMap.put(i, entity.getMergeRely()); + } + if (entity.getList() != null) { + for (ExcelExportEntity inner : entity.getList()) { + if (inner.isMergeVertical()) { + mergeMap.put(i, inner.getMergeRely()); + } + i++; + } + } else { + i++; + } + } + return mergeMap; + } + + /** + * 获取样式 + * + * @param entity + * @param needOne + * @return + */ + public CellStyle getStyles(boolean needOne, ExcelExportEntity entity) { + return excelExportStyler.getStyles(needOne, entity); + } + + /** + * 合并单元格 + * + * @param sheet + * @param excelParams + * @param titleHeight + */ + public void mergeCells(Sheet sheet, List excelParams, int titleHeight) { + Map mergeMap = getMergeDataMap(excelParams); + PoiMergeCellUtil.mergeCells(sheet, mergeMap, titleHeight); + } + + public void setCellWith(List excelParams, Sheet sheet) { + int index = 0; + for (int i = 0; i < excelParams.size(); i++) { + if (excelParams.get(i).getList() != null) { + List list = excelParams.get(i).getList(); + for (int j = 0; j < list.size(); j++) { + sheet.setColumnWidth(index, (int) (256 * list.get(j).getWidth())); + index++; + } + } else { + sheet.setColumnWidth(index, (int) (256 * excelParams.get(i).getWidth())); + index++; + } + } + } + + /** + * 设置隐藏列 + * @param excelParams + * @param sheet + */ + public void setColumnHidden(List excelParams, Sheet sheet) { + int index = 0; + for (int i = 0; i < excelParams.size(); i++) { + if (excelParams.get(i).getList() != null) { + List list = excelParams.get(i).getList(); + for (int j = 0; j < list.size(); j++) { + sheet.setColumnHidden(index, list.get(j).isColumnHidden()); + index++; + } + } else { + sheet.setColumnHidden(index, excelParams.get(i).isColumnHidden()); + index++; + } + } + } + public void setCurrentIndex(int currentIndex) { + this.currentIndex = currentIndex; + } + + public void setExcelExportStyler(IExcelExportStyler excelExportStyler) { + this.excelExportStyler = excelExportStyler; + } + + public IExcelExportStyler getExcelExportStyler() { + return excelExportStyler; + } + //update-begin---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + /** + *创建单元格,返回最大高度和单元格数 + * @param patriarch + * @param index + * @param t + * @param excelParams + * @param sheet + * @param workbook + * @param rowHeight 行高 + * @param cellNum 格数 + * @return + */ + public int[] createCells(Drawing patriarch, int index, Object t, + List excelParams, Sheet sheet, Workbook workbook, + short rowHeight, int cellNum) { + try { + ExcelExportEntity entity; + Row row = sheet.getRow(index) == null ? sheet.createRow(index) : sheet.getRow(index); + DataFormat df = workbook.createDataFormat(); + if (rowHeight != -1) { + row.setHeight(rowHeight); + } + int maxHeight = 1, listMaxHeight = 1; + // 合并需要合并的单元格 + int margeCellNum = cellNum; + int indexKey = 0; + if (excelParams != null && !excelParams.isEmpty()) { + indexKey = createIndexCell(row, index, excelParams.get(0)); + } + cellNum += indexKey; + for (int k = indexKey, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + //不论数据是否为空都应该把该列的数据跳过去 + if (entity.getList() != null) { + Collection list = getListCellValue(entity, t); + int tmpListHeight = 0; + if (list != null && list.size() > 0) { + int tempCellNum = 0; + for (Object obj : list) { + int[] temp = createCells(patriarch, index + tmpListHeight, obj, entity.getList(), sheet, workbook, rowHeight, cellNum); + tempCellNum = temp[1]; + tmpListHeight += temp[0]; + } + cellNum = tempCellNum; + listMaxHeight = Math.max(listMaxHeight, tmpListHeight); + } else { + cellNum = cellNum + getListCellSize(entity.getList()); + } + } else { + Object value = getCellValue(entity, t); + if (entity.getType() == 1) { + createStringCell(row, cellNum++, value == null ? "" : value.toString(), + index % 2 == 0 ? getStyles(false, entity) : getStyles(true, entity), + entity); + + } else if (entity.getType() == 4) { + createNumericCell(row, cellNum++, value == null ? "" : value.toString(), + getNumberCellStyle(index, df, entity), + entity); + } else { + createImageCell(patriarch, entity, row, cellNum++, + value == null ? "" : value.toString(), t); + } + //update-begin-author:liusq---date:20220728--for: 新增isHyperlink属性 --- + if (entity.isHyperlink()) { + row.getCell(cellNum - 1) + .setHyperlink(dataHanlder.getHyperlink( + row.getSheet().getWorkbook().getCreationHelper(), t, + entity.getName(), value)); + } + //update-end-author:liusq---date:20220728--for: 新增isHyperlink属性 --- + } + } + maxHeight += listMaxHeight - 1; + if (indexKey == 1 && excelParams.get(1).isNeedMerge()) { + excelParams.get(0).setNeedMerge(true); + } + for (int k = indexKey, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + if (entity.getList() != null) { + margeCellNum += entity.getList().size(); + } else if (entity.isNeedMerge() && maxHeight > 1) { + for (int i = index + 1; i < index + maxHeight; i++) { + if (sheet.getRow(i) == null) { + sheet.createRow(i); + } + sheet.getRow(i).createCell(margeCellNum); + sheet.getRow(i).getCell(margeCellNum).setCellStyle(getStyles(false, entity)); + } + PoiMergeCellUtil.addMergedRegion(sheet, index, index + maxHeight - 1, margeCellNum, margeCellNum); + margeCellNum++; + } + } + return new int[]{maxHeight, cellNum}; + } catch (Exception e) { + LOGGER.error("excel cell export error ,data is :{}", ReflectionToStringBuilder.toString(t)); + LOGGER.error(e.getMessage(), e); + throw new ExcelExportException(ExcelExportEnum.EXPORT_ERROR, e); + } + } + + /** + * 获取集合的宽度 + * + * @param list + * @return + */ + protected int getListCellSize(List list) { + int cellSize = 0; + for (ExcelExportEntity ee : list) { + if (ee.getList() != null) { + cellSize += getListCellSize(ee.getList()); + } else { + cellSize++; + } + } + return cellSize; + } + //update-end---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/base/ExportBase.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/base/ExportBase.java new file mode 100644 index 0000000..5c3bba7 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/base/ExportBase.java @@ -0,0 +1,552 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export.base; + +import org.apache.commons.lang3.StringUtils; +import org.jeecgframework.core.util.ApplicationContextUtil; +import org.jeecgframework.dict.service.AutoPoiDictServiceI; +import org.jeecgframework.poi.excel.annotation.*; +import org.jeecgframework.poi.excel.entity.ExportParams; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.handler.inter.IExcelDataHandler; +import org.jeecgframework.poi.handler.inter.IExcelDictHandler; +import org.jeecgframework.poi.util.PoiPublicUtil; + +import java.lang.reflect.*; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; + +/** + * 导出基础处理,不设计POI,只设计对象,保证复用性 + * + * @author JEECG + * @date 2014年8月9日 下午11:01:32 + */ +public class ExportBase { + + protected IExcelDataHandler dataHanlder; + + //update-begin-author:liusq---date:20220527--for: 增加列循环功能时中用到 --- + protected IExcelDictHandler dictHandler; + //update-end-author:liusq---date:20220527--for: be 增加列循环功能时中用到--- + + protected List needHanlderList; + + /** + * 创建导出实体对象 + * + * @param field + * @param targetId + * @param pojoClass + * @param getMethods + * @return + * @throws Exception + */ + private ExcelExportEntity createExcelExportEntity(Field field, String targetId, Class pojoClass, List getMethods) + throws Exception { + Excel excel = field.getAnnotation(Excel.class); + ExcelExportEntity excelEntity = new ExcelExportEntity(); + excelEntity.setType(excel.type()); + getExcelField(targetId, field, excelEntity, excel, pojoClass); + if (getMethods != null) { + List newMethods = new ArrayList(); + newMethods.addAll(getMethods); + newMethods.add(excelEntity.getMethod()); + excelEntity.setMethods(newMethods); + } + return excelEntity; + } + + private Object formatValue(Object value, ExcelExportEntity entity) throws Exception { + Date temp = null; + //update-begin-author:wangshuai date:20201118 for:Excel导出错误原因,value为""字符串,gitee I249JF + if ("".equals(value)) { + value = null; + } + //update-begin-author:wangshuai date:20201118 for:Excel导出错误原因,value为""字符串,gitee I249JF + if (value instanceof String && entity.getDatabaseFormat() != null) { + SimpleDateFormat format = new SimpleDateFormat(entity.getDatabaseFormat()); + temp = format.parse(value.toString()); + } else if (value instanceof Date) { + temp = (Date) value; + //update-begin-author:taoyan date:2022-5-17 for: mybatis-plus升级 时间字段变成了jdk8的LocalDateTime,导致格式化失败 + } else if (value instanceof LocalDateTime) { + LocalDateTime ldt = (LocalDateTime) value; + DateTimeFormatter format = DateTimeFormatter.ofPattern(entity.getFormat()); + return format.format(ldt); + } else if (value instanceof LocalDate) { + LocalDate ld = (LocalDate) value; + DateTimeFormatter format = DateTimeFormatter.ofPattern(entity.getFormat()); + return format.format(ld); + } + //update-end-author:taoyan date:2022-5-17 for: mybatis-plus升级 时间字段变成了jdk8的LocalDateTime,导致格式化失败 + if (temp != null) { + SimpleDateFormat format = new SimpleDateFormat(entity.getFormat()); + value = format.format(temp); + } + return value; + } + + /** + * 获取需要导出的全部字段 + * + * @param exclusions + * @param targetId + * 目标ID + * @param fields + * @throws Exception + */ + public void getAllExcelField(String[] exclusions, String targetId, Field[] fields, List excelParams, + Class pojoClass, List getMethods) throws Exception { + List exclusionsList = exclusions != null ? Arrays.asList(exclusions) : null; + ExcelExportEntity excelEntity; + // 遍历整个filed + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + // 先判断是不是collection,在判断是不是java自带对象,之后就是我们自己的对象了 + if (PoiPublicUtil.isNotUserExcelUserThis(exclusionsList, field, targetId)) { + continue; + } + // 首先判断Excel 可能一下特殊数据用户回自定义处理 + if (field.getAnnotation(Excel.class) != null) { + excelParams.add(createExcelExportEntity(field, targetId, pojoClass, getMethods)); + } else if (PoiPublicUtil.isCollection(field.getType())) { + ExcelCollection excel = field.getAnnotation(ExcelCollection.class); + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class clz = (Class) pt.getActualTypeArguments()[0]; + List list = new ArrayList(); + getAllExcelField(exclusions, StringUtils.isNotEmpty(excel.id()) ? excel.id() : targetId, PoiPublicUtil.getClassFields(clz), + list, clz, null); + excelEntity = new ExcelExportEntity(); + excelEntity.setName(getExcelName(excel.name(), targetId)); + excelEntity.setOrderNum(getCellOrder(excel.orderNum(), targetId)); + excelEntity.setMethod(PoiPublicUtil.getMethod(field.getName(), pojoClass)); + excelEntity.setList(list); + excelParams.add(excelEntity); + } else { + List newMethods = new ArrayList(); + if (getMethods != null) { + newMethods.addAll(getMethods); + } + newMethods.add(PoiPublicUtil.getMethod(field.getName(), pojoClass)); + ExcelEntity excel = field.getAnnotation(ExcelEntity.class); + //update-begin-author:taoyan date:20210531 for:excel导出支持 注解@ExcelEntity显示合并表头 + if (excel.show() == true) { + List list = new ArrayList(); + // 这里有个设计的坑,导出的时候最后一个参数是null, 即getgetMethods获取的是空,导入的时候需要设置层级getmethod + getAllExcelField(exclusions, StringUtils.isNotEmpty(excel.id()) ? excel.id() : targetId, + PoiPublicUtil.getClassFields(field.getType()), list, field.getType(), null); + excelEntity = new ExcelExportEntity(); + excelEntity.setName(getExcelName(excel.name(), targetId)); + excelEntity.setMethod(PoiPublicUtil.getMethod(field.getName(), pojoClass)); + excelEntity.setList(list); + excelParams.add(excelEntity); + } else { + getAllExcelField(exclusions, StringUtils.isNotEmpty(excel.id()) ? excel.id() : targetId, + PoiPublicUtil.getClassFields(field.getType()), excelParams, field.getType(), newMethods); + } + //update-end-author:taoyan date:20210531 for:excel导出支持 注解@ExcelEntity显示合并表头 + } + } + } + + /** + * 获取这个字段的顺序 + * + * @param orderNum + * @param targetId + * @return + */ + public int getCellOrder(String orderNum, String targetId) { + if (isInteger(orderNum) || targetId == null) { + return Integer.valueOf(orderNum); + } + String[] arr = orderNum.split(","); + String[] temp; + for (String str : arr) { + temp = str.split("_"); + if (targetId.equals(temp[1])) { + return Integer.valueOf(temp[0]); + } + } + return 0; + } + + /** + * 获取填如这个cell的值,提供一些附加功能 + * + * @param entity + * @param obj + * @return + * @throws Exception + */ + public Object getCellValue(ExcelExportEntity entity, Object obj) throws Exception { + if (Objects.isNull(obj)) { + return ""; + } + Object value; + if (obj instanceof Map) { + value = ((Map) obj).get(entity.getKey()); + } else { + value = entity.getMethods() != null ? getFieldBySomeMethod(entity.getMethods(), obj) : entity.getMethod().invoke(obj, + new Object[] {}); + } + + //update-begin-author:scott date:20200831 for:导出excel实体反射,时间格式转换错误 #1573 + value = Optional.ofNullable(value).orElse(""); + if (StringUtils.isEmpty(value.toString())) { + return ""; + } + //update-end-author:scott date:20200831 for:导出excel实体反射,时间格式转换错误 #1573 + + //update-begin-author:taoyan date:2020319 for:Excel注解的numFormat方法似乎未实现 #970 + if (StringUtils.isNotEmpty(entity.getNumFormat()) && value != null) { + value = new DecimalFormat(entity.getNumFormat()).format(value); + } + //update-end-author:taoyan date:2020319 for:Excel注解的numFormat方法似乎未实现 #970 + + if (StringUtils.isNotEmpty(entity.getDict()) && dictHandler != null) { + value = dictHandler.toName(entity.getDict(), obj, entity.getName(), value); + } + if (StringUtils.isNotEmpty(entity.getFormat())) { + value = formatValue(value, entity); + } + if (entity.getReplace() != null && entity.getReplace().length > 0) { + //update-begin-author:taoyan date:20180731 for:TASK #3038 【bug】Excel 导出多个值(逗号隔开的情况下,导出字典值是ID值) + if (value == null) { + value = "";//String.valueOf(value) 如果value为null 则返回"null" + } + String oldVal = value.toString(); + if (entity.isMultiReplace()) { + value = multiReplaceValue(entity.getReplace(), String.valueOf(value)); + } else { + value = replaceValue(entity.getReplace(), String.valueOf(value)); + } + //update-end-author:taoyan date:20180731 for:TASK #3038 【bug】Excel 导出多个值(逗号隔开的情况下,导出字典值是ID值) + + //update-begin-author:liusq date:20210127 for: 两个数值相等,就证明处理翻译失败的情况 + if (oldVal.equals(value)) { + + } + //update-end-author:liusq date:20210127 for: 两个数值相等,就证明处理翻译失败的情况 + } + if (needHanlderList != null && needHanlderList.contains(entity.getName())) { + value = dataHanlder.exportHandler(obj, entity.getName(), value); + } + if (StringUtils.isNotEmpty(entity.getSuffix()) && value != null) { + value = value + entity.getSuffix(); + } + return value == null ? "" : value.toString(); + } + + /** + * 获取集合的值 + * + * @param entity + * @param obj + * @return + * @throws Exception + */ + public Collection getListCellValue(ExcelExportEntity entity, Object obj) throws Exception { + Object value; + if (obj instanceof Map) { + value = ((Map) obj).get(entity.getKey()); + } else { + value = entity.getMethod().invoke(obj, new Object[] {}); + if (value instanceof Collection) { + return (Collection) value; + } else { + List list = new ArrayList(); + list.add(value); + return list; + } + } + return (Collection) value; + } + + /** + * 注解到导出对象的转换 + * + * @param targetId + * @param field + * @param excelEntity + * @param excel + * @param pojoClass + * @throws Exception + */ + private void getExcelField(String targetId, Field field, ExcelExportEntity excelEntity, Excel excel, Class pojoClass) + throws Exception { + excelEntity.setName(getExcelName(excel.name(), targetId)); + excelEntity.setWidth(excel.width()); + excelEntity.setHeight(excel.height()); + excelEntity.setNeedMerge(excel.needMerge()); + excelEntity.setMergeVertical(excel.mergeVertical()); + excelEntity.setMergeRely(excel.mergeRely()); + excelEntity.setReplace(excel.replace()); + excelEntity.setHyperlink(excel.isHyperlink()); + if (StringUtils.isNotEmpty(excel.dicCode())) { + AutoPoiDictServiceI jeecgDictService = null; + try { + jeecgDictService = ApplicationContextUtil.getContext().getBean(AutoPoiDictServiceI.class); + } catch (Exception e) { + } + if (jeecgDictService != null) { + String[] dictReplace = jeecgDictService.queryDict(excel.dictTable(), excel.dicCode(), excel.dicText()); + if (excelEntity.getReplace() != null && dictReplace != null && dictReplace.length != 0) { + excelEntity.setReplace(dictReplace); + } + } + } + excelEntity.setOrderNum(getCellOrder(excel.orderNum(), targetId)); + excelEntity.setWrap(excel.isWrap()); + excelEntity.setExportImageType(excel.imageType()); + excelEntity.setSuffix(excel.suffix()); + excelEntity.setDatabaseFormat(excel.databaseFormat()); + excelEntity.setFormat(StringUtils.isNotEmpty(excel.exportFormat()) ? excel.exportFormat() : excel.format()); + excelEntity.setStatistics(excel.isStatistics()); + String fieldname = field.getName(); + //update-begin-author:taoyan date:20200319 for:autopoi 双表头问题 #862 基于注解的解决方案 + excelEntity.setKey(fieldname); + //update-end-author:taoyan date:20200319 for:autopoi 双表头问题 #862 基于注解的解决方案 + //update-begin-author:taoyan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + excelEntity.setNumFormat(excel.numFormat()); + //update-end-author:taoyan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + + //update-begin-author:liusq date:202010723 for:Excel注解的isColumnHidden方法未实现 + excelEntity.setColumnHidden(excel.isColumnHidden()); + //update-end-author:liusq date:202010723 for:Excel注解的isColumnHidden方法未实现 + + //update-begin-author:taoyan date:20180615 for:TASK #2798 【例子】导入扩展方法,支持自定义导入字段转换规则 + excelEntity.setMethod(PoiPublicUtil.getMethod(fieldname, pojoClass, excel.exportConvert())); + //update-end-author:taoyan date:20180615 for:TASK #2798 【例子】导入扩展方法,支持自定义导入字段转换规则 + //update-begin-author:taoyan date:20180801 for:TASK #3038 【bug】Excel 导出多个值(逗号隔开的情况下,导出字典值是ID值) + excelEntity.setMultiReplace(excel.multiReplace()); + //update-end-author:taoyan date:20180801 for:TASK #3038 【bug】Excel 导出多个值(逗号隔开的情况下,导出字典值是ID值) + //update-begin-author:taoyan date:20200319 for:autopoi 双表头问题 #862 基于实体注解的解决方案 + if (StringUtils.isNotEmpty(excel.groupName())) { + excelEntity.setGroupName(excel.groupName()); + excelEntity.setColspan(true); + } + //update-end-author:taoyan date:20200319 for:autopoi 双表头问题 #862 基于实体注解的解决方案 + } + + /** + * 判断在这个单元格显示的名称 + * + * @param exportName + * @param targetId + * @return + */ + public String getExcelName(String exportName, String targetId) { + if (exportName.indexOf(",") < 0 || targetId == null) { + return exportName; + } + String[] arr = exportName.split(","); + for (String str : arr) { + if (str.indexOf(targetId) != -1) { + return str.split("_")[0]; + } + } + return null; + } + + /** + * 多个反射获取值 + * + * @param list + * @param t + * @return + * @throws Exception + */ + public Object getFieldBySomeMethod(List list, Object t) throws Exception { + for (Method m : list) { + if (t == null) { + t = ""; + break; + } + t = m.invoke(t, new Object[] {}); + } + return t; + } + + /** + * 根据注解获取行高 + * + * @param excelParams + * @return + */ + public short getRowHeight(List excelParams) { + double maxHeight = 0; + for (int i = 0; i < excelParams.size(); i++) { + maxHeight = maxHeight > excelParams.get(i).getHeight() ? maxHeight : excelParams.get(i).getHeight(); + if (excelParams.get(i).getList() != null) { + for (int j = 0; j < excelParams.get(i).getList().size(); j++) { + maxHeight = maxHeight > excelParams.get(i).getList().get(j).getHeight() ? maxHeight : excelParams.get(i).getList().get( + j).getHeight(); + } + } + } + return (short) (maxHeight * 50); + } + + /** + * 判断字符串是否是整数 + */ + public boolean isInteger(String value) { + try { + Integer.parseInt(value); + return true; + } catch (NumberFormatException e) { + return false; + } + } + + private Object replaceValue(String[] replace, String value) { + String[] temp; + for (String str : replace) { + //temp = str.split("_"); {'男_sheng_1','女_2'} + //update-begin-author:liusq date:20210127 for:字符串截取修改 + temp = getValueArr(str); + //update-end-author:liusq date:20210127 for:字符串截取修改 + + //update-begin---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析--- + if (value.equals(temp[1]) || value.replace("_", "---").equals(temp[1])) { + value = temp[0]; + break; + } + //update-end---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析--- + } + return value; + } + + //update-begin-author:taoyan date:20180731 for:TASK #3038 【bug】Excel 导出多个值(逗号隔开的情况下,导出字典值是ID值) + + /** + * 如果需要被替换的值是多选项,则每一项之间有逗号隔开,走以下方法 + * @author taoYan + * @since 2018年7月31日 + */ + private Object multiReplaceValue(String[] replace, String value) { + if (value.indexOf(",") > 0) { + String[] radioVals = value.split(","); + String[] temp; + String result = ""; + for (int i = 0; i < radioVals.length; i++) { + String radio = radioVals[i]; + for (String str : replace) { + temp = str.split("_"); + //update-begin-author:liusq date:20210127 for:字符串截取修改 + temp = getValueArr(str); + //update-end-author:liusq date:20210127 for:字符串截取修改 + + //update-begin---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析--- + if (radio.equals(temp[1]) || radio.replace("_", "---").equals(temp[1])) { + result = result.concat(temp[0]) + ","; + break; + } + //update-end---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析--- + } + } + if (result.equals("")) { + result = value; + } else { + result = result.substring(0, result.length() - 1); + } + return result; + } else { + return replaceValue(replace, value); + } + } + //update-end-author:taoyan date:20180731 for:TASK #3038 【bug】Excel 导出多个值(逗号隔开的情况下,导出字典值是ID值) + + /** + * 对字段根据用户设置排序 + */ + public void sortAllParams(List excelParams) { + Collections.sort(excelParams); + for (ExcelExportEntity entity : excelParams) { + if (entity.getList() != null) { + Collections.sort(entity.getList()); + } + } + } + + /** + * 循环ExcelExportEntity集合 附加配置信息
+ * 1.列排序
+ * 2.读取图片根路径设置(如果有字段是图片类型 并且存储在本地 则设置磁盘路径获取全地址导出)
+ * 3.多表头配置(仅限于单表 会走这个逻辑处理) + */ + public void reConfigExcelExportParams(List excelParams, ExportParams exportParams) { + Set NameSet = new HashSet(); + Map> groupAndColumnList = new HashMap>(); + Map groupOrder = new HashMap<>(); + int index = -99; + for (ExcelExportEntity entity : excelParams) { + if (entity.getOrderNum() == 0) { + entity.setOrderNum(index++); + } + if (entity.getExportImageType() == 3) { + entity.setImageBasePath(exportParams.getImageBasePath()); + } + if (entity.getList() != null) { + Collections.sort(entity.getList()); + } + String groupName = entity.getGroupName(); + if (StringUtils.isNotEmpty(groupName)) { + List ls = groupAndColumnList.get(groupName); + if (ls == null) { + ls = new ArrayList(); + groupAndColumnList.put(groupName, ls); + } + ls.add(entity.getKey().toString()); + + Integer order = groupOrder.get(groupName); + if (order == null || entity.getOrderNum() < order) { + order = entity.getOrderNum(); + } + groupOrder.put(groupName, order); + } + } + + for (String key : groupAndColumnList.keySet()) { + ExcelExportEntity temp = new ExcelExportEntity(key); + temp.setColspan(true); + temp.setSubColumnList(groupAndColumnList.get(key)); + temp.setOrderNum(groupOrder.get(key)); + excelParams.add(temp); + } + Collections.sort(excelParams); + } + + /** + * 字典文本中含多个下划线横岗,取最后一个(解决空值情况) + * + * @param val + * @return + */ + public String[] getValueArr(String val) { + int i = val.lastIndexOf("_");//最后一个分隔符的位置 + String[] c = new String[2]; + c[0] = val.substring(0, i); //label + c[1] = val.substring(i + 1); //key + return c; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/AbstractExcelExportStyler.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/AbstractExcelExportStyler.java new file mode 100644 index 0000000..251f71c --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/AbstractExcelExportStyler.java @@ -0,0 +1,83 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export.styler; + +import org.apache.poi.ss.usermodel.BuiltinFormats; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.excel.entity.params.ExcelForEachParams; + +/** + * 抽象接口提供两个公共方法 + * + * @author JEECG + * @date 2015年1月9日 下午5:48:55 + */ +public abstract class AbstractExcelExportStyler implements IExcelExportStyler { + // 单行 + protected CellStyle stringNoneStyle; + protected CellStyle stringNoneWrapStyle; + // 间隔行 + protected CellStyle stringSeptailStyle; + protected CellStyle stringSeptailWrapStyle; + + protected Workbook workbook; + + protected static final short STRING_FORMAT = (short) BuiltinFormats.getBuiltinFormat("TEXT"); + + protected void createStyles(Workbook workbook) { + this.stringNoneStyle = stringNoneStyle(workbook, false); + this.stringNoneWrapStyle = stringNoneStyle(workbook, true); + this.stringSeptailStyle = stringSeptailStyle(workbook, false); + this.stringSeptailWrapStyle = stringSeptailStyle(workbook, true); + this.workbook = workbook; + } + + @Override + public CellStyle getStyles(boolean noneStyler, ExcelExportEntity entity) { + if (noneStyler && (entity == null || entity.isWrap())) { + return stringNoneWrapStyle; + } + if (noneStyler) { + return stringNoneStyle; + } + if (noneStyler == false && (entity == null || entity.isWrap())) { + return stringSeptailWrapStyle; + } + return stringSeptailStyle; + } + + public CellStyle stringNoneStyle(Workbook workbook, boolean isWarp) { + return null; + } + + public CellStyle stringSeptailStyle(Workbook workbook, boolean isWarp) { + return null; + } + + /** + * 获取模板样式(列循环时用到) + * @param isSingle + * @param excelForEachParams + * @return + */ + @Override + public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) { + return null; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerBorderImpl.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerBorderImpl.java new file mode 100644 index 0000000..98b3d5f --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerBorderImpl.java @@ -0,0 +1,81 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export.styler; + +import org.apache.poi.ss.usermodel.*; + +/** + * 带有边框的Excel样式 + * + * @author JEECG + * @date 2015年1月9日 下午5:55:29 + */ +public class ExcelExportStylerBorderImpl extends AbstractExcelExportStyler implements IExcelExportStyler { + + public ExcelExportStylerBorderImpl(Workbook workbook) { + super.createStyles(workbook); + } + + @Override + public CellStyle getHeaderStyle(short color) { + CellStyle titleStyle = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontHeightInPoints((short) 12); + titleStyle.setFont(font); + titleStyle.setBorderLeft(BorderStyle.THIN); // 左边框 + titleStyle.setBorderRight(BorderStyle.THIN); // 右边框 + titleStyle.setBorderBottom(BorderStyle.THIN); + titleStyle.setBorderTop(BorderStyle.THIN); + titleStyle.setAlignment(HorizontalAlignment.CENTER); + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); + return titleStyle; + } + + @Override + public CellStyle stringNoneStyle(Workbook workbook, boolean isWarp) { + CellStyle style = workbook.createCellStyle(); + style.setBorderLeft(BorderStyle.THIN); // 左边框 + style.setBorderRight(BorderStyle.THIN); // 右边框 + style.setBorderBottom(BorderStyle.THIN); + style.setBorderTop(BorderStyle.THIN); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setDataFormat(STRING_FORMAT); + if (isWarp) { + style.setWrapText(true); + } + return style; + } + + @Override + public CellStyle getTitleStyle(short color) { + CellStyle titleStyle = workbook.createCellStyle(); + titleStyle.setBorderLeft(BorderStyle.THIN); // 左边框 + titleStyle.setBorderRight(BorderStyle.THIN); // 右边框 + titleStyle.setBorderBottom(BorderStyle.THIN); + titleStyle.setBorderTop(BorderStyle.THIN); + titleStyle.setAlignment(HorizontalAlignment.CENTER); + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); + titleStyle.setWrapText(true); + return titleStyle; + } + + @Override + public CellStyle stringSeptailStyle(Workbook workbook, boolean isWarp) { + return isWarp ? stringNoneWrapStyle : stringNoneStyle; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerColorImpl.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerColorImpl.java new file mode 100644 index 0000000..930f709 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerColorImpl.java @@ -0,0 +1,89 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export.styler; + +import org.apache.poi.ss.usermodel.*; + +/** + * 带有样式的导出服务 + * + * @author JEECG + * @date 2015年1月9日 下午4:54:15 + */ +public class ExcelExportStylerColorImpl extends AbstractExcelExportStyler implements IExcelExportStyler { + + public ExcelExportStylerColorImpl(Workbook workbook) { + super.createStyles(workbook); + } + + @Override + public CellStyle getHeaderStyle(short headerColor) { + CellStyle titleStyle = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontHeightInPoints((short) 24); + titleStyle.setFont(font); + titleStyle.setFillForegroundColor(headerColor); + titleStyle.setAlignment(HorizontalAlignment.CENTER); + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); + return titleStyle; + } + + @Override + public CellStyle stringNoneStyle(Workbook workbook, boolean isWarp) { + CellStyle style = workbook.createCellStyle(); + style.setBorderLeft(BorderStyle.THIN); // 左边框 + style.setBorderRight(BorderStyle.THIN); // 右边框 + style.setBorderBottom(BorderStyle.THIN); + style.setBorderTop(BorderStyle.THIN); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setDataFormat(STRING_FORMAT); + if (isWarp) { + style.setWrapText(true); + } + return style; + } + + @Override + public CellStyle getTitleStyle(short color) { + CellStyle titleStyle = workbook.createCellStyle(); + titleStyle.setFillForegroundColor(color); // 填充的背景颜色 + titleStyle.setAlignment(HorizontalAlignment.CENTER); + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); + titleStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 填充图案 + titleStyle.setWrapText(true); + return titleStyle; + } + + @Override + public CellStyle stringSeptailStyle(Workbook workbook, boolean isWarp) { + CellStyle style = workbook.createCellStyle(); + style.setBorderLeft(BorderStyle.THIN); // 左边框 + style.setBorderRight(BorderStyle.THIN); // 右边框 + style.setBorderBottom(BorderStyle.THIN); + style.setBorderTop(BorderStyle.THIN); + style.setFillForegroundColor((short) 41); // 填充的背景颜色 + style.setFillPattern(FillPatternType.SOLID_FOREGROUND); // 填充图案 + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setDataFormat(STRING_FORMAT); + if (isWarp) { + style.setWrapText(true); + } + return style; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerDefaultImpl.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerDefaultImpl.java new file mode 100644 index 0000000..5052fe8 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/ExcelExportStylerDefaultImpl.java @@ -0,0 +1,76 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export.styler; + +import org.apache.poi.ss.usermodel.*; + +/** + * 样式的默认实现 + * + * @author JEECG + * @date 2015年1月9日 下午5:36:08 + */ +public class ExcelExportStylerDefaultImpl extends AbstractExcelExportStyler implements IExcelExportStyler { + + public ExcelExportStylerDefaultImpl(Workbook workbook) { + super.createStyles(workbook); + } + + @Override + public CellStyle getTitleStyle(short color) { + CellStyle titleStyle = workbook.createCellStyle(); + titleStyle.setAlignment(HorizontalAlignment.CENTER); + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); + titleStyle.setWrapText(true); + return titleStyle; + } + + @Override + public CellStyle stringSeptailStyle(Workbook workbook, boolean isWarp) { + CellStyle style = workbook.createCellStyle(); + style.setAlignment( HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setDataFormat(STRING_FORMAT); + if (isWarp) { + style.setWrapText(true); + } + return style; + } + + @Override + public CellStyle getHeaderStyle(short color) { + CellStyle titleStyle = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setFontHeightInPoints((short) 12); + titleStyle.setFont(font); + titleStyle.setAlignment( HorizontalAlignment.CENTER); + titleStyle.setVerticalAlignment(VerticalAlignment.CENTER); + return titleStyle; + } + + @Override + public CellStyle stringNoneStyle(Workbook workbook, boolean isWarp) { + CellStyle style = workbook.createCellStyle(); + style.setAlignment(HorizontalAlignment.CENTER); + style.setVerticalAlignment(VerticalAlignment.CENTER); + style.setDataFormat(STRING_FORMAT); + if (isWarp) { + style.setWrapText(true); + } + return style; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/IExcelExportStyler.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/IExcelExportStyler.java new file mode 100644 index 0000000..036c6e1 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/styler/IExcelExportStyler.java @@ -0,0 +1,59 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export.styler; + +import org.apache.poi.ss.usermodel.CellStyle; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.excel.entity.params.ExcelForEachParams; + +/** + * Excel导出样式接口 + * + * @author JEECG + * @date 2015年1月9日 下午5:32:30 + */ +public interface IExcelExportStyler { + + /** + * 列表头样式 + * + * @param headerColor + * @return + */ + public CellStyle getHeaderStyle(short headerColor); + + /** + * 标题样式 + * + * @param color + * @return + */ + public CellStyle getTitleStyle(short color); + + /** + * 获取样式方法 + * + * @param noneStyler + * @param entity + * @return + */ + public CellStyle getStyles(boolean noneStyler, ExcelExportEntity entity); + /** + * 模板使用的样式设置 + */ + public CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams); + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/template/ExcelExportOfTemplateUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/template/ExcelExportOfTemplateUtil.java new file mode 100644 index 0000000..011c065 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/export/template/ExcelExportOfTemplateUtil.java @@ -0,0 +1,1026 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.export.template; + +import java.lang.reflect.Field; +import java.util.*; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFClientAnchor; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.ss.util.CellRangeAddress; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.jeecgframework.poi.cache.ExcelCache; +import org.jeecgframework.poi.cache.ImageCache; +import org.jeecgframework.poi.entity.ImageEntity; +import org.jeecgframework.poi.excel.annotation.ExcelTarget; +import org.jeecgframework.poi.excel.entity.TemplateExportParams; +import org.jeecgframework.poi.excel.entity.enmus.ExcelType; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.excel.entity.params.ExcelForEachParams; +import org.jeecgframework.poi.excel.entity.params.ExcelTemplateParams; +import org.jeecgframework.poi.excel.export.base.ExcelExportBase; +import org.jeecgframework.poi.excel.export.styler.IExcelExportStyler; +import org.jeecgframework.poi.excel.html.helper.MergedRegionHelper; +import org.jeecgframework.poi.exception.excel.ExcelExportException; +import org.jeecgframework.poi.exception.excel.enums.ExcelExportEnum; + +import static org.jeecgframework.poi.util.PoiElUtil.*; + +import org.jeecgframework.poi.util.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Excel 导出根据模板导出 + * + * @author JEECG + * @date 2013-10-17 + * @version 1.0 + */ +public final class ExcelExportOfTemplateUtil extends ExcelExportBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelExportOfTemplateUtil.class); + + /** + * 缓存TEMP 的for each创建的cell ,跳过这个cell的模板语法查找,提高效率 + */ + private Set tempCreateCellSet = new HashSet(); + /** + * 模板参数,全局都用到 + */ + private TemplateExportParams teplateParams; + /** + * 单元格合并信息 + */ + private MergedRegionHelper mergedRegionHelper; + + + /** + * 往Sheet 填充正常数据,根据表头信息 使用导入的部分逻辑,坐对象映射 + * + * @param teplateParams + * @param pojoClass + * @param dataSet + * @param workbook + */ + private void addDataToSheet(Class pojoClass, Collection dataSet, Sheet sheet, Workbook workbook) throws Exception { + + if (workbook instanceof XSSFWorkbook) { + super.type = ExcelType.XSSF; + } + // 获取表头数据 + Map titlemap = getTitleMap(sheet); + Drawing patriarch = sheet.createDrawingPatriarch(); + // 得到所有字段 + Field[] fileds = PoiPublicUtil.getClassFields(pojoClass); + ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); + String targetId = null; + if (etarget != null) { + targetId = etarget.value(); + } + // 获取实体对象的导出数据 + List excelParams = new ArrayList(); + getAllExcelField(null, targetId, fileds, excelParams, pojoClass, null); + // 根据表头进行筛选排序 + sortAndFilterExportField(excelParams, titlemap); + short rowHeight = getRowHeight(excelParams); + int index = teplateParams.getHeadingRows() + teplateParams.getHeadingStartRow(), titleHeight = index; + // 下移数据,模拟插入 + sheet.shiftRows(teplateParams.getHeadingRows() + teplateParams.getHeadingStartRow(), sheet.getLastRowNum(), getShiftRows(dataSet, excelParams), true, true); + if (excelParams.size() == 0) { + return; + } + Iterator its = dataSet.iterator(); + while (its.hasNext()) { + Object t = its.next(); + index += createCells(patriarch, index, t, excelParams, sheet, workbook, rowHeight); + } + // 合并同类项 + mergeCells(sheet, excelParams, titleHeight); + } + + /** + * 下移数据 + * + * @param its + * @param excelParams + * @return + */ + private int getShiftRows(Collection dataSet, List excelParams) throws Exception { + int size = 0; + Iterator its = dataSet.iterator(); + while (its.hasNext()) { + Object t = its.next(); + size += getOneObjectSize(t, excelParams); + } + return size; + } + + /** + * 获取单个对象的高度,主要是处理一堆多的情况 + * + * @param styles + * @param rowHeight + * @throws Exception + */ + public int getOneObjectSize(Object t, List excelParams) throws Exception { + ExcelExportEntity entity; + int maxHeight = 1; + for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + if (entity.getList() != null) { + Collection list = (Collection) entity.getMethod().invoke(t, new Object[] {}); + if (list != null && list.size() > maxHeight) { + maxHeight = list.size(); + } + } + } + return maxHeight; + + } + + public Workbook createExcleByTemplate(TemplateExportParams params, Class pojoClass, Collection dataSet, Map map) { + // step 1. 判断模板的地址 + if (params == null || map == null || StringUtils.isEmpty(params.getTemplateUrl())) { + throw new ExcelExportException(ExcelExportEnum.PARAMETER_ERROR); + } + Workbook wb = null; + // step 2. 判断模板的Excel类型,解析模板 + try { + this.teplateParams = params; + wb = getCloneWorkBook(); + // 创建表格样式 + setExcelExportStyler((IExcelExportStyler) teplateParams.getStyle().getConstructor(Workbook.class).newInstance(wb)); + // step 3. 解析模板 + for (int i = 0, le = params.isScanAllsheet() ? wb.getNumberOfSheets() : params.getSheetNum().length; i < le; i++) { + if (params.getSheetName() != null && params.getSheetName().length > i && StringUtils.isNotEmpty(params.getSheetName()[i])) { + wb.setSheetName(i, params.getSheetName()[i]); + } + tempCreateCellSet.clear(); + parseTemplate(wb.getSheetAt(i), map, params.isColForEach()); + } + if (dataSet != null) { + // step 4. 正常的数据填充 + dataHanlder = params.getDataHanlder(); + if (dataHanlder != null) { + needHanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields()); + } + addDataToSheet(pojoClass, dataSet, wb.getSheetAt(params.getDataSheetNum()), wb); + } + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + return null; + } + return wb; + } + + /** + * 克隆excel防止操作原对象,workbook无法克隆,只能对excel进行克隆 + * + * @param teplateParams + * @throws Exception + * @Author JEECG + * @date 2013-11-11 + */ + private Workbook getCloneWorkBook() throws Exception { + //update-begin-author:wangshuai date:20200730 for:jar 包上传到服务器后 autopoi 读取不到excel模版文件 #1505 + return ExcelCache.getWorkbookByTemplate(teplateParams.getTemplateUrl(), teplateParams.getSheetNum(), teplateParams.isScanAllsheet()); + //update-end-author:wangshuai date:20200730 for:jar 包上传到服务器后 autopoi 读取不到excel模版文件 #1505 + } + + /** + * 获取表头数据,设置表头的序号 + * + * @param teplateParams + * @param sheet + * @return + */ + private Map getTitleMap(Sheet sheet) { + Row row = null; + Iterator cellTitle; + Map titlemap = new HashMap(); + for (int j = 0; j < teplateParams.getHeadingRows(); j++) { + row = sheet.getRow(j + teplateParams.getHeadingStartRow()); + cellTitle = row.cellIterator(); + int i = row.getFirstCellNum(); + while (cellTitle.hasNext()) { + Cell cell = cellTitle.next(); + String value = cell.getStringCellValue(); + if (!StringUtils.isEmpty(value)) { + titlemap.put(value, i); + } + i = i + 1; + } + } + return titlemap; + + } + + private void parseTemplate(Sheet sheet, Map map, boolean colForeach) throws Exception { + deleteCell(sheet, map); + //update-begin-author:liusq---date:20220527--for: 模板导出列循环核心代码 --- + mergedRegionHelper = new MergedRegionHelper(sheet); + if (colForeach) { + colForeach(sheet, map); + } + //update-end-author:liusq---date:20220527--for: 模板导出列循环核心代码 --- + Row row = null; + int index = 0; + while (index <= sheet.getLastRowNum()) { + row = sheet.getRow(index++); + if (row == null) { + continue; + } + for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) { + if (row.getCell(i) != null && !tempCreateCellSet.contains(row.getRowNum() + "_" + row.getCell(i).getColumnIndex())) { + setValueForCellByMap(row.getCell(i), map); + } + } + } + } + + /** + * 先判断删除,省得影响效率 + * + * @param sheet + * @param map + * @throws Exception + */ + private void deleteCell(Sheet sheet, Map map) throws Exception { + Row row = null; + Cell cell = null; + int index = 0; + while (index <= sheet.getLastRowNum()) { + row = sheet.getRow(index++); + if (row == null) { + continue; + } + for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) { + cell = row.getCell(i); + if (row.getCell(i) != null && (cell.getCellType() == CellType.STRING || cell.getCellType() == CellType.NUMERIC)) { + cell.setCellType(CellType.STRING); + String text = cell.getStringCellValue(); + if (text.contains(IF_DELETE)) { + if (Boolean.valueOf(eval(text.substring(text.indexOf(START_STR) + 2, text.indexOf(END_STR)).trim(), map).toString())) { + PoiSheetUtility.deleteColumn(sheet, i); + } + cell.setCellValue(""); + } + } + } + } + } + + /** + * 给每个Cell通过解析方式set值 + * + * @param cell + * @param map + */ + private void setValueForCellByMap(Cell cell, Map map) throws Exception { + CellType cellType = cell.getCellType(); + if (cellType != CellType.STRING && cellType != CellType.NUMERIC) { + return; + } + String oldString; + cell.setCellType(CellType.STRING); + oldString = cell.getStringCellValue(); + if (oldString != null && oldString.indexOf(START_STR) != -1 && !oldString.contains(FOREACH)) { + // step 2. 判断是否含有解析函数 + String params = null; + boolean isNumber = false; + if (isNumber(oldString)) { + isNumber = true; + oldString = oldString.replace(NUMBER_SYMBOL, ""); + } + while (oldString.indexOf(START_STR) != -1) { + params = oldString.substring(oldString.indexOf(START_STR) + 2, oldString.indexOf(END_STR)); + + oldString = oldString.replace(START_STR + params + END_STR, eval(params, map).toString()); + } + // 如何是数值 类型,就按照数值类型进行设置 + if (isNumber && StringUtils.isNotBlank(oldString)) { + cell.setCellValue(Double.parseDouble(oldString)); + cell.setCellType(CellType.NUMERIC); + } else { + cell.setCellValue(oldString); + } + } + // 判断foreach 这种方法 + if (oldString != null && oldString.contains(FOREACH)) { + addListDataToExcel(cell, map, oldString.trim()); + } + + } + + private boolean isNumber(String text) { + return text.startsWith(NUMBER_SYMBOL) || text.contains("{" + NUMBER_SYMBOL) || text.contains(" " + NUMBER_SYMBOL); + } + + /** + * 利用foreach循环输出数据 + * + * @param cell + * @param map + * @param oldString + * @throws Exception + */ + private void addListDataToExcel(Cell cell, Map map, String name) throws Exception { + boolean isCreate = !name.contains(FOREACH_NOT_CREATE); + boolean isShift = name.contains(FOREACH_AND_SHIFT); + name = name.replace(FOREACH_NOT_CREATE, EMPTY).replace(FOREACH_AND_SHIFT, EMPTY).replace(FOREACH, EMPTY).replace(START_STR, EMPTY); + String[] keys = name.replaceAll("\\s{1,}", " ").trim().split(" "); + Collection datas = (Collection) PoiPublicUtil.getParamsValue(keys[0], map); + //update-begin-author:liusq---date:20220609--for: [issues/3328]autopoi模板导出Excel功能,$fe: 遍历不好用 --- + Object[] columnsInfo = getAllDataColumns(cell, name.replace(keys[0], EMPTY), + mergedRegionHelper); + int rowspan = (Integer) columnsInfo[0], colspan = (Integer) columnsInfo[1]; + @SuppressWarnings("unchecked") + List columns = (List) columnsInfo[2]; + if (datas == null) { + return; + } + Iterator its = datas.iterator(); + Row row; + int rowIndex = cell.getRow().getRowNum() + 1; + //处理当前行 + int loopSize = 0; + if (its.hasNext()) { + Object t = its.next(); + cell.getRow().setHeight(columns.get(0).getHeight()); + loopSize = setForeachRowCellValue(isCreate, cell.getRow(), cell.getColumnIndex(), t, columns, map, + rowspan, colspan, mergedRegionHelper)[0]; + rowIndex += rowspan - 1 + loopSize - 1; + } + //修复不论后面有没有数据,都应该执行的是插入操作 + if (isShift && datas.size() * rowspan > 1 && cell.getRowIndex() + rowspan <= cell.getRow().getSheet().getLastRowNum()) { + int lastRowNum = cell.getRow().getSheet().getLastRowNum(); + int shiftRows = lastRowNum - cell.getRowIndex() - rowspan; + cell.getRow().getSheet().shiftRows(cell.getRowIndex() + rowspan, lastRowNum, (datas.size() - 1) * rowspan, true, true); + //update-begin-author:liusq---date:20221103--for: [issues/4142]exlce模板导出如果模板中有多个合并单元格的循环表格,第二个表格读取错误 --- + mergedRegionHelper.shiftRows(cell.getSheet(), cell.getRowIndex() + rowspan, (datas.size() - 1) * rowspan, shiftRows); + PoiExcelTempUtil.reset(cell.getSheet(), cell.getRowIndex() + rowspan + (datas.size() - 1) * rowspan, cell.getRow().getSheet().getLastRowNum()); + //update-end-author:liusq---date:20221103--for: [issues/4142]exlce模板导出如果模板中有多个合并单元格的循环表格,第二个表格读取错误 --- + } + while (its.hasNext()) { + Object t = its.next(); + row = createRow(rowIndex, cell.getSheet(), isCreate, rowspan); + row.setHeight(columns.get(0).getHeight()); + loopSize = setForeachRowCellValue(isCreate, row, cell.getColumnIndex(), t, columns, map, rowspan, + colspan, mergedRegionHelper)[0]; + rowIndex += rowspan + loopSize - 1; + } + //update-end-author:liusq---date:20220609--for: [issues/3328]autopoi模板导出Excel功能,$fe: 遍历不好用 --- + } + + private void setForEeachCellValue(boolean isCreate, Row row, int columnIndex, Object t, List columns, Map map) throws Exception { + for (int i = 0, max = columnIndex + columns.size(); i < max; i++) { + if (row.getCell(i) == null) + row.createCell(i); + } + for (int i = 0, max = columns.size(); i < max; i++) { + boolean isNumber = false; + String tempStr = new String(columns.get(i).getName()); + if (isNumber(tempStr)) { + isNumber = true; + tempStr = tempStr.replace(NUMBER_SYMBOL, ""); + } + map.put(teplateParams.getTempParams(), t); + String val = eval(tempStr, map).toString(); + if (isNumber && StringUtils.isNotEmpty(val)) { + row.getCell(i + columnIndex).setCellValue(Double.parseDouble(val)); + row.getCell(i + columnIndex).setCellType(CellType.NUMERIC); + } else { + row.getCell(i + columnIndex).setCellValue(val); + } + row.getCell(i + columnIndex).setCellStyle(columns.get(i).getCellStyle()); + tempCreateCellSet.add(row.getRowNum() + "_" + (i + columnIndex)); + } + + } + + /** + * 获取迭代的数据的值 + * + * @param cell + * @param name + * @return + */ + private List getAllDataColumns(Cell cell, String name) { + List columns = new ArrayList(); + cell.setCellValue(""); + if (name.contains(END_STR)) { + columns.add(new ExcelTemplateParams(name.replace(END_STR, EMPTY).trim(), cell.getCellStyle(), cell.getRow().getHeight())); + return columns; + } + columns.add(new ExcelTemplateParams(name.trim(), cell.getCellStyle(), cell.getRow().getHeight())); + int index = cell.getColumnIndex(); + //列数 + int lastCellNum = cell.getRow().getLastCellNum(); + Cell tempCell; + while (true) { + tempCell = cell.getRow().getCell(++index); + //--begin--date:2020/09/18---for:增加列数判断,防止提前跳出 + if (tempCell == null&&index>=lastCellNum) { + break; + } + String cellStringString; + try {// 允许为空,单表示已经完结了,因为可能被删除了 + cellStringString = tempCell.getStringCellValue(); + if (StringUtils.isBlank(cellStringString)&&index>=lastCellNum) { + break; + } + } catch (Exception e) { + throw new ExcelExportException("for each 当中存在空字符串,请检查模板"); + } + //--end--date:2020/09/18---for:增加列数判断,防止提前跳出 + // 把读取过的cell 置为空 + tempCell.setCellValue(""); + if (cellStringString.contains(END_STR)) { + columns.add(new ExcelTemplateParams(cellStringString.trim().replace(END_STR, ""), tempCell.getCellStyle(), tempCell.getRow().getHeight())); + break; + } else { + if (cellStringString.trim().contains(teplateParams.getTempParams())) { + columns.add(new ExcelTemplateParams(cellStringString.trim(), tempCell.getCellStyle(), tempCell.getRow().getHeight())); + }else if(cellStringString.trim().equals(EMPTY)){ + //可能是合并的单元格,允许空数据的设置 + columns.add(new ExcelTemplateParams(EMPTY, tempCell.getCellStyle(), tempCell.getRow().getHeight())); + } else { + // 最后一行被删除了 + break; + } + } + + } + return columns; + } + + /** + * 对导出序列进行排序和塞选 + * + * @param excelParams + * @param titlemap + * @return + */ + private void sortAndFilterExportField(List excelParams, Map titlemap) { + for (int i = excelParams.size() - 1; i >= 0; i--) { + if (excelParams.get(i).getList() != null && excelParams.get(i).getList().size() > 0) { + sortAndFilterExportField(excelParams.get(i).getList(), titlemap); + if (excelParams.get(i).getList().size() == 0) { + excelParams.remove(i); + } else { + excelParams.get(i).setOrderNum(i); + } + } else { + if (titlemap.containsKey(excelParams.get(i).getName())) { + excelParams.get(i).setOrderNum(i); + } else { + excelParams.remove(i); + } + } + } + sortAllParams(excelParams); + } + + //-----------------update-begin-author:liusq---date:20220527--for: 以下方法是模板导出列循环功能新增的方法 --- + /** + * 先进行列的循环,因为涉及很多数据 + * + * @param sheet + * @param map + */ + private void colForeach(Sheet sheet, Map map) throws Exception { + Row row = null; + Cell cell = null; + int index = 0; + while (index <= sheet.getLastRowNum()) { + row = sheet.getRow(index++); + if (row == null) { + continue; + } + for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) { + cell = row.getCell(i); + if (row.getCell(i) != null && (cell.getCellType() == CellType.STRING + || cell.getCellType() == CellType.NUMERIC)) { + String text = PoiCellUtil.getCellValue(cell); + if (text.contains(FOREACH_COL) || text.contains(FOREACH_COL_VALUE)) { + foreachCol(cell, map, text); + } + } + } + } + } + + /** + * 循环列表 + * + * @param cell + * @param map + * @param name + * @throws Exception + */ + private void foreachCol(Cell cell, Map map, String name) throws Exception { + boolean isCreate = name.contains(FOREACH_COL_VALUE); + name = name.replace(FOREACH_COL_VALUE, EMPTY).replace(FOREACH_COL, EMPTY).replace(START_STR, + EMPTY); + String[] keys = name.replaceAll("\\s{1,}", " ").trim().split(" "); + Collection datas = (Collection) PoiPublicUtil.getParamsValue(keys[0], map); + Object[] columnsInfo = getAllDataColumns(cell, name.replace(keys[0], EMPTY), + mergedRegionHelper); + if (datas == null) { + return; + } + Iterator its = datas.iterator(); + int rowspan = (Integer) columnsInfo[0], colspan = (Integer) columnsInfo[1]; + @SuppressWarnings("unchecked") + List columns = (List) columnsInfo[2]; + while (its.hasNext()) { + Object t = its.next(); + setForeachRowCellValue(true, cell.getRow(), cell.getColumnIndex(), t, columns, map, + rowspan, colspan, mergedRegionHelper); + if (cell.getRow().getCell(cell.getColumnIndex() + colspan) == null) { + cell.getRow().createCell(cell.getColumnIndex() + colspan); + } + cell = cell.getRow().getCell(cell.getColumnIndex() + colspan); + } + if (isCreate) { + cell = cell.getRow().getCell(cell.getColumnIndex() - 1); + cell.setCellValue(cell.getStringCellValue() + END_STR); + } + } + /** + * 循环迭代创建,遍历row + * + * @param isCreate + * @param row + * @param columnIndex + * @param t + * @param columns + * @param map + * @param rowspan + * @param colspan + * @param mergedRegionHelper + * @return rowSize, cellSize + * @throws Exception + */ + private int[] setForeachRowCellValue(boolean isCreate, Row row, int columnIndex, Object t, + List columns, Map map, + int rowspan, int colspan, + MergedRegionHelper mergedRegionHelper) throws Exception { + createRowCellSetStyle(row, columnIndex, columns, rowspan, colspan); + //填写数据 + ExcelForEachParams params; + int loopSize = 1; + int loopCi = 1; + row = row.getSheet().getRow(row.getRowNum() - rowspan + 1); + for (int k = 0; k < rowspan; k++) { + int ci = columnIndex; + row.setHeight(getMaxHeight(k, colspan, columns)); + for (int i = 0; i < colspan && i < columns.size(); i++) { + boolean isNumber = false; + params = columns.get(colspan * k + i); + tempCreateCellSet.add(row.getRowNum() + "_" + (ci)); + if (params == null) { + continue; + } + if (StringUtils.isEmpty(params.getName()) + && StringUtils.isEmpty(params.getConstValue())) { + row.getCell(ci).setCellStyle(params.getCellStyle()); + ci = ci + params.getColspan(); + continue; + } + String val; + Object obj = null; + //是不是常量 + String tempStr = params.getName(); + if (StringUtils.isEmpty(params.getName())) { + val = params.getConstValue(); + } else { + if (isHasSymbol(tempStr, NUMBER_SYMBOL)) { + isNumber = true; + tempStr = tempStr.replaceFirst(NUMBER_SYMBOL, ""); + } + map.put(teplateParams.getTempParams(), t); + boolean isDict = false; + String dict = null; + if (isHasSymbol(tempStr, DICT_HANDLER)) { + isDict = true; + dict = tempStr.substring(tempStr.indexOf(DICT_HANDLER) + 5).split(";")[0]; + tempStr = tempStr.replaceFirst(DICT_HANDLER, ""); + tempStr = tempStr.replaceFirst(dict + ";", ""); + } + obj = eval(tempStr, map); + if (isDict && !(obj instanceof Collection)) { + obj = dictHandler.toName(dict, t, tempStr, obj); + } + val = obj.toString(); + } + if (obj != null && obj instanceof Collection) { + // 需要找到哪一级别是集合 ,方便后面的replace + String collectName = evalFindName(tempStr, map); + int[] loop = setForEachLoopRowCellValue(row, ci, (Collection) obj, columns, + params, map, rowspan, colspan, mergedRegionHelper, collectName); + loopSize = Math.max(loopSize, loop[0]); + i += loop[1] - 1; + ci = loop[2] - params.getColspan(); + } else if (obj != null && obj instanceof ImageEntity) { + ImageEntity img = (ImageEntity) obj; + row.getCell(ci).setCellValue(""); + if (img.getRowspan() > 1 || img.getColspan() > 1) { + img.setHeight(0); + row.getCell(ci).getSheet().addMergedRegion(new CellRangeAddress(row.getCell(ci).getRowIndex(), + row.getCell(ci).getRowIndex() + img.getRowspan() - 1, row.getCell(ci).getColumnIndex(), row.getCell(ci).getColumnIndex() + img.getColspan() - 1)); + } + createImageCell(row.getCell(ci), img.getHeight(), img.getRowspan(), img.getColspan(), img.getUrl(), img.getData()); + } else if (isNumber && StringUtils.isNotEmpty(val)) { + row.getCell(ci).setCellValue(Double.parseDouble(val)); + } else { + try { + row.getCell(ci).setCellValue(val); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + } + if (params.getCellStyle() != null) { + row.getCell(ci).setCellStyle(params.getCellStyle()); + } + //如果合并单元格,就把这个单元格的样式和之前的保持一致 + setMergedRegionStyle(row, ci, params); + //合并对应单元格 + //update-begin-author:liusq---date:20221103--for: [issues/4142]exlce模板导出如果模板中有多个合并单元格的循环表格,第二个表格读取错误 --- + boolean isNeedMerge = (params.getRowspan() != 1 || params.getColspan() != 1) + && !mergedRegionHelper.isMergedRegion(row.getRowNum() + 1, ci); + //update-end-author:liusq---date:20221103--for: [issues/4142]exlce模板导出如果模板中有多个合并单元格的循环表格,第二个表格读取错误 --- + if (isNeedMerge) { + PoiMergeCellUtil.addMergedRegion(row.getSheet(), row.getRowNum(), + row.getRowNum() + params.getRowspan() - 1, ci, + ci + params.getColspan() - 1); + } + ci = ci + params.getColspan(); + } + loopCi = Math.max(loopCi, ci); + // 需要把需要合并的单元格合并了 --- 不是集合的栏位合并了 + if (loopSize > 1) { + handlerLoopMergedRegion(row, columnIndex, columns, loopSize); + } + row = row.getSheet().getRow(row.getRowNum() + 1); + } + return new int[]{loopSize, loopCi}; + } + /** + * 图片类型的Cell + */ + public void createImageCell(Cell cell, double height, int rowspan, int colspan, + String imagePath, byte[] data) throws Exception { + if (height > cell.getRow().getHeight()) { + cell.getRow().setHeight((short) height); + } + ClientAnchor anchor; + if (type.equals(ExcelType.HSSF)) { + anchor = new HSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + colspan), + cell.getRow().getRowNum() + rowspan); + } else { + anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + colspan), + cell.getRow().getRowNum() + rowspan); + } + if (StringUtils.isNotEmpty(imagePath)) { + data = ImageCache.getImage(imagePath); + } + if (data != null) { + PoiExcelGraphDataUtil.getDrawingPatriarch(cell.getSheet()).createPicture(anchor, + cell.getSheet().getWorkbook().addPicture(data, getImageType(data))); + } + } + /** + * 处理内循环 + * + * @param row + * @param columnIndex + * @param obj + * @param columns + * @param params + * @param map + * @param rowspan + * @param colspan + * @param mergedRegionHelper + * @param collectName + * @return [rowNums, columnsNums, ciIndex] + * @throws Exception + */ + private int[] setForEachLoopRowCellValue(Row row, int columnIndex, Collection obj, List columns, + ExcelForEachParams params, Map map, + int rowspan, int colspan, + MergedRegionHelper mergedRegionHelper, String collectName) throws Exception { + + //多个一起遍历 -去掉第一层 把所有的数据遍历一遍 + //STEP 1拿到所有的和当前一样项目的字段 + List temp = getLoopEachParams(columns, columnIndex, collectName); + Iterator its = obj.iterator(); + Row tempRow = row; + int nums = 0; + int ci = columnIndex; + while (its.hasNext()) { + Object data = its.next(); + map.put("loop_" + columnIndex, data); + int[] loopArr = setForeachRowCellValue(false, tempRow, columnIndex, data, temp, map, rowspan, + colspan, mergedRegionHelper); + nums += loopArr[0]; + ci = Math.max(ci, loopArr[1]); + map.remove("loop_" + columnIndex); + tempRow = createRow(tempRow.getRowNum() + loopArr[0], row.getSheet(), false, rowspan); + } + for (int i = 0; i < temp.size(); i++) { + temp.get(i).setName(temp.get(i).getTempName().pop()); + //都是集合 + temp.get(i).setCollectCell(true); + + } + return new int[]{nums, temp.size(), ci}; + } + /** + * 创建并返回第一个Row + * + * @param sheet + * @param rowIndex + * @param isCreate + * @param rows + * @return + */ + private Row createRow(int rowIndex, Sheet sheet, boolean isCreate, int rows) { + for (int i = 0; i < rows; i++) { + if (isCreate) { + sheet.createRow(rowIndex++); + } else if (sheet.getRow(rowIndex++) == null) { + sheet.createRow(rowIndex - 1); + } + } + return sheet.getRow(rowIndex - rows); + } + /** + * 根据 当前是集合的信息,把后面整个集合的迭代获取出来,并替换掉集合的前缀方便后面取数 + * + * @param columns + * @param columnIndex + * @param collectName + * @return + */ + private List getLoopEachParams(List columns, int columnIndex, String collectName) { + List temp = new ArrayList<>(); + for (int i = 0; i < columns.size(); i++) { + //先置为不是集合 + columns.get(i).setCollectCell(false); + if (columns.get(i) == null || columns.get(i).getName().contains(collectName)) { + temp.add(columns.get(i)); + if (columns.get(i).getTempName() == null) { + columns.get(i).setTempName(new Stack<>()); + } + columns.get(i).setCollectCell(true); + columns.get(i).getTempName().push(columns.get(i).getName()); + columns.get(i).setName(columns.get(i).getName().replace(collectName, "loop_" + columnIndex)); + } + } + return temp; + } + + /** + * 设置行样式 + * @param row + * @param columnIndex + * @param columns + * @param rowspan + * @param colspan + */ + private void createRowCellSetStyle(Row row, int columnIndex, List columns, + int rowspan, int colspan) { + //所有的cell创建一遍 + for (int i = 0; i < rowspan; i++) { + int size = columns.size(); + for (int j = columnIndex, max = columnIndex + colspan; j < max; j++) { + if (row.getCell(j) == null) { + row.createCell(j); + CellStyle style = row.getRowNum() % 2 == 0 + ? getStyles(false, + size <= j - columnIndex ? null : columns.get(j - columnIndex)) + : getStyles(true, + size <= j - columnIndex ? null : columns.get(j - columnIndex)); + //返回的styler不为空时才使用,否则使用Excel设置的,更加推荐Excel设置的样式 + if (style != null) { + row.getCell(j).setCellStyle(style); + } + } + + } + if (i < rowspan - 1) { + row = row.getSheet().getRow(row.getRowNum() + 1); + } + } + } + + /** + * 获取CellStyle + * @param isSingle + * @param excelForEachParams + * @return + */ + private CellStyle getStyles(boolean isSingle, ExcelForEachParams excelForEachParams) { + return excelExportStyler.getTemplateStyles(isSingle, excelForEachParams); + } + + /** + * 获取最大高度 + * @param k + * @param colspan + * @param columns + * @return + */ + private short getMaxHeight(int k, int colspan, List columns) { + short high = columns.get(0).getHeight(); + int n = k; + while (n > 0) { + if (columns.get(n * colspan).getHeight() == 0) { + n--; + } else { + high = columns.get(n * colspan).getHeight(); + break; + } + } + return high; + } + + private boolean isHasSymbol(String text, String symbol) { + return text.startsWith(symbol) || text.contains("{" + symbol) + || text.contains(" " + symbol); + } + /** + * 迭代把不是集合的数据都合并了 + * + * @param row + * @param columnIndex + * @param columns + * @param loopSize + */ + private void handlerLoopMergedRegion(Row row, int columnIndex, List columns, int loopSize) { + for (int i = 0; i < columns.size(); i++) { + if (!columns.get(i).isCollectCell()) { + PoiMergeCellUtil.addMergedRegion(row.getSheet(), row.getRowNum(), + row.getRowNum() + loopSize - 1, columnIndex, + columnIndex + columns.get(i).getColspan() - 1); + } + columnIndex = columnIndex + columns.get(i).getColspan(); + } + } + /** + * 设置合并单元格的样式 + * + * @param row + * @param ci + * @param params + */ + private void setMergedRegionStyle(Row row, int ci, ExcelForEachParams params) { + //第一行数据 + for (int i = 1; i < params.getColspan(); i++) { + if (params.getCellStyle() != null) { + row.getCell(ci + i).setCellStyle(params.getCellStyle()); + } + } + for (int i = 1; i < params.getRowspan(); i++) { + for (int j = 0; j < params.getColspan(); j++) { + if (params.getCellStyle() != null) { + row.getCell(ci + j).setCellStyle(params.getCellStyle()); + } + } + } + } + /** + * 获取迭代的数据的值 + * + * @param cell + * @param name + * @param mergedRegionHelper + * @return + */ + private Object[] getAllDataColumns(Cell cell, String name, + MergedRegionHelper mergedRegionHelper) { + List columns = new ArrayList(); + cell.setCellValue(""); + columns.add(getExcelTemplateParams(name.replace(END_STR, EMPTY), cell, mergedRegionHelper)); + int rowspan = 1, colspan = 1; + if (!name.contains(END_STR)) { + int index = cell.getColumnIndex(); + //保存col 的开始列 + int startIndex = cell.getColumnIndex(); + Row row = cell.getRow(); + while (index < row.getLastCellNum()) { + int colSpan = columns.get(columns.size() - 1) != null + ? columns.get(columns.size() - 1).getColspan() : 1; + index += colSpan; + + + for (int i = 1; i < colSpan; i++) { + //添加合并的单元格,这些单元可能不是空,但是没有值,所以也需要跳过 + columns.add(null); + continue; + } + cell = row.getCell(index); + //可能是合并的单元格 + if (cell == null) { + //读取是判断,跳过 + columns.add(null); + continue; + } + String cellStringString; + try {//不允许为空 便利单元格必须有结尾和值 + cellStringString = cell.getStringCellValue(); + if (StringUtils.isBlank(cellStringString) && colspan + startIndex <= index) { + throw new ExcelExportException("for each 当中存在空字符串,请检查模板"); + } else if (StringUtils.isBlank(cellStringString) + && colspan + startIndex > index) { + //读取是判断,跳过,数据为空,但是不是第一次读这一列,所以可以跳过 + columns.add(new ExcelForEachParams(null, cell.getCellStyle(), (short) 0)); + continue; + } + } catch (Exception e) { + throw new ExcelExportException(ExcelExportEnum.TEMPLATE_ERROR, e); + } + //把读取过的cell 置为空 + cell.setCellValue(""); + if (cellStringString.contains(END_STR)) { + columns.add(getExcelTemplateParams(cellStringString.replace(END_STR, EMPTY), + cell, mergedRegionHelper)); + //补全缺失的cell(合并单元格后面的) + int lastCellColspan = columns.get(columns.size() - 1).getColspan(); + for (int i = 1; i < lastCellColspan; i++) { + //添加合并的单元格,这些单元可能不是空,但是没有值,所以也需要跳过 + columns.add(null); + } + break; + } else if (cellStringString.contains(WRAP)) { + columns.add(getExcelTemplateParams(cellStringString.replace(WRAP, EMPTY), cell, + mergedRegionHelper)); + //发现换行符,执行换行操作 + colspan = index - startIndex + 1; + index = startIndex - columns.get(columns.size() - 1).getColspan(); + row = row.getSheet().getRow(row.getRowNum() + 1); + rowspan++; + } else { + columns.add(getExcelTemplateParams(cellStringString.replace(WRAP, EMPTY), cell, + mergedRegionHelper)); + } + } + } + colspan = 0; + for (int i = 0; i < columns.size(); i++) { + colspan += columns.get(i) != null ? columns.get(i).getColspan() : 0; + } + colspan = colspan / rowspan; + return new Object[]{rowspan, colspan, columns}; + } + /** + * 获取模板参数 + * + * @param name + * @param cell + * @param mergedRegionHelper + * @return + */ + private ExcelForEachParams getExcelTemplateParams(String name, Cell cell, + MergedRegionHelper mergedRegionHelper) { + name = name.trim(); + ExcelForEachParams params = new ExcelForEachParams(name, cell.getCellStyle(), + cell.getRow().getHeight()); + //判断是不是常量 + if (name.startsWith(CONST) && name.endsWith(CONST)) { + params.setName(null); + params.setConstValue(name.substring(1, name.length() - 1)); + } + //判断是不是空 + if (NULL.equals(name)) { + params.setName(null); + params.setConstValue(EMPTY); + } + //获取合并单元格的数据 + if (mergedRegionHelper.isMergedRegion(cell.getRowIndex() + 1, cell.getColumnIndex())) { + Integer[] colAndrow = mergedRegionHelper.getRowAndColSpan(cell.getRowIndex() + 1, + cell.getColumnIndex()); + params.setRowspan(colAndrow[0]); + params.setColspan(colAndrow[1]); + } + return params; + } + //-----------------update-end-author:liusq---date:20220527--for: 以上方法是模板导出列循环功能新增的方法 --- +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/builder/ExcelChartBuildService.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/builder/ExcelChartBuildService.java new file mode 100644 index 0000000..0346c55 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/builder/ExcelChartBuildService.java @@ -0,0 +1,263 @@ +///** +// * +// */ +//package org.jeecgframework.poi.excel.graph.builder; +// +//import java.util.ArrayList; +//import java.util.List; +// +//import org.apache.commons.lang3.StringUtils; +//import org.apache.poi.ss.usermodel.Chart; +//import org.apache.poi.ss.usermodel.ClientAnchor; +//import org.apache.poi.ss.usermodel.Drawing; +//import org.apache.poi.ss.usermodel.Sheet; +//import org.apache.poi.ss.usermodel.Workbook; +//import org.apache.poi.ss.usermodel.charts.AxisCrosses; +//import org.apache.poi.ss.usermodel.charts.AxisPosition; +//import org.apache.poi.ss.usermodel.charts.ChartAxis; +//import org.apache.poi.ss.usermodel.charts.ChartDataSource; +//import org.apache.poi.ss.usermodel.charts.ChartLegend; +//import org.apache.poi.ss.usermodel.charts.DataSources; +//import org.apache.poi.ss.usermodel.charts.LegendPosition; +//import org.apache.poi.ss.usermodel.charts.LineChartData; +//import org.apache.poi.ss.usermodel.charts.ScatterChartData; +//import org.apache.poi.ss.usermodel.charts.ValueAxis; +//import org.apache.poi.ss.util.CellRangeAddress; +// +//import org.jeecgframework.poi.excel.graph.constant.ExcelGraphElementType; +//import org.jeecgframework.poi.excel.graph.constant.ExcelGraphType; +//import org.jeecgframework.poi.excel.graph.entity.ExcelGraph; +//import org.jeecgframework.poi.excel.graph.entity.ExcelGraphElement; +//import org.jeecgframework.poi.excel.graph.entity.ExcelTitleCell; +//import org.jeecgframework.poi.util.PoiCellUtil; +//import org.jeecgframework.poi.util.PoiExcelGraphDataUtil; +// +///** +// * @Description +// * @author liusq +// * @data 2022年1月4号 +// */ +//public class ExcelChartBuildService +//{ +// /** +// * +// * @param workbook +// * @param graphList +// * @param build 通过实时数据行来重新计算图形定义 +// * @param append +// */ +// public static void createExcelChart(Workbook workbook, List graphList, Boolean build, Boolean append) +// { +// if(workbook!=null&&graphList!=null){ +// //设定默认第一个sheet为数据项 +// Sheet dataSouce=workbook.getSheetAt(0); +// if(dataSouce!=null){ +// buildTitle(dataSouce,graphList); +// +// if(build){ +// PoiExcelGraphDataUtil.buildGraphData(dataSouce, graphList); +// } +// if(append){ +// buildExcelChart(dataSouce, dataSouce, graphList); +// }else{ +// Sheet sheet=workbook.createSheet("图形界面"); +// buildExcelChart(dataSouce, sheet, graphList); +// } +// } +// +// } +// } +// +// /** +// * 构建基础图形 +// * @param drawing +// * @param anchor +// * @param dataSourceSheet +// * @param graph +// */ +// private static void buildExcelChart(Drawing drawing,ClientAnchor anchor,Sheet dataSourceSheet,ExcelGraph graph){ +// Chart chart = null; +// // TODO 图表没有成功 +// //drawing.createChart(anchor); +// ChartLegend legend = chart.getOrCreateLegend(); +// legend.setPosition(LegendPosition.TOP_RIGHT); +// +// ChartAxis bottomAxis = chart.getChartAxisFactory().createCategoryAxis(AxisPosition.BOTTOM); +// ValueAxis leftAxis = chart.getChartAxisFactory().createValueAxis(AxisPosition.LEFT); +// leftAxis.setCrosses(AxisCrosses.AUTO_ZERO); +// ExcelGraphElement categoryElement=graph.getCategory(); +// +// ChartDataSource categoryChart; +// if(categoryElement!=null&& categoryElement.getElementType().equals(ExcelGraphElementType.STRING_TYPE)){ +// categoryChart=DataSources.fromStringCellRange(dataSourceSheet, new CellRangeAddress(categoryElement.getStartRowNum(),categoryElement.getEndRowNum(),categoryElement.getStartColNum(),categoryElement.getEndColNum())); +// }else{ +// categoryChart=DataSources.fromNumericCellRange(dataSourceSheet, new CellRangeAddress(categoryElement.getStartRowNum(),categoryElement.getEndRowNum(),categoryElement.getStartColNum(),categoryElement.getEndColNum())); +// } +// +// List valueList=graph.getValueList(); +// List> chartValueList= new ArrayList<>(); +// if(valueList!=null&&valueList.size()>0){ +// for(ExcelGraphElement ele:valueList){ +// ChartDataSource source=DataSources.fromNumericCellRange(dataSourceSheet, new CellRangeAddress(ele.getStartRowNum(),ele.getEndRowNum(),ele.getStartColNum(),ele.getEndColNum())); +// chartValueList.add(source); +// } +// } +// +// if(graph.getGraphType().equals(ExcelGraphType.LINE_CHART)){ +// LineChartData data = chart.getChartDataFactory().createLineChartData(); +// buildLineChartData(data, categoryChart, chartValueList, graph.getTitle()); +// chart.plot(data, bottomAxis, leftAxis); +// } +// else +// { +// ScatterChartData data=chart.getChartDataFactory().createScatterChartData(); +// buildScatterChartData(data, categoryChart, chartValueList,graph.getTitle()); +// chart.plot(data, bottomAxis, leftAxis); +// } +// } +// +// +// +// +// /** +// * 构建多个图形对象 +// * @param dataSourceSheet +// * @param tragetSheet +// * @param graphList +// */ +// private static void buildExcelChart(Sheet dataSourceSheet,Sheet tragetSheet,List graphList){ +// int len=graphList.size(); +// if(len==1) +// { +// buildExcelChart(dataSourceSheet, tragetSheet, graphList.get(0)); +// } +// else +// { +// int drawStart=0; +// int drawEnd=20; +// Drawing drawing = PoiExcelGraphDataUtil.getDrawingPatriarch(tragetSheet); +// for(int i=0;i0){ +// +// }else{ +// for(int i=0;i graphList){ +// if(graphList!=null&&graphList.size()>0){ +// for(ExcelGraph graph:graphList){ +// if(graph!=null) +// { +// buildTitle(sheet, graph); +// } +// } +// } +// } +// +// /** +// * +// * @param data +// * @param categoryChart +// * @param chartValueList +// * @param title +// */ +// private static void buildLineChartData(LineChartData data,ChartDataSource categoryChart,List> chartValueList,List title){ +// if(chartValueList.size()==title.size()) +// { +// int len=title.size(); +// for(int i=0;i source:chartValueList){ +// String temp_title=title.get(i); +// if(StringUtils.isNotBlank(temp_title)){ +// //data.addSerie(categoryChart, source).setTitle(_title); +// }else{ +// //data.addSerie(categoryChart, source); +// } +// } +// } +// } +// +// /** +// * +// * @param data +// * @param categoryChart +// * @param chartValueList +// * @param title +// */ +// private static void buildScatterChartData(ScatterChartData data,ChartDataSource categoryChart,List> chartValueList,List title){ +// if(chartValueList.size()==title.size()) +// { +// int len=title.size(); +// for(int i=0;i source:chartValueList){ +// String temp_title=title.get(i); +// if(StringUtils.isNotBlank(temp_title)){ +// data.addSerie(categoryChart, source).setTitle(temp_title); +// }else{ +// data.addSerie(categoryChart, source); +// } +// } +// } +// } +// +// +//} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/constant/ExcelGraphElementType.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/constant/ExcelGraphElementType.java new file mode 100644 index 0000000..9b74909 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/constant/ExcelGraphElementType.java @@ -0,0 +1,15 @@ +/** + * + */ +package org.jeecgframework.poi.excel.graph.constant; + +/** + * @Description 定义元素类型 + * @author liusq + * @date 2022年1月4号 + */ +public interface ExcelGraphElementType +{ + public static final Integer STRING_TYPE =1; + public static final Integer NUMERIC_TYPE =2; +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/constant/ExcelGraphType.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/constant/ExcelGraphType.java new file mode 100644 index 0000000..7bf9495 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/constant/ExcelGraphType.java @@ -0,0 +1,16 @@ +/** + * + */ +package org.jeecgframework.poi.excel.graph.constant; + +/** + * @Description 定义图形类型 + * @author liusq + * @date 2022年1月4号 + */ +public interface ExcelGraphType +{ + public static final Integer LINE_CHART =1; + public static final Integer SCATTER_CHART =2; + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraph.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraph.java new file mode 100644 index 0000000..df51dce --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraph.java @@ -0,0 +1,20 @@ +/** + * + */ +package org.jeecgframework.poi.excel.graph.entity; + +import java.util.List; + +/** + * @Description Excel 图形构造服务 + * @author liusq + * @date 2022年1月4号 + */ +public interface ExcelGraph +{ + public ExcelGraphElement getCategory(); + public List getValueList(); + public Integer getGraphType(); + public List getTitleCell(); + public List getTitle(); +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraphDefined.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraphDefined.java new file mode 100644 index 0000000..c3b4488 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraphDefined.java @@ -0,0 +1,74 @@ +/** + * + */ +package org.jeecgframework.poi.excel.graph.entity; + +import org.jeecgframework.poi.excel.graph.constant.ExcelGraphType; + +import java.util.ArrayList; +import java.util.List; + + +/** + * @Description Excel 图形构造服务 + * @author liusq + * @date 2022年1月4号 + */ +public class ExcelGraphDefined implements ExcelGraph +{ + private ExcelGraphElement category; + public List valueList= new ArrayList<>(); + public List titleCell= new ArrayList<>(); + private Integer graphType= ExcelGraphType.LINE_CHART; + public List title= new ArrayList<>(); + + @Override + public ExcelGraphElement getCategory() + { + return category; + } + public void setCategory(ExcelGraphElement category) + { + this.category = category; + } + @Override + public List getValueList() + { + return valueList; + } + public void setValueList(List valueList) + { + this.valueList = valueList; + } + + @Override + public Integer getGraphType() + { + return graphType; + } + public void setGraphType(Integer graphType) + { + this.graphType = graphType; + } + @Override + public List getTitleCell() + { + return titleCell; + } + public void setTitleCell(List titleCell) + { + this.titleCell = titleCell; + } + @Override + public List getTitle() + { + return title; + } + public void setTitle(List title) + { + this.title = title; + } + + + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraphElement.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraphElement.java new file mode 100644 index 0000000..07c493a --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelGraphElement.java @@ -0,0 +1,63 @@ +/** + * + */ +package org.jeecgframework.poi.excel.graph.entity; + + +import org.jeecgframework.poi.excel.graph.constant.ExcelGraphElementType; + +/** + * @Description Excel 图形构造服务 + * @author liusq + * @date 2022年1月4号 + */ +public class ExcelGraphElement +{ + private Integer startRowNum; + private Integer endRowNum; + private Integer startColNum; + private Integer endColNum; + private Integer elementType= ExcelGraphElementType.STRING_TYPE; + + + public Integer getStartRowNum() + { + return startRowNum; + } + public void setStartRowNum(Integer startRowNum) + { + this.startRowNum = startRowNum; + } + public Integer getEndRowNum() + { + return endRowNum; + } + public void setEndRowNum(Integer endRowNum) + { + this.endRowNum = endRowNum; + } + public Integer getStartColNum() + { + return startColNum; + } + public void setStartColNum(Integer startColNum) + { + this.startColNum = startColNum; + } + public Integer getEndColNum() + { + return endColNum; + } + public void setEndColNum(Integer endColNum) + { + this.endColNum = endColNum; + } + public Integer getElementType() + { + return elementType; + } + public void setElementType(Integer elementType) + { + this.elementType = elementType; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelTitleCell.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelTitleCell.java new file mode 100644 index 0000000..7bd0535 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/entity/ExcelTitleCell.java @@ -0,0 +1,43 @@ +/** + * + */ +package org.jeecgframework.poi.excel.graph.entity; + +/** + * @Description Excel 图形构造服务 + * @author liusq + * @date 2022年1月4号 + */ +public class ExcelTitleCell +{ + private Integer row; + private Integer col; + + public ExcelTitleCell(){ + + } + + public ExcelTitleCell(Integer row,Integer col){ + this.row=row; + this.col=col; + } + + public Integer getRow() + { + return row; + } + public void setRow(Integer row) + { + this.row = row; + } + public Integer getCol() + { + return col; + } + public void setCol(Integer col) + { + this.col = col; + } + + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/package-info.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/package-info.java new file mode 100644 index 0000000..103161d --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/graph/package-info.java @@ -0,0 +1,9 @@ +/** + * + */ +/** + * @Description Excel 图形构造服务 + * @author liusq + * @date 2022年1月4号 + */ +package org.jeecgframework.poi.excel.graph; \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/ExcelToHtmlServer.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/ExcelToHtmlServer.java new file mode 100644 index 0000000..eaee1e8 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/ExcelToHtmlServer.java @@ -0,0 +1,191 @@ +package org.jeecgframework.poi.excel.html; + +import java.util.Formatter; +import java.util.Iterator; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellStyle; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.poi.excel.html.helper.CellValueHelper; +import org.jeecgframework.poi.excel.html.helper.MergedRegionHelper; +import org.jeecgframework.poi.excel.html.helper.StylerHelper; + +/** + * Excel转换成Html 服务 + * + * @author JEECG + * @date 2015年5月10日 上午11:41:15 + */ +public class ExcelToHtmlServer { + + private Workbook wb; + private int sheetNum; + private int cssRandom; + + /* 是不是完成界面 */ + private boolean completeHTML; + private Formatter out; + /* 已经完成范围处理 */ + private boolean gotBounds; + private int firstColumn; + private int endColumn; + private static final String COL_HEAD_CLASS = "colHeader"; + // private static final String ROW_HEAD_CLASS = "rowHeader"; + + private static final String DEFAULTS_CLASS = "excelDefaults"; + + public ExcelToHtmlServer(Workbook wb, boolean completeHTML, int sheetNum) { + this.wb = wb; + this.completeHTML = completeHTML; + this.sheetNum = sheetNum; + cssRandom = (int) Math.ceil(Math.random() * 1000); + } + + public String printPage() { + try { + ensureOut(); + if (completeHTML) { + out.format("%n"); + out.format("%n"); + out.format("%n"); + out.format("%n"); + } + new StylerHelper(wb, out, sheetNum, cssRandom); + if (completeHTML) { + out.format("%n"); + out.format("%n"); + } + print(); + if (completeHTML) { + out.format("%n"); + out.format("%n"); + } + return out.toString(); + } finally { + if (out != null) + out.close(); + } + } + + private void print() { + printSheets(); + } + + private void ensureOut() { + if (out == null) + out = new Formatter(new StringBuilder()); + } + + private void printSheets() { + Sheet sheet = wb.getSheetAt(sheetNum); + printSheet(sheet); + } + + private void printSheet(Sheet sheet) { + out.format("%n", DEFAULTS_CLASS, getTableWidth(sheet)); + printCols(sheet); + printSheetContent(sheet); + out.format("
%n"); + } + + private void printCols(Sheet sheet) { + // out.format("%n"); + ensureColumnBounds(sheet); + for (int i = firstColumn; i < endColumn; i++) { + out.format("%n", sheet.getColumnWidth(i) / 32); + } + } + + private int getTableWidth(Sheet sheet) { + ensureColumnBounds(sheet); + int width = 0; + for (int i = firstColumn; i < endColumn; i++) { + width = width + (sheet.getColumnWidth(i) / 32); + } + return width; + } + + private void ensureColumnBounds(Sheet sheet) { + if (gotBounds) + return; + + Iterator iter = sheet.rowIterator(); + firstColumn = (iter.hasNext() ? Integer.MAX_VALUE : 0); + endColumn = 0; + while (iter.hasNext()) { + Row row = iter.next(); + short firstCell = row.getFirstCellNum(); + if (firstCell >= 0) { + firstColumn = Math.min(firstColumn, firstCell); + endColumn = Math.max(endColumn, row.getLastCellNum()); + } + } + gotBounds = true; + } + + @SuppressWarnings("unused") + /**本来是用来生成 A,B 那个列名称的**/ + private void printColumnHeads(Sheet sheet) { + out.format("%n"); + out.format(" %n", COL_HEAD_CLASS); + out.format(" ◊%n", COL_HEAD_CLASS); + StringBuilder colName = new StringBuilder(); + for (int i = firstColumn; i < endColumn; i++) { + colName.setLength(0); + int cnum = i; + do { + colName.insert(0, (char) ('A' + cnum % 26)); + cnum /= 26; + } while (cnum > 0); + out.format(" %s%n", COL_HEAD_CLASS, colName); + } + out.format(" %n"); + out.format("%n"); + } + + private void printSheetContent(Sheet sheet) { + // printColumnHeads(sheet); + MergedRegionHelper mergedRegionHelper = new MergedRegionHelper(sheet); + CellValueHelper cellValueHelper = new CellValueHelper(wb, cssRandom); + out.format("%n"); + Iterator rows = sheet.rowIterator(); + int rowIndex = 1; + while (rows.hasNext()) { + Row row = rows.next(); + out.format(" %n", row.getHeight() / 15); + // out.format(" %d%n", ROW_HEAD_CLASS, + // row.getRowNum() + 1); + for (int i = firstColumn; i < endColumn; i++) { + if (mergedRegionHelper.isNeedCreate(rowIndex, i)) { + String content = " "; + CellStyle style = null; + if (i >= row.getFirstCellNum() && i < row.getLastCellNum()) { + Cell cell = row.getCell(i); + if (cell != null) { + style = cell.getCellStyle(); + content = cellValueHelper.getHtmlValue(cell); + } + } + if (mergedRegionHelper.isMergedRegion(rowIndex, i)) { + Integer[] rowAndColSpan = mergedRegionHelper.getRowAndColSpan(rowIndex, i); + out.format(" %s%n", rowAndColSpan[0], rowAndColSpan[1], styleName(style), content); + } else { + out.format(" %s%n", styleName(style), content); + } + } + + } + out.format(" %n"); + rowIndex++; + } + out.format("%n"); + } + + private String styleName(CellStyle style) { + if (style == null) + return ""; + return String.format("style_%02x_%s font_%s_%s", style.getIndex(), cssRandom, style.getFontIndex(), cssRandom); + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/CellValueHelper.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/CellValueHelper.java new file mode 100644 index 0000000..51d4204 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/CellValueHelper.java @@ -0,0 +1,135 @@ +package org.jeecgframework.poi.excel.html.helper; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.poi.hssf.usermodel.HSSFRichTextString; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; + +import com.google.common.xml.XmlEscapers; + +/** + * Cell值帮助类 + * + * @author JEECG + * @date 2015年5月9日 下午10:31:32 + */ +public class CellValueHelper { + /** + * Excel 格式 + */ + private boolean is07; + + private int cssRandom; + + private Map fontCache = new HashMap(); + + public CellValueHelper(Workbook wb, int cssRandom) { + this.cssRandom = cssRandom; + if (wb instanceof HSSFWorkbook) + is07 = false; + else if (wb instanceof XSSFWorkbook) { + is07 = true; + cacheFontInfo(wb); + } else + throw new IllegalArgumentException("unknown workbook type: " + wb.getClass().getSimpleName()); + } + + /** + * O7 版本坑爹bug + * + * @param wb + */ + private void cacheFontInfo(Workbook wb) { + for (int i = 0, le = wb.getNumberOfFonts(); i < le; i++) { + Font font = wb.getFontAt(i); + fontCache.put(font.getBold() + "_" + font.getItalic() + "_" + font.getFontName() + "_" + font.getFontHeightInPoints() + "_" + font.getColor(), font.getIndex() + ""); + } + + } + + public String getHtmlValue(Cell cell) { + if (CellType.BOOLEAN == cell.getCellType() || CellType.NUMERIC == cell.getCellType()) { + cell.setCellType( CellType.STRING); + return cell.getStringCellValue(); + } else if ( CellType.STRING == cell.getCellType()) { + if (cell.getRichStringCellValue().numFormattingRuns() == 0) { + return XmlEscapers.xmlContentEscaper().escape(cell.getStringCellValue()); + } else if (is07) { + return getXSSFRichString((XSSFRichTextString) cell.getRichStringCellValue()); + } else { + return getHSSFRichString((HSSFRichTextString) cell.getRichStringCellValue()); + } + } + return ""; + } + + /** + * 03版本复杂数据 + * + * @param rich + * @return + */ + private String getHSSFRichString(HSSFRichTextString rich) { + int nums = rich.numFormattingRuns(); + StringBuilder sb = new StringBuilder(); + String text = rich.toString(); + int currentIndex = 0; + sb.append(text.substring(0, rich.getIndexOfFormattingRun(0))); + for (int i = 0; i < nums; i++) { + sb.append(""); + currentIndex = rich.getIndexOfFormattingRun(i); + if (i < nums - 1) { + sb.append(XmlEscapers.xmlContentEscaper().escape(text.substring(currentIndex, rich.getIndexOfFormattingRun(i + 1)))); + } else { + sb.append(XmlEscapers.xmlContentEscaper().escape(text.substring(currentIndex, text.length()))); + } + sb.append(""); + } + return sb.toString(); + } + + /** + * 07版本复杂数据 + * + * @param rich + * @return + */ + private String getXSSFRichString(XSSFRichTextString rich) { + int nums = rich.numFormattingRuns(); + StringBuilder sb = new StringBuilder(); + String text = rich.toString(); + int currentIndex = 0, lastIndex = 0; + for (int i = 1; i <= nums; i++) { + sb.append(""); + currentIndex = rich.getIndexOfFormattingRun(i) == -1 ? text.length() : rich.getIndexOfFormattingRun(i); + sb.append(XmlEscapers.xmlContentEscaper().escape(text.substring(lastIndex, currentIndex))); + sb.append(""); + lastIndex = currentIndex; + } + return sb.toString(); + } + + private String getFontIndex(XSSFFont font) { + return fontCache.get(font.getBold() + "_" + font.getItalic() + "_" + font.getFontName() + "_" + font.getFontHeightInPoints() + "_" + font.getColor()); + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/MergedRegionHelper.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/MergedRegionHelper.java new file mode 100644 index 0000000..70e6ab3 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/MergedRegionHelper.java @@ -0,0 +1,139 @@ +package org.jeecgframework.poi.excel.html.helper; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.poi.ss.usermodel.Sheet; +import org.jeecgframework.poi.util.PoiCellUtil; +import org.jeecgframework.poi.util.PoiMergeCellUtil; + +/** + * 合并单元格帮助类 + * + * @author JEECG + * @date 2015年5月9日 下午2:13:35 + */ +public class MergedRegionHelper { + + private Map mergedCache = new HashMap(); + + private Set notNeedCread = new HashSet(); + + public MergedRegionHelper(Sheet sheet) { + getAllMergedRegion(sheet); + } + + private void getAllMergedRegion(Sheet sheet) { + int nums = sheet.getNumMergedRegions(); + for (int i = 0; i < nums; i++) { + handerMergedString(sheet.getMergedRegion(i).formatAsString()); + } + } + + /** + * 根据合并输出内容,处理合并单元格事情 + * + * @param formatAsString + */ + private void handerMergedString(String formatAsString) { + String[] strArr = formatAsString.split(":"); + if (strArr.length == 2) { + int startCol = strArr[0].charAt(0) - 65; + if (strArr[0].charAt(1) >= 65) { + startCol = (startCol + 1) * 26 + (strArr[0].charAt(1) - 65); + } + int startRol = Integer.valueOf(strArr[0].substring(strArr[0].charAt(1) >= 65 ? 2 : 1)); + int endCol = strArr[1].charAt(0) - 65; + if (strArr[1].charAt(1) >= 65) { + endCol = (endCol + 1) * 26 + (strArr[1].charAt(1) - 65); + } + int endRol = Integer.valueOf(strArr[1].substring(strArr[1].charAt(1) >= 65 ? 2 : 1)); + mergedCache.put(startRol + "_" + startCol, new Integer[] { endRol - startRol + 1, endCol - startCol + 1 }); + for (int i = startRol; i <= endRol; i++) { + for (int j = startCol; j <= endCol; j++) { + notNeedCread.add(i + "_" + j); + } + } + notNeedCread.remove(startRol + "_" + startCol); + } + + } + + /** + * 是不是需要创建这个TD + * + * @param row + * @param col + * @return + */ + public boolean isNeedCreate(int row, int col) { + return !notNeedCread.contains(row + "_" + col); + } + + /** + * 是不是合并区域 + * + * @param row + * @param col + * @return + */ + public boolean isMergedRegion(int row, int col) { + return mergedCache.containsKey(row + "_" + col); + } + + /** + * 获取合并区域 + * + * @param row + * @param col + * @return + */ + public Integer[] getRowAndColSpan(int row, int col) { + return mergedCache.get(row + "_" + col); + } + + /** + * 插入之后还原之前的合并单元格 + * + * @param rowIndex + * @param size + */ + public void shiftRows(Sheet sheet, int rowIndex, int size, int shiftRows) { + Set keys = new HashSet(); + keys.addAll(mergedCache.keySet()); + for (String key : keys) { + String[] temp = key.split("_"); + //update-begin---author:chenrui ---date:20240102 for:[issue/5167]遍历单元格次行原本的合并缓存未正确删除导致最终输出合并样式有问题------------ + if (Integer.parseInt(temp[0]) > rowIndex) { + //update-end---author:chenrui ---date:20240102 for:[issue/5167]遍历单元格次行原本的合并缓存未正确删除导致最终输出合并样式有问题------------ + Integer[] data = mergedCache.get(key); + String newKey = (Integer.parseInt(temp[0]) + size) + "_" + temp[1]; + if (!mergedCache.containsKey(newKey)) { + mergedCache.put(newKey, mergedCache.get(key)); + try { + // 还原合并单元格 + if (!PoiCellUtil.isMergedRegion(sheet, Integer.parseInt(temp[0]) + size - 1, Integer.parseInt(temp[1]))) { + PoiMergeCellUtil.addMergedRegion(sheet, + Integer.parseInt(temp[0]) + size - 1, Integer.parseInt(temp[0]) + data[0] + size - 2, + Integer.parseInt(temp[1]), Integer.parseInt(temp[1]) + data[1] - 1 + ); + } + } catch (Exception e) { + } + } + } + } + //删除掉原始的缓存KEY + for (String key : keys) { + String[] temp = key.split("_"); + //update-begin---author:chenrui ---date:20240102 for:[issue/5167]遍历单元格次行原本的合并缓存未正确删除导致最终输出合并样式有问题------------ + if (Integer.parseInt(temp[0]) >= rowIndex && Integer.parseInt(temp[0]) <= rowIndex + size ) { + //update-end---author:chenrui ---date:20240102 for:[issue/5167]遍历单元格次行原本的合并缓存未正确删除导致最终输出合并样式有问题------------ + mergedCache.remove(key); + } + } + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/StylerHelper.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/StylerHelper.java new file mode 100644 index 0000000..734126c --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/StylerHelper.java @@ -0,0 +1,259 @@ +package org.jeecgframework.poi.excel.html.helper; + + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Formatter; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import org.apache.poi.hssf.usermodel.HSSFCellStyle; +import org.apache.poi.hssf.usermodel.HSSFPalette; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.hssf.util.HSSFColor; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.apache.poi.xssf.usermodel.XSSFColor; +import org.apache.poi.xssf.usermodel.XSSFFont; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.jeecgframework.poi.util.PoiPublicUtil; + +/** + * 样式帮助类 + * + * @author JEECG + * @date 2015年5月9日 下午4:04:24 + */ +public class StylerHelper { + + private static String DEFAULTS_CLASS_CSS = ".excelDefaults {background-color: white;color: black;text-decoration: none;direction: ltr;text-transform: none;text-indent: 0;letter-spacing: 0;word-spacing: 0;white-space: normal;unicode-bidi: normal;vertical-align: 0;text-shadow: none;padding: 0;margin: 0;border-collapse: collapse;white-space: pre-wrap;word-wrap: break-word;word-break: break-all;}.excelDefaults td {padding: 1px 5px;border: 1px solid silver;border-color: #000000;text-align: center;vertical-align: middle;font-size: 12pt;}.excelDefaults .colHeader {background-color: silver;font-weight: bold;border: 1px solid black;text-align: center;padding: 1px 5px;}.excelDefaults .rowHeader {background-color: silver;font-weight: bold;border: 1px solid black;text-align: right;padding: 1px 5px;}"; + + private static final String DEFAULTS_CLASS = "excelDefaults"; + + private static final Map ALIGN = PoiPublicUtil.mapFor(HorizontalAlignment.LEFT.getCode(), "left",HorizontalAlignment.CENTER.getCode(), "center",HorizontalAlignment.RIGHT.getCode(), "right", HorizontalAlignment.FILL.getCode(), "left",HorizontalAlignment.JUSTIFY.getCode(), "left",HorizontalAlignment.CENTER_SELECTION.getCode(), "center"); + + private static final Map VERTICAL_ALIGN = PoiPublicUtil.mapFor(VerticalAlignment.BOTTOM.getCode(), "bottom", VerticalAlignment.CENTER.getCode(), "middle",VerticalAlignment.TOP.getCode(), "top"); + + private Formatter out; + + private Sheet sheet; + + private HtmlHelper helper; + + private int sheetNum; + + private int cssRandom; + + public StylerHelper(Workbook wb, Formatter out, int sheetNum, int cssRandom) { + this.out = out; + this.sheetNum = sheetNum; + this.cssRandom = cssRandom; + if (wb instanceof HSSFWorkbook) + helper = new HSSFHtmlHelper((HSSFWorkbook) wb); + else if (wb instanceof XSSFWorkbook) + helper = new XSSFHtmlHelper((XSSFWorkbook) wb); + else + throw new IllegalArgumentException("unknown workbook type: " + wb.getClass().getSimpleName()); + printInlineStyle(wb); + } + + private void printInlineStyle(Workbook wb) { + out.format("%n"); + } + + private void prontFonts(Workbook wb) { + //update-begin---author:liusq Date:20220228 for:[I4I3ZY]issue AutoPOi Workbook对象转HTML字符串 数组下标越界异常---- + for (int i = 0, le = wb.getNumberOfFonts(); i < le; i++) { + Font font = wb.getFontAt(i); + out.format(".%s .%s {%n", DEFAULTS_CLASS, "font_" + i + "_" + cssRandom); + fontStyle(font); + out.format("}%n"); + } + //update-end---author:liusq Date:20220228 for:[I4I3ZY]issue AutoPOi Workbook对象转HTML字符串 数组下标越界异常整---- + } + + public void printStyles(Workbook wb) { + if (DEFAULTS_CLASS_CSS == null) { + DEFAULTS_CLASS_CSS = getDefaultsClassCss(); + } + out.format(DEFAULTS_CLASS_CSS); + Set seen = new HashSet(); + sheet = wb.getSheetAt(sheetNum); + Iterator rows = sheet.rowIterator(); + while (rows.hasNext()) { + Row row = rows.next(); + for (Cell cell : row) { + CellStyle style = cell.getCellStyle(); + if (!seen.contains(style)) { + printStyle(style); + seen.add(style); + } + } + } + } + + private String getDefaultsClassCss() { + BufferedReader in = null; + StringBuilder sb = new StringBuilder(); + Formatter formatter = new Formatter(sb); + try { + in = new BufferedReader(new InputStreamReader(StylerHelper.class.getResourceAsStream("excelStyle.css"))); + String line; + while ((line = in.readLine()) != null) { + formatter.format("%s%n", line); + } + return formatter.toString(); + } catch (IOException e) { + throw new IllegalStateException("Reading standard css", e); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + throw new IllegalStateException("Reading standard css", e); + } + } + formatter.close(); + } + } + + private void printStyle(CellStyle style) { + out.format(".%s .%s {%n", DEFAULTS_CLASS, styleName(style)); + styleContents(style); + out.format("}%n"); + } + + private void styleContents(CellStyle style) { + if (style.getAlignment().getCode() != 2) { + styleOut("text-align", style.getAlignment().getCode(), ALIGN); + styleOut("vertical-align", style.getAlignment().getCode(), VERTICAL_ALIGN); + } + helper.colorStyles(style, out); + } + + private void fontStyle(Font font) { + if (font.getBold()) + out.format(" font-weight: bold;%n"); + if (font.getItalic()) + out.format(" font-style: italic;%n"); + out.format(" font-family: %s;%n", font.getFontName()); + + int fontheight = font.getFontHeightInPoints(); + if (fontheight == 9) { + fontheight = 10; + } + out.format(" font-size: %dpt;%n", fontheight); + helper.styleColor(out, "color", getColor(font)); + } + + private Color getColor(Font font) { + if (helper instanceof HSSFHtmlHelper) { + return ((HSSFWorkbook) sheet.getWorkbook()).getCustomPalette().getColor(font.getColor()); + } else { + return ((XSSFFont) font).getXSSFColor(); + } + } + + private String styleName(CellStyle style) { + if (style == null) + return ""; + return String.format("style_%02x_%s", style.getIndex(), cssRandom); + } + + private void styleOut(String attr, K key, Map mapping) { + String value = mapping.get(key); + if (value != null) { + out.format(" %s: %s;%n", attr, value); + } + } + + private interface HtmlHelper { + /** + * Outputs the appropriate CSS style for the given cell style. + * + * @param style + * The cell style. + * @param out + * The place to write the output. + */ + void colorStyles(CellStyle style, Formatter out); + + void styleColor(Formatter out, String attr, Color color); + } + + private class HSSFHtmlHelper implements HtmlHelper { + private final HSSFWorkbook wb; + private final HSSFPalette colors; + + //-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + private HSSFColor HSSF_AUTO = new HSSFColor(0x40, -1, java.awt.Color.black); + //-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + + public HSSFHtmlHelper(HSSFWorkbook wb) { + this.wb = wb; + colors = wb.getCustomPalette(); + } + + public void colorStyles(CellStyle style, Formatter out) { + HSSFCellStyle cs = (HSSFCellStyle) style; + out.format(" /* fill pattern = %d */%n", cs.getFillPattern()); + styleColor(out, "background-color", cs.getFillForegroundColor()); + styleColor(out, "color", colors.getColor(cs.getFont(wb).getColor())); + } + + private void styleColor(Formatter out, String attr, short index) { + HSSFColor color = colors.getColor(index); + if (index == HSSF_AUTO.getIndex() || color == null) { + out.format(" /* %s: index = %d */%n", attr, index); + } else { + short[] rgb = color.getTriplet(); + out.format(" %s: #%02x%02x%02x; /* index = %d */%n", attr, rgb[0], rgb[1], rgb[2], index); + } + } + + public void styleColor(Formatter out, String attr, Color color) { + if (color == null) { + return; + } + HSSFColor hSSFColor = (HSSFColor) color; + short[] rgb = hSSFColor.getTriplet(); + out.format(" %s: #%02x%02x%02x; %n", attr, rgb[0], rgb[1], rgb[2]); + } + } + + /** + * Implementation of {@link HtmlHelper} for XSSF files. + * + * @author Ken Arnold, Industrious Media LLC + */ + private class XSSFHtmlHelper implements HtmlHelper { + + public XSSFHtmlHelper(XSSFWorkbook wb) { + } + + public void colorStyles(CellStyle style, Formatter out) { + XSSFCellStyle cs = (XSSFCellStyle) style; + styleColor(out, "background-color", cs.getFillForegroundXSSFColor()); + styleColor(out, "color", cs.getFont().getXSSFColor()); + } + + public void styleColor(Formatter out, String attr, Color color) { + XSSFColor xSSFColor = (XSSFColor) color; + if (color == null || xSSFColor.isAuto()) + return; + + byte[] rgb = xSSFColor.getRGB(); + if (rgb == null) { + return; + } + out.format(" %s: #%02x%02x%02x;%n", attr, rgb[0], rgb[1], rgb[2]); + } + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/excelStyle.css b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/excelStyle.css new file mode 100644 index 0000000..93fdbe2 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/html/helper/excelStyle.css @@ -0,0 +1,45 @@ +.excelDefaults { + background-color: white; + color: black; + text-decoration: none; + direction: ltr; + text-transform: none; + text-indent: 0; + letter-spacing: 0; + word-spacing: 0; + white-space: normal; + unicode-bidi: normal; + vertical-align: 0; + text-shadow: none; + padding: 0; + margin: 0; + border-collapse: collapse; + white-space: pre-wrap; + word-wrap: break-word; + word-break: break-all; +} + +.excelDefaults td { + padding: 1px 5px; + border: 1px solid silver; + border-color: #000000; + text-align: center; + vertical-align: middle; + font-size: 12pt; +} + +.excelDefaults .colHeader { + background-color: silver; + font-weight: bold; + border: 1px solid black; + text-align: center; + padding: 1px 5px; +} + +.excelDefaults .rowHeader { + background-color: silver; + font-weight: bold; + border: 1px solid black; + text-align: right; + padding: 1px 5px; +} \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/CellValueServer.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/CellValueServer.java new file mode 100644 index 0000000..23e1910 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/CellValueServer.java @@ -0,0 +1,387 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.jeecgframework.poi.excel.entity.params.ExcelImportEntity; +import org.jeecgframework.poi.excel.entity.sax.SaxReadCellEntity; +import org.jeecgframework.poi.exception.excel.ExcelImportException; +import org.jeecgframework.poi.exception.excel.enums.ExcelImportEnum; +import org.jeecgframework.poi.handler.inter.IExcelDataHandler; +import org.jeecgframework.poi.util.ExcelUtil; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.sql.Time; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * Cell 取值服务 判断类型处理数据 1.判断Excel中的类型 2.根据replace替换值 3.handler处理数据 4.判断返回类型转化数据返回 + * + * @author JEECG + * @date 2014年6月26日 下午10:42:28 + */ +public class CellValueServer { + + private static final Logger LOGGER = LoggerFactory.getLogger(CellValueServer.class); + + private List hanlderList = null; + + /** + * 获取单元格内的值 + * + * @param xclass + * @param cell + * @param entity + * @return + */ + private Object getCellValue(String xclass, Cell cell, ExcelImportEntity entity) { + if (cell == null) { + return ""; + } + Object result = null; + // 日期格式比较特殊,和cell格式不一致 + if ("class java.util.Date".equals(xclass) || ("class java.sql.Time").equals(xclass)) { + if ( CellType.NUMERIC == cell.getCellType()) { + // 日期格式 + result = cell.getDateCellValue(); + } else { + cell.setCellType( CellType.STRING); + result = getDateData(entity, cell.getStringCellValue()); + } + if (("class java.sql.Time").equals(xclass)) { + result = new Time(((Date) result).getTime()); + } + } else if ( CellType.NUMERIC == cell.getCellType()) { + result = cell.getNumericCellValue(); + } else if ( CellType.BOOLEAN == cell.getCellType()) { + result = cell.getBooleanCellValue(); + } else if ( CellType.FORMULA == cell.getCellType() && PoiPublicUtil.isNumber(xclass)) { + //如果单元格是表达式 且 字段是数字类型 + double cellValue = cell.getNumericCellValue(); + //---author:liusq---date:20221102-----for: [issues/3369]Excel导入 带公式的时候精度丢失--- + //setScale方法的第一个参数设置小数点保留位数,第二个参数设置进位方法、此处是四舍五入 + BigDecimal bigDecimal= new BigDecimal(cellValue).setScale(4, RoundingMode.HALF_UP); + //stripTrailingZeros方法去除末尾的0,toPlainString避免输出科学计数法的字符串 + result = bigDecimal.stripTrailingZeros().toPlainString(); + //---author:liusq---date:20221102-----for:[issues/3369] Excel导入 带公式的时候精度丢失--- + } else { + //设置单元格类型 + cell.setCellType(CellType.STRING); + result = cell.getStringCellValue(); + } + return result; + } + + /** + * 获取日期类型数据 + * + * @Author JEECG + * @date 2013年11月26日 + * @param entity + * @param value + * @return + */ + private Date getDateData(ExcelImportEntity entity, String value) { + if (StringUtils.isNotEmpty(entity.getFormat()) && StringUtils.isNotEmpty(value)) { + SimpleDateFormat format = new SimpleDateFormat(entity.getFormat()); + try { + return format.parse(value); + } catch (ParseException e) { + LOGGER.error("时间格式化失败,格式化:{},值:{}", entity.getFormat(), value); + throw new ExcelImportException(ExcelImportEnum.GET_VALUE_ERROR); + } + } + return null; + } + + /** + * 获取cell的值 + * + * @param object + * @param excelParams + * @param cell + * @param titleString + */ + public Object getValue(IExcelDataHandler dataHanlder, Object object, Cell cell, Map excelParams, String titleString) throws Exception { + ExcelImportEntity entity = excelParams.get(titleString); + String xclass = "class java.lang.Object"; + if (!(object instanceof Map)) { + Method setMethod = entity.getMethods() != null && entity.getMethods().size() > 0 ? entity.getMethods().get(entity.getMethods().size() - 1) : entity.getMethod(); + Type[] ts = setMethod.getGenericParameterTypes(); + xclass = ts[0].toString(); + } + Object result = getCellValue(xclass, cell, entity); + if (entity != null) { + result = hanlderSuffix(entity.getSuffix(), result); + //update-begin-author:taoYan date:20180807 for:多值替换 + result = replaceValue(entity.getReplace(), result,entity.isMultiReplace()); + //update-end-author:taoYan date:20180807 for:多值替换 + } + result = hanlderValue(dataHanlder, object, result, titleString); + return getValueByType(xclass, result, entity); + } + + /** + * 获取cell值 + * + * @param dataHanlder + * @param object + * @param cellEntity + * @param excelParams + * @param titleString + * @return + */ + public Object getValue(IExcelDataHandler dataHanlder, Object object, SaxReadCellEntity cellEntity, Map excelParams, String titleString) { + ExcelImportEntity entity = excelParams.get(titleString); + Method setMethod = entity.getMethods() != null && entity.getMethods().size() > 0 ? entity.getMethods().get(entity.getMethods().size() - 1) : entity.getMethod(); + Type[] ts = setMethod.getGenericParameterTypes(); + String xclass = ts[0].toString(); + Object result = cellEntity.getValue(); + result = hanlderSuffix(entity.getSuffix(), result); + //update-begin-auhtor:taoyan date:20180807 for:多值替换 + result = replaceValue(entity.getReplace(), result,entity.isMultiReplace()); + //update-end-auhtor:taoyan date:20180807 for:多值替换 + result = hanlderValue(dataHanlder, object, result, titleString); + return getValueByType(xclass, result, entity); + } + + /** + * 把后缀删除掉 + * + * @param result + * @param suffix + * @return + */ + private Object hanlderSuffix(String suffix, Object result) { + if (StringUtils.isNotEmpty(suffix) && result != null && result.toString().endsWith(suffix)) { + String temp = result.toString(); + return temp.substring(0, temp.length() - suffix.length()); + } + return result; + } + + /** + * 根据返回类型获取返回值 + * + * @param xclass + * @param result + * @param entity + * @return + */ + private Object getValueByType(String xclass, Object result, ExcelImportEntity entity) { + try { + //update-begin-author:scott date:20180711 for:TASK #2950 【bug】excel 导入报错,空指针问题 + if(result==null || "".equals(String.valueOf(result))){ + return null; + } + //update-end-author:scott date:20180711 for:TASK #2950 【bug】excel 导入报错,空指针问题 + if ("class java.util.Date".equals(xclass)) { + return result; + } + if ("class java.lang.Boolean".equals(xclass) || "boolean".equals(xclass)) { + //update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + Boolean temp = Boolean.valueOf(String.valueOf(result)); + //if(StringUtils.isNotEmpty(entity.getNumFormat())){ + // return Boolean.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp)); + //}else{ + return temp; + //} + //update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + } + if ("class java.lang.Double".equals(xclass) || "double".equals(xclass)) { + //update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + Double temp = Double.valueOf(String.valueOf(result)); + //if(StringUtils.isNotEmpty(entity.getNumFormat())){ + // return Double.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp)); + //}else{ + return temp; + //} + //update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + } + if ("class java.lang.Long".equals(xclass) || "long".equals(xclass)) { + //update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + Long temp = Long.valueOf(ExcelUtil.remove0Suffix(String.valueOf(result))); + //if(StringUtils.isNotEmpty(entity.getNumFormat())){ + // return Long.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp)); + //}else{ + return temp; + //} + //update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + } + if ("class java.lang.Float".equals(xclass) || "float".equals(xclass)) { + //update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + Float temp = Float.valueOf(String.valueOf(result)); + //if(StringUtils.isNotEmpty(entity.getNumFormat())){ + // return Float.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp)); + //}else{ + return temp; + //} + //update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + } + if ("class java.lang.Integer".equals(xclass) || "int".equals(xclass)) { + //update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + Integer temp = Integer.valueOf(ExcelUtil.remove0Suffix(String.valueOf(result))); + //if(StringUtils.isNotEmpty(entity.getNumFormat())){ + // return Integer.valueOf(new DecimalFormat(entity.getNumFormat()).format(temp)); + //}else{ + return temp; + //} + //update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + } + if ("class java.math.BigDecimal".equals(xclass)) { + //update-begin-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + BigDecimal temp = new BigDecimal(String.valueOf(result)); + //if(StringUtils.isNotEmpty(entity.getNumFormat())){ + // return new BigDecimal(new DecimalFormat(entity.getNumFormat()).format(temp)); + //}else{ + return temp; + //} + //update-end-author:taoYan date:20200319 for:Excel注解的numFormat方法似乎未实现 #970 + } + if ("class java.lang.String".equals(xclass)) { + // 针对String 类型,但是Excel获取的数据却不是String,比如Double类型,防止科学计数法 + if (result instanceof String) { + //---update-begin-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------ + return ExcelUtil.remove0Suffix(result); + //---update-end-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------ + } + // double类型防止科学计数法 + if (result instanceof Double) { + return PoiPublicUtil.doubleToString((Double) result); + } + //---update-begin-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------ + return ExcelUtil.remove0Suffix(String.valueOf(result)); + //---update-end-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------ + } + return result; + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelImportException(ExcelImportEnum.GET_VALUE_ERROR); + } + } + + /** + * 调用处理接口处理值 + * + * @param dataHanlder + * @param object + * @param result + * @param titleString + * @return + */ + private Object hanlderValue(IExcelDataHandler dataHanlder, Object object, Object result, String titleString) { + if (dataHanlder == null || dataHanlder.getNeedHandlerFields() == null || dataHanlder.getNeedHandlerFields().length == 0) { + return result; + } + if (hanlderList == null) { + hanlderList = Arrays.asList(dataHanlder.getNeedHandlerFields()); + } + if (hanlderList.contains(titleString)) { + return dataHanlder.importHandler(object, titleString, result); + } + return result; + } + + //update-begin-author:taoyan date:20180807 for:导入多值替换-- + /** + * 导入支持多值替换 + * @param replace 数据库中字典查询出来的数组 + * @param result excel单元格获取的值 + * @param multiReplace 是否支持多值替换 + * @author taoYan + * @since 2018年8月7日 + */ + private Object replaceValue(String[] replace, Object result,boolean multiReplace) { + if(result == null){ + return ""; + } + if(replace == null || replace.length<=0){ + return result; + } + String temp = String.valueOf(result); + String backValue = ""; + if(temp.indexOf(",")>0 && multiReplace){ + //原值中带有逗号,认为他是多值的 + String multiReplaces[] = temp.split(","); + for (String str : multiReplaces) { + backValue = backValue.concat(replaceSingleValue(replace, str)+","); + } + if(backValue.equals("")){ + backValue = temp; + }else{ + backValue = backValue.substring(0, backValue.length()-1); + } + }else{ + backValue = replaceSingleValue(replace, temp); + } + //update-begin-author:liusq date:20210204 for:字典替换失败提示日志 + if(replace.length>0 && backValue.equals(temp)){ + LOGGER.warn("====================字典替换失败,字典值:{},要转换的导入值:{}====================", replace, temp); + } + //update-end-author:liusq date:20210204 for:字典替换失败提示日志 + return backValue; + } + /** + * 单值替换 ,若没找到则原值返回 + */ + private String replaceSingleValue(String[] replace, String temp){ + String[] tempArr; + for (int i = 0; i < replace.length; i++) { + //update-begin---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析--- + //tempArr = replace[i].split("_"); + tempArr = getValueArr(replace[i]); + if (temp.equals(tempArr[0]) || temp.replace("_","---").equals(tempArr[0])) { + //update-begin---author:wangshuai ---date:20220422 for:导入字典替换需要将---替换成_,不然数据库会存--- ------------ + if(tempArr[1].contains("---")){ + return tempArr[1].replace("---","_"); + } + //update-end---author:wangshuai ---date:20220422 for:导入字典替换需要将---替换成_,不然数据库会存--- -------------- + return tempArr[1]; + } + //update-end---author:scott Date:20211220 for:[issues/I4MBB3]@Excel dicText字段的值有下划线时,导入功能不能正确解析--- + } + return temp; + } + //update-end-author:taoyan date:20180807 for:导入多值替换-- + + /** + * 字典文本中含多个下划线横岗,取最后一个(解决空值情况) + * + * @param val + * @return + */ + public String[] getValueArr(String val) { + int i = val.lastIndexOf("_");//最后一个分隔符的位置 + String[] c = new String[2]; + c[0] = val.substring(0, i); //label + c[1] = val.substring(i + 1); //key + return c; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/ExcelImportServer.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/ExcelImportServer.java new file mode 100644 index 0000000..7bdb7a7 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/ExcelImportServer.java @@ -0,0 +1,620 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.poifs.filesystem.FileMagic; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.formula.functions.T; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.jeecgframework.core.util.ApplicationContextUtil; +import org.jeecgframework.poi.excel.annotation.ExcelTarget; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.entity.params.ExcelCollectionParams; +import org.jeecgframework.poi.excel.entity.params.ExcelImportEntity; +import org.jeecgframework.poi.excel.entity.result.ExcelImportResult; +import org.jeecgframework.poi.excel.entity.result.ExcelVerifyHanlderResult; +import org.jeecgframework.poi.excel.imports.base.ImportBaseService; +import org.jeecgframework.poi.excel.imports.base.ImportFileServiceI; +import org.jeecgframework.poi.excel.imports.verifys.VerifyHandlerServer; +import org.jeecgframework.poi.exception.excel.ExcelImportException; +import org.jeecgframework.poi.exception.excel.enums.ExcelImportEnum; +import org.jeecgframework.poi.util.ExcelUtil; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.*; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Excel 导入服务 + * + * @author JEECG + * @date 2014年6月26日 下午9:20:51 + */ +@SuppressWarnings({ "rawtypes", "unchecked", "hiding" }) +public class ExcelImportServer extends ImportBaseService { + + private final static Logger LOGGER = LoggerFactory.getLogger(ExcelImportServer.class); + + private CellValueServer cellValueServer; + + private VerifyHandlerServer verifyHandlerServer; + + private boolean verfiyFail = false; + //仅允许字母数字字符的正则表达式 + private static final Pattern lettersAndNumbersPattern = Pattern.compile("^[a-zA-Z0-9]+$") ; + /** + * 异常数据styler + */ + private CellStyle errorCellStyle; + + public ExcelImportServer() { + this.cellValueServer = new CellValueServer(); + this.verifyHandlerServer = new VerifyHandlerServer(); + } + + /*** + * 向List里面继续添加元素 + * + * @param object + * @param param + * @param row + * @param titlemap + * @param targetId + * @param pictures + * @param params + */ + private void addListContinue(Object object, ExcelCollectionParams param, Row row, Map titlemap, String targetId, Map pictures, ImportParams params) throws Exception { + Collection collection = (Collection) PoiPublicUtil.getMethod(param.getName(), object.getClass()).invoke(object, new Object[] {}); + Object entity = PoiPublicUtil.createObject(param.getType(), targetId); + String picId; + boolean isUsed = false;// 是否需要加上这个对象 + for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++) { + Cell cell = row.getCell(i); + String titleString = (String) titlemap.get(i); + if (param.getExcelParams().containsKey(titleString)) { + if (param.getExcelParams().get(titleString).getType() == 2) { + picId = row.getRowNum() + "_" + i; + saveImage(object, picId, param.getExcelParams(), titleString, pictures, params); + } else { + saveFieldValue(params, entity, cell, param.getExcelParams(), titleString, row); + } + isUsed = true; + } + } + if (isUsed) { + collection.add(entity); + } + } + + /** + * 获取key的值,针对不同类型获取不同的值 + * + * @Author JEECG + * @date 2013-11-21 + * @param cell + * @return + */ + private String getKeyValue(Cell cell) { + if(cell==null){ + return null; + } + Object obj = null; + switch (cell.getCellType()) { + case STRING: + obj = cell.getStringCellValue(); + break; + case BOOLEAN: + obj = cell.getBooleanCellValue(); + break; + case NUMERIC: + obj = cell.getNumericCellValue(); + break; + case FORMULA: + obj = cell.getCellFormula(); + break; + } + return obj == null ? null : obj.toString().trim(); + } + + /** + * 获取保存的真实路径 + * + * @param excelImportEntity + * @param object + * @return + * @throws Exception + */ + private String getSaveUrl(ExcelImportEntity excelImportEntity, Object object) throws Exception { + String url = ""; + if (excelImportEntity.getSaveUrl().equals("upload")) { + if (excelImportEntity.getMethods() != null && excelImportEntity.getMethods().size() > 0) { + object = getFieldBySomeMethod(excelImportEntity.getMethods(), object); + } + url = object.getClass().getName().split("\\.")[object.getClass().getName().split("\\.").length - 1]; + return excelImportEntity.getSaveUrl() + "/" + url.substring(0, url.lastIndexOf("Entity")); + } + return excelImportEntity.getSaveUrl(); + } + //update-begin--Author:xuelin Date:20171205 for:TASK #2098 【excel问题】 Online 一对多导入失败-------------------- + private List importExcel(Collection result, Sheet sheet, Class pojoClass, ImportParams params, Map pictures) throws Exception { + List collection = new ArrayList(); + Map excelParams = new HashMap(); + List excelCollection = new ArrayList(); + String targetId = null; + if (!Map.class.equals(pojoClass)) { + Field fileds[] = PoiPublicUtil.getClassFields(pojoClass); + ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); + if (etarget != null) { + targetId = etarget.value(); + } + getAllExcelField(targetId, fileds, excelParams, excelCollection, pojoClass, null); + } + ignoreHeaderHandler(excelParams, params); + Iterator rows = sheet.rowIterator(); + Map titlemap = getTitleMap(sheet, rows, params, excelCollection); + //update-begin-author:liusq date:20220310 for:[issues/I4PU45]@excel里面新增属性fixedIndex + Set keys = excelParams.keySet(); + for (String key : keys) { + if (key.startsWith("FIXED_")) { + String[] arr = key.split("_"); + titlemap.put(Integer.parseInt(arr[1]), key); + } + } + //update-end-author:liusq date:20220310 for:[issues/I4PU45]@excel里面新增属性fixedIndex + Set columnIndexSet = titlemap.keySet(); + Integer maxColumnIndex = Collections.max(columnIndexSet); + Integer minColumnIndex = Collections.min(columnIndexSet); + Row row = null; + //跳过表头和标题行 + for (int j = 0; j < params.getTitleRows() + params.getHeadRows(); j++) { + row = rows.next(); + } + Object object = null; + String picId; + while (rows.hasNext() && (row == null || sheet.getLastRowNum() - row.getRowNum() > params.getLastOfInvalidRow())) { + row = rows.next(); + //update-begin--Author:xuelin Date:20171017 for:TASK #2373 【bug】表改造问题,导致 3.7.1批量导入用户bug-导入不成功-------------------- + // 判断是集合元素还是不是集合元素,如果是就继续加入这个集合,不是就创建新的对象 + //update-begin--Author:xuelin Date:20171206 for:TASK #2451 【excel导出bug】online 一对多导入成功, 但是现在代码生成后的一对多online导入有问题了 + Cell keyIndexCell = row.getCell(params.getKeyIndex()); + if (excelCollection.size()>0 && StringUtils.isEmpty(getKeyValue(keyIndexCell)) && object != null && !Map.class.equals(pojoClass)) { + //update-end--Author:xuelin Date:20171206 for:TASK #2451 【excel导出bug】online 一对多导入成功, 但是现在代码生成后的一对多online导入有问题了 + for (ExcelCollectionParams param : excelCollection) { + addListContinue(object, param, row, titlemap, targetId, pictures, params); + } + + } else { + object = PoiPublicUtil.createObject(pojoClass, targetId); + try { + //update-begin-author:taoyan date:20200303 for:导入图片 + int firstCellNum = row.getFirstCellNum(); + if(firstCellNum>minColumnIndex){ + firstCellNum = minColumnIndex; + } + int lastCellNum = row.getLastCellNum(); + if(lastCellNum excelParams,ImportParams params){ + List ignoreList = new ArrayList<>(); + for(String key:excelParams.keySet()){ + String temp = excelParams.get(key).getGroupName(); + if(temp!=null && temp.length()>0){ + ignoreList.add(temp); + } + } + params.setIgnoreHeaderList(ignoreList); + } + + /** + * 获取表格字段列名对应信息 + * + * @param rows + * @param params + * @param excelCollection + * @return + */ + private Map getTitleMap(Sheet sheet, Iterator rows, ImportParams params, List excelCollection) throws Exception { + Map titlemap = new HashMap(); + Iterator cellTitle = null; + String collectionName = null; + ExcelCollectionParams collectionParams = null; + Row headRow = null; + int headBegin = params.getTitleRows(); + //update_begin-author:taoyan date:2020622 for:当文件行数小于代码里设置的TitleRows时headRow一直为空就会出现死循环 + int allRowNum = sheet.getPhysicalNumberOfRows(); + //找到首行表头,每个sheet都必须至少有一行表头 + while(headRow == null && headBegin < allRowNum){ + headRow = sheet.getRow(headBegin++); + } + if(headRow==null){ + throw new Exception("不识别该文件"); + } + //update-end-author:taoyan date:2020622 for:当文件行数小于代码里设置的TitleRows时headRow一直为空就会出现死循环 + + //设置表头行数 + if (ExcelUtil.isMergedRegion(sheet, headRow.getRowNum(), 0)) { + params.setHeadRows(2); + }else{ + params.setHeadRows(1); + } + cellTitle = headRow.cellIterator(); + while (cellTitle.hasNext()) { + Cell cell = cellTitle.next(); + String value = getKeyValue(cell); + if (StringUtils.isNotEmpty(value)) { + titlemap.put(cell.getColumnIndex(), value);//加入表头列表 + } + } + + //多行表头 + for (int j = headBegin; j < headBegin + params.getHeadRows()-1; j++) { + headRow = sheet.getRow(j); + cellTitle = headRow.cellIterator(); + while (cellTitle.hasNext()) { + Cell cell = cellTitle.next(); + String value = getKeyValue(cell); + if (StringUtils.isNotEmpty(value)) { + int columnIndex = cell.getColumnIndex(); + //当前cell的上一行是否为合并单元格 + if(ExcelUtil.isMergedRegion(sheet, cell.getRowIndex()-1, columnIndex)){ + collectionName = ExcelUtil.getMergedRegionValue(sheet, cell.getRowIndex()-1, columnIndex); + if(params.isIgnoreHeader(collectionName)){ + titlemap.put(cell.getColumnIndex(), value); + }else{ + titlemap.put(cell.getColumnIndex(), collectionName + "_" + value); + } + }else{ + //update-begin-author:taoyan date:20220112 for: JT640 【online】导入 无论一对一还是一对多 如果子表只有一个字段 则子表无数据 + // 上一行不是合并的情况下另有一种特殊的场景: 如果当前单元格和上面的单元格同一列 即子表字段只有一个 所以标题没有出现跨列 + String prefixTitle = titlemap.get(cell.getColumnIndex()); + if(prefixTitle!=null && !"".equals(prefixTitle)){ + titlemap.put(cell.getColumnIndex(), prefixTitle + "_" +value); + }else{ + titlemap.put(cell.getColumnIndex(), value); + } + //update-end-author:taoyan date:20220112 for: JT640 【online】导入 无论一对一还是一对多 如果子表只有一个字段 则子表无数据 + } + /*int i = cell.getColumnIndex(); + // 用以支持重名导入 + if (titlemap.containsKey(i)) { + collectionName = titlemap.get(i); + collectionParams = getCollectionParams(excelCollection, collectionName); + titlemap.put(i, collectionName + "_" + value); + } else if (StringUtils.isNotEmpty(collectionName) && collectionParams.getExcelParams().containsKey(collectionName + "_" + value)) { + titlemap.put(i, collectionName + "_" + value); + } else { + collectionName = null; + collectionParams = null; + } + if (StringUtils.isEmpty(collectionName)) { + titlemap.put(i, value); + }*/ + } + } + } + return titlemap; + } + //update-end--Author:xuelin Date:20171205 for:TASK #2098 【excel问题】 Online 一对多导入失败-------------------- + /** + * 获取这个名称对应的集合信息 + * + * @param excelCollection + * @param collectionName + * @return + */ + private ExcelCollectionParams getCollectionParams(List excelCollection, String collectionName) { + for (ExcelCollectionParams excelCollectionParams : excelCollection) { + if (collectionName.equals(excelCollectionParams.getExcelName())) { + return excelCollectionParams; + } + } + return null; + } + + /** + * Excel 导入 field 字段类型 Integer,Long,Double,Date,String,Boolean + * + * @param inputstream + * @param pojoClass + * @param params + * @return + * @throws Exception + */ + public ExcelImportResult importExcelByIs(InputStream inputstream, Class pojoClass, ImportParams params) throws Exception { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Excel import start ,class is {}", pojoClass); + } + List result = new ArrayList(); + Workbook book = null; + boolean isXSSFWorkbook = false; + if (!(inputstream.markSupported())) { + inputstream = new PushbackInputStream(inputstream, 8); + } + //begin-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + //------poi4.x begin---- +// FileMagic fm = FileMagic.valueOf(FileMagic.prepareToCheckMagic(inputstream)); +// if(FileMagic.OLE2 == fm){ +// isXSSFWorkbook=false; +// } + book = WorkbookFactory.create(inputstream); + if(book instanceof XSSFWorkbook){ + isXSSFWorkbook=true; + } + LOGGER.info(" >>> poi3升级到4.0兼容改造工作, isXSSFWorkbook = " +isXSSFWorkbook); + //end-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + + //begin-------author:liusq------date:20210313-----for:-------多sheet导入改造点-------- + //获取导入文本的sheet数 + //update-begin-author:taoyan date:20211210 for:https://gitee.com/jeecg/jeecg-boot/issues/I45C32 导入空白sheet报错 + if(params.getSheetNum()==0){ + int sheetNum = book.getNumberOfSheets(); + if(sheetNum>0){ + params.setSheetNum(sheetNum); + } + } + //update-end-author:taoyan date:20211210 for:https://gitee.com/jeecg/jeecg-boot/issues/I45C32 导入空白sheet报错 + //end-------author:liusq------date:20210313-----for:-------多sheet导入改造点-------- + createErrorCellStyle(book); + Map pictures; + // 获取指定的sheet名称 + String sheetName = params.getSheetName(); + + //update-begin-author:liusq date:20220609 for:issues/I57UPC excel导入 ImportParams 中没有startSheetIndex参数 + for (int i = params.getStartSheetIndex(); i < params.getStartSheetIndex() + + params.getSheetNum(); i++) { + //update-end-author:liusq date:20220609 for:issues/I57UPC excel导入 ImportParams 中没有startSheetIndex参数 + + //update-begin-author:taoyan date:2023-3-4 for: 导入数据支持指定sheet名称 + if(sheetName!=null && !"".equals(sheetName)){ + Sheet tempSheet = book.getSheetAt(i); + if(!sheetName.equals(tempSheet.getSheetName())){ + continue; + } + } + //update-end-author:taoyan date:2023-3-4 for: 导入数据支持指定sheet名称 + + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(" start to read excel by is ,startTime is {}", System.currentTimeMillis()); + } + if (isXSSFWorkbook) { + pictures = PoiPublicUtil.getSheetPictrues07((XSSFSheet) book.getSheetAt(i), (XSSFWorkbook) book); + } else { + pictures = PoiPublicUtil.getSheetPictrues03((HSSFSheet) book.getSheetAt(i), (HSSFWorkbook) book); + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(" end to read excel by is ,endTime is {}", new Date().getTime()); + } + result.addAll(importExcel(result, book.getSheetAt(i), pojoClass, params, pictures)); + if (LOGGER.isDebugEnabled()) { + LOGGER.debug(" end to read excel list by pos ,endTime is {}", new Date().getTime()); + } + } + if (params.isNeedSave()) { + saveThisExcel(params, pojoClass, isXSSFWorkbook, book); + } + return new ExcelImportResult(result, verfiyFail, book); + } + /** + * + * @param is + * @return + * @throws IOException + */ + public static byte[] getBytes(InputStream is) throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + int len; + byte[] data = new byte[100000]; + while ((len = is.read(data, 0, data.length)) != -1) { + buffer.write(data, 0, len); + } + + buffer.flush(); + return buffer.toByteArray(); + } + + /** + * 保存字段值(获取值,校验值,追加错误信息) + * + * @param params + * @param object + * @param cell + * @param excelParams + * @param titleString + * @param row + * @throws Exception + */ + private void saveFieldValue(ImportParams params, Object object, Cell cell, Map excelParams, String titleString, Row row) throws Exception { + Object value = cellValueServer.getValue(params.getDataHanlder(), object, cell, excelParams, titleString); + if (object instanceof Map) { + if (params.getDataHanlder() != null) { + params.getDataHanlder().setMapValue((Map) object, titleString, value); + } else { + ((Map) object).put(titleString, value); + } + } else { + ExcelVerifyHanlderResult verifyResult = verifyHandlerServer.verifyData(object, value, titleString, excelParams.get(titleString).getVerify(), params.getVerifyHanlder()); + if (verifyResult.isSuccess()) { + setValues(excelParams.get(titleString), object, value); + } else { + Cell errorCell = row.createCell(row.getLastCellNum()); + errorCell.setCellValue(verifyResult.getMsg()); + errorCell.setCellStyle(errorCellStyle); + verfiyFail = true; + throw new ExcelImportException(ExcelImportEnum.VERIFY_ERROR); + } + } + } + + /** + * + * @param object + * @param picId + * @param excelParams + * @param titleString + * @param pictures + * @param params + * @throws Exception + */ + private void saveImage(Object object, String picId, Map excelParams, String titleString, Map pictures, ImportParams params) throws Exception { + if (pictures == null || pictures.get(picId)==null) { + return; + } + PictureData image = pictures.get(picId); + byte[] data = image.getData(); + String fileName = "pic" + Math.round(Math.random() * 100000000000L); + fileName += "." + PoiPublicUtil.getFileExtendName(data); + //update-beign-author:taoyan date:20200302 for:【多任务】online 专项集中问题 LOWCOD-159 + int saveType = excelParams.get(titleString).getSaveType(); + if ( saveType == 1) { + String path = PoiPublicUtil.getWebRootPath(getSaveUrl(excelParams.get(titleString), object)); + File savefile = new File(path); + if (!savefile.exists()) { + savefile.mkdirs(); + } + savefile = new File(path + "/" + fileName); + FileOutputStream fos = new FileOutputStream(savefile); + fos.write(data); + fos.close(); + setValues(excelParams.get(titleString), object, getSaveUrl(excelParams.get(titleString), object) + "/" + fileName); + } else if(saveType==2) { + setValues(excelParams.get(titleString), object, data); + } else { + ImportFileServiceI importFileService = null; + try { + importFileService = ApplicationContextUtil.getContext().getBean(ImportFileServiceI.class); + } catch (Exception e) { + System.err.println(e.getMessage()); + } + if(importFileService!=null){ + //update-beign-author:liusq date:20230411 for:【issue/4415】autopoi-web 导入图片字段时无法指定保存路径 + String saveUrl = excelParams.get(titleString).getSaveUrl(); + String dbPath; + if(StringUtils.isNotBlank(saveUrl)){ + LOGGER.debug("图片保存路径saveUrl = "+saveUrl); + Matcher matcher = lettersAndNumbersPattern.matcher(saveUrl); + if(!matcher.matches()){ + LOGGER.warn("图片保存路径格式错误,只能设置字母和数字的组合!"); + dbPath = importFileService.doUpload(data); + }else{ + dbPath = importFileService.doUpload(data,saveUrl); + } + }else{ + dbPath = importFileService.doUpload(data); + } + //update-end-author:liusq date:20230411 for:【issue/4415】autopoi-web 导入图片字段时无法指定保存路径 + setValues(excelParams.get(titleString), object, dbPath); + } + } + //update-end-author:taoyan date:20200302 for:【多任务】online 专项集中问题 LOWCOD-159 + } + + private void createErrorCellStyle(Workbook workbook) { + errorCellStyle = workbook.createCellStyle(); + Font font = workbook.createFont(); + font.setColor(Font.COLOR_RED); + errorCellStyle.setFont(font); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/base/ImportBaseService.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/base/ImportBaseService.java new file mode 100644 index 0000000..49a57bf --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/base/ImportBaseService.java @@ -0,0 +1,328 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports.base; + +import java.io.File; +import java.io.FileOutputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.Workbook; +import org.jeecgframework.core.util.ApplicationContextUtil; +import org.jeecgframework.dict.service.AutoPoiDictServiceI; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.jeecgframework.poi.excel.annotation.ExcelCollection; +import org.jeecgframework.poi.excel.annotation.ExcelEntity; +import org.jeecgframework.poi.excel.annotation.ExcelVerify; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.entity.params.ExcelCollectionParams; +import org.jeecgframework.poi.excel.entity.params.ExcelImportEntity; +import org.jeecgframework.poi.excel.entity.params.ExcelVerifyEntity; +import org.jeecgframework.poi.util.PoiPublicUtil; + +/** + * 导入基础和,普通方法和Sax共用 + * + * @author JEECG + * @date 2015年1月9日 下午10:25:53 + */ +public class ImportBaseService { + + /** + * 把这个注解解析放到类型对象中 + * + * @param targetId + * @param field + * @param excelEntity + * @param pojoClass + * @param getMethods + * @param temp + * @throws Exception + */ + public void addEntityToMap(String targetId, Field field, ExcelImportEntity excelEntity, Class pojoClass, List getMethods, Map temp) throws Exception { + Excel excel = field.getAnnotation(Excel.class); + excelEntity = new ExcelImportEntity(); + excelEntity.setType(excel.type()); + excelEntity.setSaveUrl(excel.savePath()); + excelEntity.setSaveType(excel.imageType()); + excelEntity.setReplace(excel.replace()); + excelEntity.setDatabaseFormat(excel.databaseFormat()); + excelEntity.setVerify(getImportVerify(field)); + excelEntity.setSuffix(excel.suffix()); + excelEntity.setNumFormat(excel.numFormat()); + excelEntity.setGroupName(excel.groupName()); + //update-begin-author:liusq date:20220310 for:[issues/I4PU45]@excel里面新增属性fixedIndex + excelEntity.setFixedIndex(excel.fixedIndex()); + //update-end-author:liusq date:20220310 for:[issues/I4PU45]@excel里面新增属性fixedIndex + + //update-begin-author:taoYan date:20180202 for:TASK #2067 【bug excel 问题】excel导入字典文本翻译问题 + excelEntity.setMultiReplace(excel.multiReplace()); + if(StringUtils.isNotEmpty(excel.dicCode())){ + AutoPoiDictServiceI jeecgDictService = null; + try { + jeecgDictService = ApplicationContextUtil.getContext().getBean(AutoPoiDictServiceI.class); + } catch (Exception e) { + } + if(jeecgDictService!=null){ + String[] dictReplace = jeecgDictService.queryDict(excel.dictTable(), excel.dicCode(), excel.dicText()); + if(excelEntity.getReplace()!=null && dictReplace!=null && dictReplace.length!=0){ + excelEntity.setReplace(dictReplace); + } + } + } + //update-end-author:taoYan date:20180202 for:TASK #2067 【bug excel 问题】excel导入字典文本翻译问题 + getExcelField(targetId, field, excelEntity, excel, pojoClass); + if (getMethods != null) { + List newMethods = new ArrayList(); + newMethods.addAll(getMethods); + newMethods.add(excelEntity.getMethod()); + excelEntity.setMethods(newMethods); + } + //update-begin-author:liusq date:20220310 for:[issues/I4PU45]@excel里面新增属性fixedIndex + if (excelEntity.getFixedIndex() != -1) { + temp.put("FIXED_" + excelEntity.getFixedIndex(), excelEntity); + } else { + temp.put(excelEntity.getName(), excelEntity); + } + //update-end-author:liusq date:20220310 for:[issues/I4PU45]@excel里面新增属性fixedIndex + } + + /** + * 获取导入校验参数 + * + * @param field + * @return + */ + public ExcelVerifyEntity getImportVerify(Field field) { + ExcelVerify verify = field.getAnnotation(ExcelVerify.class); + if (verify != null) { + ExcelVerifyEntity entity = new ExcelVerifyEntity(); + entity.setEmail(verify.isEmail()); + entity.setInterHandler(verify.interHandler()); + entity.setMaxLength(verify.maxLength()); + entity.setMinLength(verify.minLength()); + entity.setMobile(verify.isMobile()); + entity.setNotNull(verify.notNull()); + entity.setRegex(verify.regex()); + entity.setRegexTip(verify.regexTip()); + entity.setTel(verify.isTel()); + return entity; + } + return null; + } + + /** + * 获取需要导出的全部字段 + * + * @param targetId + * 目标ID + * @param fields + * @param excelCollection + * @throws Exception + */ + public void getAllExcelField(String targetId, Field[] fields, Map excelParams, List excelCollection, Class pojoClass, List getMethods) throws Exception { + ExcelImportEntity excelEntity = null; + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (PoiPublicUtil.isNotUserExcelUserThis(null, field, targetId)) { + continue; + } + if (PoiPublicUtil.isCollection(field.getType())) { + // 集合对象设置属性 + ExcelCollectionParams collection = new ExcelCollectionParams(); + collection.setName(field.getName()); + Map temp = new HashMap(); + ParameterizedType pt = (ParameterizedType) field.getGenericType(); + Class clz = (Class) pt.getActualTypeArguments()[0]; + collection.setType(clz); + getExcelFieldList(targetId, PoiPublicUtil.getClassFields(clz), clz, temp, null); + collection.setExcelParams(temp); + collection.setExcelName(field.getAnnotation(ExcelCollection.class).name()); + additionalCollectionName(collection); + excelCollection.add(collection); + } else if (PoiPublicUtil.isJavaClass(field)) { + addEntityToMap(targetId, field, excelEntity, pojoClass, getMethods, excelParams); + } else { + List newMethods = new ArrayList(); + if (getMethods != null) { + newMethods.addAll(getMethods); + } + newMethods.add(PoiPublicUtil.getMethod(field.getName(), pojoClass)); + //update-begin-author:taoyan date:20210531 for:excel导入支持 注解@ExcelEntity显示合并表头 + ExcelEntity excel = field.getAnnotation(ExcelEntity.class); + if(excel.show()==true){ + Map subExcelParams = new HashMap<>(); + // 这里有个设计的坑,导出的时候最后一个参数是null, 即getgetMethods获取的是空,导入的时候需要设置层级getmethod + getAllExcelField(targetId, PoiPublicUtil.getClassFields(field.getType()), subExcelParams, excelCollection, field.getType(), newMethods); + for(String key: subExcelParams.keySet()){ + excelParams.put(excel.name()+"_"+key, subExcelParams.get(key)); + } + }else{ + getAllExcelField(targetId, PoiPublicUtil.getClassFields(field.getType()), excelParams, excelCollection, field.getType(), newMethods); + } + //update-end-author:taoyan date:20210531 for:excel导入支持 注解@ExcelEntity显示合并表头 + } + } + } + + /** + * 追加集合名称到前面 + * + * @param collection + */ + private void additionalCollectionName(ExcelCollectionParams collection) { + Set keys = new HashSet(); + keys.addAll(collection.getExcelParams().keySet()); + for (String key : keys) { + collection.getExcelParams().put(collection.getExcelName() + "_" + key, collection.getExcelParams().get(key)); + collection.getExcelParams().remove(key); + } + } + + public void getExcelField(String targetId, Field field, ExcelImportEntity excelEntity, Excel excel, Class pojoClass) throws Exception { + excelEntity.setName(getExcelName(excel.name(), targetId)); + String fieldname = field.getName(); + //update-begin-author:taoyan for:TASK #2798 【例子】导入扩展方法,支持自定义导入字段转换规则 + excelEntity.setMethod(PoiPublicUtil.getMethod(fieldname, pojoClass, field.getType(),excel.importConvert())); + //update-end-author:taoyan for:TASK #2798 【例子】导入扩展方法,支持自定义导入字段转换规则 + if (StringUtils.isNotEmpty(excel.importFormat())) { + excelEntity.setFormat(excel.importFormat()); + } else { + excelEntity.setFormat(excel.format()); + } + } + + public void getExcelFieldList(String targetId, Field[] fields, Class pojoClass, Map temp, List getMethods) throws Exception { + ExcelImportEntity excelEntity = null; + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + if (PoiPublicUtil.isNotUserExcelUserThis(null, field, targetId)) { + continue; + } + if (PoiPublicUtil.isJavaClass(field)) { + addEntityToMap(targetId, field, excelEntity, pojoClass, getMethods, temp); + } else { + List newMethods = new ArrayList(); + if (getMethods != null) { + newMethods.addAll(getMethods); + } + newMethods.add(PoiPublicUtil.getMethod(field.getName(), pojoClass, field.getType())); + getExcelFieldList(targetId, PoiPublicUtil.getClassFields(field.getType()), field.getType(), temp, newMethods); + } + } + } + + /** + * 判断在这个单元格显示的名称 + * + * @param exportName + * @param targetId + * @return + */ + public String getExcelName(String exportName, String targetId) { + if (exportName.indexOf("_") < 0) { + return exportName; + } + if (StringUtils.isBlank(targetId)) { + return exportName; + } + String[] arr = exportName.split(","); + for (String str : arr) { + if (str.indexOf(targetId) != -1) { + //update-begin-author:liusq date:20210127 for:targetId问题处理 + //return str.split("_")[0]; + return str.replace("_"+targetId,""); + //update-end-author:liusq date:20210127 for:targetId问题处理 + } + } + return null; + } + + public Object getFieldBySomeMethod(List list, Object t) throws Exception { + Method m; + for (int i = 0; i < list.size() - 1; i++) { + m = list.get(i); + t = m.invoke(t, new Object[] {}); + } + return t; + } + + public void saveThisExcel(ImportParams params, Class pojoClass, boolean isXSSFWorkbook, Workbook book) throws Exception { + String path = PoiPublicUtil.getWebRootPath(getSaveExcelUrl(params, pojoClass)); + File savefile = new File(path); + if (!savefile.exists()) { + savefile.mkdirs(); + } + SimpleDateFormat format = new SimpleDateFormat("yyyMMddHHmmss"); + FileOutputStream fos = new FileOutputStream(path + "/" + format.format(new Date()) + "_" + Math.round(Math.random() * 100000) + (isXSSFWorkbook == true ? ".xlsx" : ".xls")); + book.write(fos); + fos.close(); + } + + /** + * 获取保存的Excel 的真实路径 + * + * @param params + * @param pojoClass + * @return + * @throws Exception + */ + public String getSaveExcelUrl(ImportParams params, Class pojoClass) throws Exception { + String url = ""; + if (params.getSaveUrl().equals("upload/excelUpload")) { + url = pojoClass.getName().split("\\.")[pojoClass.getName().split("\\.").length - 1]; + return params.getSaveUrl() + "/" + url; + } + return params.getSaveUrl(); + } + + /** + * 多个get 最后再set + * + * @param setMethods + * @param object + */ + public void setFieldBySomeMethod(List setMethods, Object object, Object value) throws Exception { + Object t = getFieldBySomeMethod(setMethods, object); + setMethods.get(setMethods.size() - 1).invoke(t, value); + } + + /** + * + * @param entity + * @param object + * @param value + * @throws Exception + */ + public void setValues(ExcelImportEntity entity, Object object, Object value) throws Exception { + if (entity.getMethods() != null) { + setFieldBySomeMethod(entity.getMethods(), object, value); + } else { + entity.getMethod().invoke(object, value); + } + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/base/ImportFileServiceI.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/base/ImportFileServiceI.java new file mode 100644 index 0000000..0797a18 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/base/ImportFileServiceI.java @@ -0,0 +1,20 @@ +package org.jeecgframework.poi.excel.imports.base; + +public interface ImportFileServiceI { + + /** + * 上传文件 返回文件地址字符串 + * @param data + * @return + */ + String doUpload(byte[] data); + + /** + * 上传文件 返回文件地址字符串 + * @param data + * @param saveUrl 保存路径 + * @return + */ + String doUpload(byte[] data,String saveUrl); + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/package-info.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/package-info.java new file mode 100644 index 0000000..ec96ca8 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/package-info.java @@ -0,0 +1,6 @@ +/** + * 导入类 + * @author JEECG + * @date 2014年6月23日 下午11:05:59 + */ +package org.jeecgframework.poi.excel.imports; \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/SaxReadExcel.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/SaxReadExcel.java new file mode 100644 index 0000000..3f16c69 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/SaxReadExcel.java @@ -0,0 +1,91 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports.sax; + +import java.io.InputStream; +import java.util.Iterator; +import java.util.List; + +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.xssf.eventusermodel.XSSFReader; +import org.apache.poi.xssf.model.SharedStringsTable; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.imports.sax.parse.ISaxRowRead; +import org.jeecgframework.poi.excel.imports.sax.parse.SaxRowRead; +import org.jeecgframework.poi.exception.excel.ExcelImportException; +import org.jeecgframework.poi.handler.inter.IExcelReadRowHanlder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.XMLReaderFactory; + +/** + * 基于SAX Excel大数据读取,读取Excel 07版本,不支持图片读取 + * + * @author JEECG + * @date 2014年12月29日 下午9:41:38 + * @version 1.0 + */ +@SuppressWarnings("rawtypes") +public class SaxReadExcel { + + private static final Logger LOGGER = LoggerFactory.getLogger(SaxReadExcel.class); + + public List readExcel(InputStream inputstream, Class pojoClass, ImportParams params, ISaxRowRead rowRead, IExcelReadRowHanlder hanlder) { + try { + OPCPackage opcPackage = OPCPackage.open(inputstream); + return readExcel(opcPackage, pojoClass, params, rowRead, hanlder); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelImportException(e.getMessage()); + } + } + + private List readExcel(OPCPackage opcPackage, Class pojoClass, ImportParams params, ISaxRowRead rowRead, IExcelReadRowHanlder hanlder) { + try { + XSSFReader xssfReader = new XSSFReader(opcPackage); + SharedStringsTable sst = (SharedStringsTable) xssfReader.getSharedStringsTable(); + if (rowRead == null) { + rowRead = new SaxRowRead(pojoClass, params, hanlder); + } + XMLReader parser = fetchSheetParser(sst, rowRead); + Iterator sheets = xssfReader.getSheetsData(); + int sheetIndex = 0; + while (sheets.hasNext() && sheetIndex < params.getSheetNum()) { + sheetIndex++; + InputStream sheet = sheets.next(); + InputSource sheetSource = new InputSource(sheet); + parser.parse(sheetSource); + sheet.close(); + } + return rowRead.getList(); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelImportException("SAX导入数据失败"); + } + } + + private XMLReader fetchSheetParser(SharedStringsTable sst, ISaxRowRead rowRead) throws SAXException { + XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser"); + ContentHandler handler = new SheetHandler(sst, rowRead); + parser.setContentHandler(handler); + return parser; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/SheetHandler.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/SheetHandler.java new file mode 100644 index 0000000..893a99e --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/SheetHandler.java @@ -0,0 +1,136 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports.sax; + +import java.math.BigDecimal; +import java.util.Date; +import java.util.List; + +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.xssf.model.SharedStringsTable; +import org.apache.poi.xssf.usermodel.XSSFRichTextString; +import org.jeecgframework.poi.excel.entity.enmus.CellValueType; +import org.jeecgframework.poi.excel.entity.sax.SaxReadCellEntity; +import org.jeecgframework.poi.excel.imports.sax.parse.ISaxRowRead; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import com.google.common.collect.Lists; + +/** + * 回调接口 + * + * @author JEECG + * @date 2014年12月29日 下午9:50:09 + */ +public class SheetHandler extends DefaultHandler { + + private SharedStringsTable sst; + private String lastContents; + + // 当前行 + private int curRow = 0; + // 当前列 + private int curCol = 0; + + private CellValueType type; + + private ISaxRowRead read; + + // 存储行记录的容器 + private List rowlist = Lists.newArrayList(); + + public SheetHandler(SharedStringsTable sst, ISaxRowRead rowRead) { + this.sst = sst; + this.read = rowRead; + } + + @Override + public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { + // 置空 + lastContents = ""; + // c => 单元格 + if ("c".equals(name)) { + // 如果下一个元素是 SST 的索引,则将nextIsString标记为true + String cellType = attributes.getValue("t"); + if ("s".equals(cellType)) { + type = CellValueType.String; + return; + } + // 日期格式 + cellType = attributes.getValue("s"); + if ("1".equals(cellType)) { + type = CellValueType.Date; + } else if ("2".equals(cellType)) { + type = CellValueType.Number; + } + } else if ("t".equals(name)) {// 当元素为t时 + type = CellValueType.TElement; + } + + } + + @Override + public void endElement(String uri, String localName, String name) throws SAXException { + + // 根据SST的索引值的到单元格的真正要存储的字符串 + // 这时characters()方法可能会被调用多次 + if (CellValueType.String.equals(type)) { + try { + int idx = Integer.parseInt(lastContents); + lastContents = sst.getItemAt(idx).getString(); + } catch (Exception e) { + + } + } + // t元素也包含字符串 + if (CellValueType.TElement.equals(type)) { + String value = lastContents.trim(); + rowlist.add(curCol, new SaxReadCellEntity(CellValueType.String, value)); + curCol++; + type = CellValueType.None; + // v => 单元格的值,如果单元格是字符串则v标签的值为该字符串在SST中的索引 + // 将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符 + } else if ("v".equals(name)) { + String value = lastContents.trim(); + value = value.equals("") ? " " : value; + if (CellValueType.Date.equals(type)) { + Date date = DateUtil.getJavaDate(Double.valueOf(value)); + rowlist.add(curCol, new SaxReadCellEntity(CellValueType.Date, date)); + } else if (CellValueType.Number.equals(type)) { + BigDecimal bd = new BigDecimal(value); + rowlist.add(curCol, new SaxReadCellEntity(CellValueType.Number, bd)); + } else if (CellValueType.String.equals(type)) { + rowlist.add(curCol, new SaxReadCellEntity(CellValueType.String, value)); + } + curCol++; + } else if (name.equals("row")) {// 如果标签名称为 row ,这说明已到行尾,调用 optRows() 方法 + read.parse(curRow, rowlist); + rowlist.clear(); + curRow++; + curCol = 0; + } + + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + // 得到单元格内容的值 + lastContents += new String(ch, start, length); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/parse/ISaxRowRead.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/parse/ISaxRowRead.java new file mode 100644 index 0000000..3eb73d0 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/parse/ISaxRowRead.java @@ -0,0 +1,39 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports.sax.parse; + +import java.util.List; + +import org.jeecgframework.poi.excel.entity.sax.SaxReadCellEntity; + +public interface ISaxRowRead { + /** + * 获取返回数据 + * + * @param + * @return + */ + public List getList(); + + /** + * 解析数据 + * + * @param index + * @param datas + */ + public void parse(int index, List datas); + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/parse/SaxRowRead.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/parse/SaxRowRead.java new file mode 100644 index 0000000..f26806e --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/sax/parse/SaxRowRead.java @@ -0,0 +1,213 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports.sax.parse; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.jeecgframework.poi.excel.annotation.ExcelTarget; +import org.jeecgframework.poi.excel.entity.ImportParams; +import org.jeecgframework.poi.excel.entity.params.ExcelCollectionParams; +import org.jeecgframework.poi.excel.entity.params.ExcelImportEntity; +import org.jeecgframework.poi.excel.entity.sax.SaxReadCellEntity; +import org.jeecgframework.poi.excel.imports.CellValueServer; +import org.jeecgframework.poi.excel.imports.base.ImportBaseService; +import org.jeecgframework.poi.exception.excel.ExcelImportException; +import org.jeecgframework.poi.handler.inter.IExcelReadRowHanlder; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.google.common.collect.Lists; + +/** + * 当行读取数据 + * + * @author JEECG + * @param + * @date 2015年1月1日 下午7:59:39 + */ +@SuppressWarnings({ "rawtypes", "unchecked" }) +public class SaxRowRead extends ImportBaseService implements ISaxRowRead { + + private static final Logger LOGGER = LoggerFactory.getLogger(SaxRowRead.class); + /** 需要返回的数据 **/ + private List list; + /** 导出的对象 **/ + private Class pojoClass; + /** 导入参数 **/ + private ImportParams params; + /** 列表头对应关系 **/ + private Map titlemap = new HashMap(); + /** 当前的对象 **/ + private Object object = null; + + private Map excelParams = new HashMap(); + + private List excelCollection = new ArrayList(); + + private String targetId; + + private CellValueServer cellValueServer; + + private IExcelReadRowHanlder hanlder; + + public SaxRowRead(Class pojoClass, ImportParams params, IExcelReadRowHanlder hanlder) { + list = Lists.newArrayList(); + this.params = params; + this.pojoClass = pojoClass; + cellValueServer = new CellValueServer(); + this.hanlder = hanlder; + initParams(pojoClass, params); + } + + private void initParams(Class pojoClass, ImportParams params) { + try { + + Field fileds[] = PoiPublicUtil.getClassFields(pojoClass); + ExcelTarget etarget = pojoClass.getAnnotation(ExcelTarget.class); + if (etarget != null) { + targetId = etarget.value(); + } + getAllExcelField(targetId, fileds, excelParams, excelCollection, pojoClass, null); + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelImportException(e.getMessage()); + } + + } + + @Override + public List getList() { + return list; + } + + @Override + public void parse(int index, List datas) { + try { + if (datas == null || datas.size() == 0) { + return; + } + // 标题行跳过 + if (index < params.getTitleRows()) { + return; + } + // 表头行 + if (index < params.getTitleRows() + params.getHeadRows()) { + addHeadData(datas); + } else { + addListData(datas); + } + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new ExcelImportException(e.getMessage()); + } + } + + /** + * 集合元素处理 + * + * @param datas + */ + private void addListData(List datas) throws Exception { + // 判断是集合元素还是不是集合元素,如果是就继续加入这个集合,不是就创建新的对象 + if ((datas.get(params.getKeyIndex()) == null || StringUtils.isEmpty(String.valueOf(datas.get(params.getKeyIndex()).getValue()))) && object != null) { + for (ExcelCollectionParams param : excelCollection) { + addListContinue(object, param, datas, titlemap, targetId, params); + } + } else { + if (object != null && hanlder != null) { + hanlder.hanlder(object); + } + object = PoiPublicUtil.createObject(pojoClass, targetId); + SaxReadCellEntity entity; + for (int i = 0, le = datas.size(); i < le; i++) { + entity = datas.get(i); + String titleString = (String) titlemap.get(i); + if (excelParams.containsKey(titleString)) { + saveFieldValue(params, object, entity, excelParams, titleString); + } + } + for (ExcelCollectionParams param : excelCollection) { + addListContinue(object, param, datas, titlemap, targetId, params); + } + if (hanlder == null) { + list.add(object); + } + } + + } + + /*** + * 向List里面继续添加元素 + * + * @param exclusions + * @param object + * @param param + * @param datas + * @param titlemap + * @param targetId + * @param params + */ + private void addListContinue(Object object, ExcelCollectionParams param, List datas, Map titlemap, String targetId, ImportParams params) throws Exception { + Collection collection = (Collection) PoiPublicUtil.getMethod(param.getName(), object.getClass()).invoke(object, new Object[] {}); + Object entity = PoiPublicUtil.createObject(param.getType(), targetId); + boolean isUsed = false;// 是否需要加上这个对象 + for (int i = 0; i < datas.size(); i++) { + String titleString = (String) titlemap.get(i); + if (param.getExcelParams().containsKey(titleString)) { + saveFieldValue(params, entity, datas.get(i), param.getExcelParams(), titleString); + isUsed = true; + } + } + if (isUsed) { + collection.add(entity); + } + } + + /** + * 设置值 + * + * @param params + * @param object + * @param entity + * @param excelParams + * @param titleString + * @throws Exception + */ + private void saveFieldValue(ImportParams params, Object object, SaxReadCellEntity entity, Map excelParams, String titleString) throws Exception { + Object value = cellValueServer.getValue(params.getDataHanlder(), object, entity, excelParams, titleString); + setValues(excelParams.get(titleString), object, value); + } + + /** + * put 表头数据 + * + * @param datas + */ + private void addHeadData(List datas) { + for (int i = 0; i < datas.size(); i++) { + if (StringUtils.isNotEmpty(String.valueOf(datas.get(i).getValue()))) { + titlemap.put(i, String.valueOf(datas.get(i).getValue())); + } + } + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/verifys/BaseVerifyHandler.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/verifys/BaseVerifyHandler.java new file mode 100644 index 0000000..1aa3e08 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/verifys/BaseVerifyHandler.java @@ -0,0 +1,145 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports.verifys; + +import java.util.regex.Pattern; + +import org.jeecgframework.poi.excel.entity.result.ExcelVerifyHanlderResult; + +/** + * 基础校验工具类 + * + * @author JEECG + * @date 2014年6月23日 下午11:10:12 + */ +public class BaseVerifyHandler { + + private static String NOT_NULL = "不允许为空"; + private static String IS_MOBILE = "不是手机号"; + private static String IS_TEL = "不是电话号码"; + private static String IS_EMAIL = "不是邮箱地址"; + private static String MIN_LENGHT = "小于规定长度"; + private static String MAX_LENGHT = "超过规定长度"; + + private static Pattern mobilePattern = Pattern.compile("^[1][3,4,5,8,7][0-9]{9}$"); + + private static Pattern telPattern = Pattern.compile("^([0][1-9]{2,3}-)?[0-9]{5,10}$"); + + private static Pattern emailPattern = Pattern.compile("^([a-zA-Z0-9]+[_|\\_|\\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\\_|\\.]?)*[a-zA-Z0-9]+\\.[a-zA-Z]{2,3}$"); + + /** + * email校验 + * + * @param name + * @param val + * @return + */ + public static ExcelVerifyHanlderResult isEmail(String name, Object val) { + if (!emailPattern.matcher(String.valueOf(val)).matches()) { + return new ExcelVerifyHanlderResult(false, name + IS_EMAIL); + } + return new ExcelVerifyHanlderResult(true); + } + + /** + * 手机校验 + * + * @param name + * @param val + * @return + */ + public static ExcelVerifyHanlderResult isMobile(String name, Object val) { + if (!mobilePattern.matcher(String.valueOf(val)).matches()) { + return new ExcelVerifyHanlderResult(false, name + IS_MOBILE); + } + return new ExcelVerifyHanlderResult(true); + } + + /** + * 电话校验 + * + * @param name + * @param val + * @return + */ + public static ExcelVerifyHanlderResult isTel(String name, Object val) { + if (!telPattern.matcher(String.valueOf(val)).matches()) { + return new ExcelVerifyHanlderResult(false, name + IS_TEL); + } + return new ExcelVerifyHanlderResult(true); + } + + /** + * 最大长度校验 + * + * @param name + * @param val + * @return + */ + public static ExcelVerifyHanlderResult maxLength(String name, Object val, int maxLength) { + if (notNull(name, val).isSuccess() && String.valueOf(val).length() > maxLength) { + return new ExcelVerifyHanlderResult(false, name + MAX_LENGHT); + } + return new ExcelVerifyHanlderResult(true); + } + + /** + * 最小长度校验 + * + * @param name + * @param val + * @param minLength + * @return + */ + public static ExcelVerifyHanlderResult minLength(String name, Object val, int minLength) { + if (notNull(name, val).isSuccess() && String.valueOf(val).length() < minLength) { + return new ExcelVerifyHanlderResult(false, name + MIN_LENGHT); + } + return new ExcelVerifyHanlderResult(true); + } + + /** + * 非空校验 + * + * @param name + * @param val + * @return + */ + public static ExcelVerifyHanlderResult notNull(String name, Object val) { + if (val == null || val.toString().equals("")) { + return new ExcelVerifyHanlderResult(false, name + NOT_NULL); + } + return new ExcelVerifyHanlderResult(true); + } + + /** + * 正则表达式校验 + * + * @param name + * @param val + * @param regex + * @param regexTip + * @return + */ + public static ExcelVerifyHanlderResult regex(String name, Object val, String regex, String regexTip) { + Pattern pattern = Pattern.compile(regex); + if (!pattern.matcher(String.valueOf(val)).matches()) { + return new ExcelVerifyHanlderResult(false, name + regexTip); + } + return new ExcelVerifyHanlderResult(true); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/verifys/VerifyHandlerServer.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/verifys/VerifyHandlerServer.java new file mode 100644 index 0000000..1d9bcfc --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/excel/imports/verifys/VerifyHandlerServer.java @@ -0,0 +1,81 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.excel.imports.verifys; + +import org.apache.commons.lang3.StringUtils; +import org.jeecgframework.poi.excel.entity.params.ExcelVerifyEntity; +import org.jeecgframework.poi.excel.entity.result.ExcelVerifyHanlderResult; +import org.jeecgframework.poi.handler.inter.IExcelVerifyHandler; + +/** + * 校验服务 + * + * @author JEECG + * @date 2014年6月29日 下午4:37:56 + */ +public class VerifyHandlerServer { + + private final static ExcelVerifyHanlderResult DEFAULT_RESULT = new ExcelVerifyHanlderResult(true); + + private void addVerifyResult(ExcelVerifyHanlderResult hanlderResult, ExcelVerifyHanlderResult result) { + if (!hanlderResult.isSuccess()) { + result.setSuccess(false); + result.setMsg((StringUtils.isEmpty(result.getMsg()) ? "" : result.getMsg() + " , ") + hanlderResult.getMsg()); + } + } + + /** + * 校驗數據 + * + * @param object + * @param value + * @param titleString + * @param verify + * @param excelVerifyHandler + */ + public ExcelVerifyHanlderResult verifyData(Object object, Object value, String name, ExcelVerifyEntity verify, IExcelVerifyHandler excelVerifyHandler) { + if (verify == null) { + return DEFAULT_RESULT; + } + ExcelVerifyHanlderResult result = new ExcelVerifyHanlderResult(true, ""); + if (verify.isNotNull()) { + addVerifyResult(BaseVerifyHandler.notNull(name, value), result); + } + if (verify.isEmail()) { + addVerifyResult(BaseVerifyHandler.isEmail(name, value), result); + } + if (verify.isMobile()) { + addVerifyResult(BaseVerifyHandler.isMobile(name, value), result); + } + if (verify.isTel()) { + addVerifyResult(BaseVerifyHandler.isTel(name, value), result); + } + if (verify.getMaxLength() != -1) { + addVerifyResult(BaseVerifyHandler.maxLength(name, value, verify.getMaxLength()), result); + } + if (verify.getMinLength() != -1) { + addVerifyResult(BaseVerifyHandler.minLength(name, value, verify.getMinLength()), result); + } + if (StringUtils.isNotEmpty(verify.getRegex())) { + addVerifyResult(BaseVerifyHandler.regex(name, value, verify.getRegex(), verify.getRegexTip()), result); + } + if (verify.isInterHandler()) { + addVerifyResult(excelVerifyHandler.verifyHandler(object, name, value), result); + } + return result; + + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/ExcelExportException.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/ExcelExportException.java new file mode 100644 index 0000000..d932e60 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/ExcelExportException.java @@ -0,0 +1,62 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.exception.excel; + +import org.jeecgframework.poi.exception.excel.enums.ExcelExportEnum; + +/** + * 导出异常 + * + * @author JEECG + * @date 2014年6月19日 下午10:56:18 + */ +public class ExcelExportException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private ExcelExportEnum type; + + public ExcelExportException() { + super(); + } + + public ExcelExportException(ExcelExportEnum type) { + super(type.getMsg()); + this.type = type; + } + + public ExcelExportException(ExcelExportEnum type, Throwable cause) { + super(type.getMsg(), cause); + } + + public ExcelExportException(String message) { + super(message); + } + + public ExcelExportException(String message, ExcelExportEnum type) { + super(message); + this.type = type; + } + + public ExcelExportEnum getType() { + return type; + } + + public void setType(ExcelExportEnum type) { + this.type = type; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/ExcelImportException.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/ExcelImportException.java new file mode 100644 index 0000000..62dd608 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/ExcelImportException.java @@ -0,0 +1,62 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.exception.excel; + +import org.jeecgframework.poi.exception.excel.enums.ExcelImportEnum; + +/** + * 导入异常 + * + * @author JEECG + * @date 2014年6月29日 下午2:23:43 + */ +public class ExcelImportException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + private ExcelImportEnum type; + + public ExcelImportException() { + super(); + } + + public ExcelImportException(ExcelImportEnum type) { + super(type.getMsg()); + this.type = type; + } + + public ExcelImportException(ExcelImportEnum type, Throwable cause) { + super(type.getMsg(), cause); + } + + public ExcelImportException(String message) { + super(message); + } + + public ExcelImportException(String message, ExcelImportEnum type) { + super(message); + this.type = type; + } + + public ExcelImportEnum getType() { + return type; + } + + public void setType(ExcelImportEnum type) { + this.type = type; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/enums/ExcelExportEnum.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/enums/ExcelExportEnum.java new file mode 100644 index 0000000..a1be14b --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/enums/ExcelExportEnum.java @@ -0,0 +1,42 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.exception.excel.enums; + +/** + * 导出异常类型枚举 + * + * @author JEECG + * @date 2014年6月19日 下午10:59:51 + */ +public enum ExcelExportEnum { + + PARAMETER_ERROR("Excel 导出 参数错误"), EXPORT_ERROR("Excel导出错误"),TEMPLATE_ERROR ("Excel 模板错误");; + + private String msg; + + ExcelExportEnum(String msg) { + this.msg = msg; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/enums/ExcelImportEnum.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/enums/ExcelImportEnum.java new file mode 100644 index 0000000..9987d57 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/excel/enums/ExcelImportEnum.java @@ -0,0 +1,42 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.exception.excel.enums; + +/** + * 导出异常类型枚举 + * + * @author JEECG + * @date 2014年6月19日 下午10:59:51 + */ +public enum ExcelImportEnum { + + GET_VALUE_ERROR("Excel 值获取失败"), VERIFY_ERROR("值校验失败"); + + private String msg; + + ExcelImportEnum(String msg) { + this.msg = msg; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/word/WordExportException.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/word/WordExportException.java new file mode 100644 index 0000000..abb7feb --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/word/WordExportException.java @@ -0,0 +1,42 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.exception.word; + +import org.jeecgframework.poi.exception.word.enmus.WordExportEnum; + +/** + * word导出异常 + * + * @author JEECG + * @date 2014年8月9日 下午10:32:51 + */ +public class WordExportException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public WordExportException() { + super(); + } + + public WordExportException(String msg) { + super(msg); + } + + public WordExportException(WordExportEnum exception) { + super(exception.getMsg()); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/word/enmus/WordExportEnum.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/word/enmus/WordExportEnum.java new file mode 100644 index 0000000..54f067e --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/exception/word/enmus/WordExportEnum.java @@ -0,0 +1,42 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.exception.word.enmus; + +/** + * 导出异常枚举 + * + * @author JEECG + * @date 2014年8月9日 下午10:34:58 + */ +public enum WordExportEnum { + + EXCEL_PARAMS_ERROR("Excel 导出 参数错误"), EXCEL_HEAD_HAVA_NULL("Excel 表头 有的字段为空"), EXCEL_NO_HEAD("Excel 没有表头"); + + private String msg; + + WordExportEnum(String msg) { + this.msg = msg; + } + + public String getMsg() { + return msg; + } + + public void setMsg(String msg) { + this.msg = msg; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/impl/ExcelDataHandlerDefaultImpl.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/impl/ExcelDataHandlerDefaultImpl.java new file mode 100644 index 0000000..272879d --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/impl/ExcelDataHandlerDefaultImpl.java @@ -0,0 +1,64 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.handler.impl; + +import java.util.Map; + +import org.jeecgframework.poi.handler.inter.IExcelDataHandler; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.Hyperlink; +/** + * 数据处理默认实现,返回空 + * + * @author JEECG + * @date 2014年6月20日 上午12:11:52 + */ +public abstract class ExcelDataHandlerDefaultImpl implements IExcelDataHandler { + /** + * 需要处理的字段 + */ + private String[] needHandlerFields; + + @Override + public Object exportHandler(Object obj, String name, Object value) { + return value; + } + + @Override + public String[] getNeedHandlerFields() { + return needHandlerFields; + } + + @Override + public Object importHandler(Object obj, String name, Object value) { + return value; + } + + @Override + public void setNeedHandlerFields(String[] needHandlerFields) { + this.needHandlerFields = needHandlerFields; + } + + @Override + public void setMapValue(Map map, String originKey, Object value) { + map.put(originKey, value); + } + + @Override + public Hyperlink getHyperlink(CreationHelper creationHelper, Object obj, String name, Object value) { + return null; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/impl/package-info.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/impl/package-info.java new file mode 100644 index 0000000..0991683 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/impl/package-info.java @@ -0,0 +1,6 @@ +/** + * 对接口的抽象的默认实现,避免用户实现过多方法 + * @author JEECG + * @date 2014年6月20日 上午12:09:27 + */ +package org.jeecgframework.poi.handler.impl; \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelDataHandler.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelDataHandler.java new file mode 100644 index 0000000..0a5e8c8 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelDataHandler.java @@ -0,0 +1,87 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.handler.inter; + +import java.util.Map; +import org.apache.poi.ss.usermodel.CreationHelper; +import org.apache.poi.ss.usermodel.Hyperlink; +/** + * Excel 导入导出 数据处理接口 + * + * @author JEECG + * @date 2014年6月19日 下午11:59:45 + */ +public interface IExcelDataHandler { + + /** + * 导出处理方法 + * + * @param obj + * 当前对象 + * @param name + * 当前字段名称 + * @param value + * 当前值 + * @return + */ + public Object exportHandler(Object obj, String name, Object value); + + /** + * 获取需要处理的字段,导入和导出统一处理了, 减少书写的字段 + * + * @return + */ + public String[] getNeedHandlerFields(); + + /** + * 导入处理方法 当前对象,当前字段名称,当前值 + * + * @param obj + * 当前对象 + * @param name + * 当前字段名称 + * @param value + * 当前值 + * @return + */ + public Object importHandler(Object obj, String name, Object value); + + /** + * 设置需要处理的属性列表 + * + * @param fields + */ + public void setNeedHandlerFields(String[] fields); + + /** + * 设置Map导入,自定义 put + * + * @param map + * @param originKey + * @param value + */ + public void setMapValue(Map map, String originKey, Object value); + /** + * 获取这个字段的 Hyperlink ,07版本需要,03版本不需要 + * @param creationHelper + * @param obj + * @param name + * @param value + * @return + */ + public Hyperlink getHyperlink(CreationHelper creationHelper, Object obj, String name, Object value); + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelDictHandler.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelDictHandler.java new file mode 100644 index 0000000..8e2a043 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelDictHandler.java @@ -0,0 +1,32 @@ +package org.jeecgframework.poi.handler.inter; + +/** + * 字典翻译处理 + * @author liusq + * @date 2022-05-27 + */ +public interface IExcelDictHandler { + + /** + * 从值翻译到名称 + * + * @param dict 字典Key + * @param obj 对象 + * @param name 属性名称 + * @param value 属性值 + * @return + */ + public String toName(String dict, Object obj, String name, Object value); + + /** + * 从名称翻译到值 + * + * @param dict 字典Key + * @param obj 对象 + * @param name 属性名称 + * @param value 属性值 + * @return + */ + public String toValue(String dict, Object obj, String name, Object value); + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelExportServer.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelExportServer.java new file mode 100644 index 0000000..5df525f --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelExportServer.java @@ -0,0 +1,21 @@ +package org.jeecgframework.poi.handler.inter; + +import java.util.List; + +/** + * 导出数据接口 + * @Description [LOWCOD-2521]【autopoi】大数据导出方法【全局】 + * @author liusq + * @date 2022年1月4号 + */ +public interface IExcelExportServer { + /** + * 查询数据接口 + * + * @param queryParams 查询条件 + * @param page 当前页数从1开始 + * @data 2022年1月4号 + * @return + */ + public List selectListForExcelExport(Object queryParams, int page); +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelReadRowHanlder.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelReadRowHanlder.java new file mode 100644 index 0000000..90b9aa9 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelReadRowHanlder.java @@ -0,0 +1,33 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.handler.inter; + +/** + * 接口自定义处理类 + * + * @author JEECG + * @date 2015年1月16日 下午8:06:26 + * @param + */ +public interface IExcelReadRowHanlder { + /** + * 处理解析对象 + * + * @param t + */ + public void hanlder(T t); + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelVerifyHandler.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelVerifyHandler.java new file mode 100644 index 0000000..6ce3115 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IExcelVerifyHandler.java @@ -0,0 +1,55 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.handler.inter; + +import org.jeecgframework.poi.excel.entity.result.ExcelVerifyHanlderResult; + +/** + * 导入校验接口 + * + * @author JEECG + * @date 2014年6月23日 下午11:08:21 + */ +public interface IExcelVerifyHandler { + + /** + * 获取需要处理的字段,导入和导出统一处理了, 减少书写的字段 + * + * @return + */ + public String[] getNeedVerifyFields(); + + /** + * 获取需要处理的字段,导入和导出统一处理了, 减少书写的字段 + * + * @return + */ + public void setNeedVerifyFields(String[] arr); + + /** + * 导出处理方法 + * + * @param obj + * 当前对象 + * @param name + * 当前字段名称 + * @param value + * 当前值 + * @return + */ + public ExcelVerifyHanlderResult verifyHandler(Object obj, String name, Object value); + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IWriter.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IWriter.java new file mode 100644 index 0000000..aa01360 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/inter/IWriter.java @@ -0,0 +1,35 @@ +package org.jeecgframework.poi.handler.inter; + +import java.util.Collection; +/** + * 大数据写出服务接口 + * + * @Description [LOWCOD-2521]【autopoi】大数据导出方法【全局】 + * @author liusq + * @date 2022年1月4号 + */ +public interface IWriter { + /** + * 获取输出对象 + * + * @return + */ + default public T get() { + return null; + } + + /** + * 写入数据 + * + * @param data + * @return + */ + public IWriter write(Collection data); + + /** + * 关闭流,完成业务 + * + * @return + */ + public T close(); +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/package-info.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/package-info.java new file mode 100644 index 0000000..f9dc007 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/handler/package-info.java @@ -0,0 +1,6 @@ +/** + * 数据处理中心,对导入导出进行数据处理 + * @author JEECG + * @date 2014年6月20日 上午12:08:09 + */ +package org.jeecgframework.poi.handler; \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/package-info.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/package-info.java new file mode 100644 index 0000000..8ba0ad3 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/package-info.java @@ -0,0 +1,13 @@ +/** + * @author JEECG + * @date 2014年2月10日 + * @version 1.0 + * 对POI进行封装,通过注解的使用,完成POI的简易重复操作 + * 通过模板完成较为复杂的操作 + * 进阶步骤:
+ *

1.了解注解,图片类

+ *

2.模板语言

+ *

3.模板组合

+ * + */ +package org.jeecgframework.poi; \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/ExcelUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/ExcelUtil.java new file mode 100644 index 0000000..49826f2 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/ExcelUtil.java @@ -0,0 +1,327 @@ +package org.jeecgframework.poi.util; +/** + * @author Link Xue + * @version 20171025 + * POI对EXCEL操作工具 + */ + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.poi.EncryptedDocumentException; +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.*; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; +import org.apache.poi.ss.util.CellRangeAddress; + +public class ExcelUtil { + + public static void main(String[] args){ + //读取excel数据 + ArrayList> result = ExcelUtil.readExcelToObj("D:\\上传表.xlsx"); + for(Map map:result){ + System.out.println(map); + } + + } + /** + * 读取excel数据 + * @param path + */ + public static ArrayList> readExcelToObj(String path) { + + Workbook wb = null; + ArrayList> result = null; + try { + wb = WorkbookFactory.create(new File(path)); + result = readExcel(wb, 0, 2, 0); + } catch (Exception e) { + e.printStackTrace(); + } + return result; + } + + /** + * 读取excel文件 + * @param wb + * @param sheetIndex sheet页下标:从0开始 + * @param startReadLine 开始读取的行:从0开始 + * @param tailLine 去除最后读取的行 + */ + public static ArrayList> readExcel(Workbook wb,int sheetIndex, int startReadLine, int tailLine) { + Sheet sheet = wb.getSheetAt(sheetIndex); + Row row = null; + ArrayList> result = new ArrayList>(); + for(int i=startReadLine; i map = new HashMap(); + for(Cell c : row) { + String returnStr = ""; + + boolean isMerge = isMergedRegion(sheet, i, c.getColumnIndex()); + //判断是否具有合并单元格 + if(isMerge) { + String rs = getMergedRegionValue(sheet, row.getRowNum(), c.getColumnIndex()); +// System.out.print(rs + "------ "); + returnStr = rs; + }else { +// System.out.print(c.getRichStringCellValue()+"++++ "); + returnStr = c.getRichStringCellValue().getString(); + } + if(c.getColumnIndex()==0){ + map.put("id",returnStr); + }else if(c.getColumnIndex()==1){ + map.put("base",returnStr); + }else if(c.getColumnIndex()==2){ + map.put("siteName",returnStr); + }else if(c.getColumnIndex()==3){ + map.put("articleName",returnStr); + }else if(c.getColumnIndex()==4){ + map.put("mediaName",returnStr); + }else if(c.getColumnIndex()==5){ + map.put("mediaUrl",returnStr); + }else if(c.getColumnIndex()==6){ + map.put("newsSource",returnStr); + }else if(c.getColumnIndex()==7){ + map.put("isRecord",returnStr); + }else if(c.getColumnIndex()==8){ + map.put("recordTime",returnStr); + }else if(c.getColumnIndex()==9){ + map.put("remark",returnStr); + } + + } + result.add(map); +// System.out.println(); + + } + return result; + + } + + /** + * 获取合并单元格的值 + * @param sheet + * @param row + * @param column + * @return + */ + public static String getMergedRegionValue(Sheet sheet ,int row , int column){ + int sheetMergeCount = sheet.getNumMergedRegions(); + + for(int i = 0 ; i < sheetMergeCount ; i++){ + CellRangeAddress ca = sheet.getMergedRegion(i); + int firstColumn = ca.getFirstColumn(); + int lastColumn = ca.getLastColumn(); + int firstRow = ca.getFirstRow(); + int lastRow = ca.getLastRow(); + + if(row >= firstRow && row <= lastRow){ + + if(column >= firstColumn && column <= lastColumn){ + Row fRow = sheet.getRow(firstRow); + Cell fCell = fRow.getCell(firstColumn); + return getCellValue(fCell) ; + } + } + } + + return null ; + } + + /** + * 判断合并了行 + * @param sheet + * @param row + * @param column + * @return + */ + public static boolean isMergedRow(Sheet sheet,int row ,int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress range = sheet.getMergedRegion(i); + int firstColumn = range.getFirstColumn(); + int lastColumn = range.getLastColumn(); + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + if(row == firstRow && row == lastRow){ + if(column >= firstColumn && column <= lastColumn){ + return true; + } + } + } + return false; + } + + /** + * 判断指定的单元格是否是合并单元格 + * @param sheet + * @param row 行下标 + * @param column 列下标 + * @return + */ + public static boolean isMergedRegion(Sheet sheet,int row ,int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress range = sheet.getMergedRegion(i); + int firstColumn = range.getFirstColumn(); + int lastColumn = range.getLastColumn(); + int firstRow = range.getFirstRow(); + int lastRow = range.getLastRow(); + if(row >= firstRow && row <= lastRow){ + if(column >= firstColumn && column <= lastColumn){ + return true; + } + } + } + return false; + } + + /** + * 判断sheet页中是否含有合并单元格 + * @param sheet + * @return + */ + public static boolean hasMerged(Sheet sheet) { + return sheet.getNumMergedRegions() > 0 ? true : false; + } + + /** + * 合并单元格 + * @param sheet + * @param firstRow 开始行 + * @param lastRow 结束行 + * @param firstCol 开始列 + * @param lastCol 结束列 + */ + public static void mergeRegion(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) { + //update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + try{ + sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); + }catch (IllegalArgumentException e){ + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + } + + /** + * 获取单元格的值 + * @param cell + * @return + */ + public static String getCellValue(Cell cell){ + + if(cell == null) { + return ""; + } + + if(cell.getCellType() == CellType.STRING){ + + return cell.getStringCellValue(); + + }else if(cell.getCellType() == CellType.BOOLEAN){ + + return String.valueOf(cell.getBooleanCellValue()); + + }else if(cell.getCellType() == CellType.FORMULA){ + + return cell.getCellFormula() ; + + }else if(cell.getCellType() == CellType.NUMERIC){ + + return String.valueOf(cell.getNumericCellValue()); + + } + return ""; + } + + /** + * 数字值,去掉.0后缀 + * @param cell + * @return + */ + public static String remove0Suffix(Object value){ + if(value!=null) { + // update-begin-author:taoyan date:20210526 for:对于特殊的字符串 V1.0 也进行了去.0操作 这是不合理的 + String val = value.toString(); + if(val.endsWith(".0") && isNumberString(val)) { + val = val.replace(".0", ""); + } + // update-end-author:taoyan date:20210526 for:对于特殊的字符串 V1.0 也进行了去.0操作 这是不合理的 + return val; + } + return null; + } + + /** + * 判断给定的字符串是不是只有数字 + * @param str + * @return + */ + private static boolean isNumberString(String str){ + String regex = "^[0-9]+\\.0+$"; + Pattern pattern = Pattern.compile(regex); + Matcher m = pattern.matcher(str); + if (m.find()) { + return true; + } + return false; + } + + /** + * 从excel读取内容 + */ + public static void readContent(String fileName) { + boolean isE2007 = false; //判断是否是excel2007格式 + if(fileName.endsWith("xlsx")) + isE2007 = true; + try { + InputStream input = new FileInputStream(fileName); //建立输入流 + Workbook wb = null; + //根据文件格式(2003或者2007)来初始化 + if(isE2007) + wb = new XSSFWorkbook(input); + else + wb = new HSSFWorkbook(input); + Sheet sheet = wb.getSheetAt(0); //获得第一个表单 + Iterator rows = sheet.rowIterator(); //获得第一个表单的迭代器 + while (rows.hasNext()) { + Row row = rows.next(); //获得行数据 + System.out.println("Row #" + row.getRowNum()); //获得行号从0开始 + Iterator cells = row.cellIterator(); //获得第一行的迭代器 + while (cells.hasNext()) { + Cell cell = cells.next(); + System.out.println("Cell #" + cell.getColumnIndex()); + switch (cell.getCellType()) { //根据cell中的类型来输出数据 + case NUMERIC: + System.out.println(cell.getNumericCellValue()); + break; + case STRING: + System.out.println(cell.getStringCellValue()); + break; + case BOOLEAN: + System.out.println(cell.getBooleanCellValue()); + break; + case FORMULA: + System.out.println(cell.getCellFormula()); + break; + default: + System.out.println("unsuported sell type======="+cell.getCellType()); + break; + } + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/MyX509TrustManager.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/MyX509TrustManager.java new file mode 100644 index 0000000..c0b8bd1 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/MyX509TrustManager.java @@ -0,0 +1,30 @@ +package org.jeecgframework.poi.util; + +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; + +import javax.net.ssl.X509TrustManager; + +/** + * https请求用到 + */ +public class MyX509TrustManager implements X509TrustManager{ + + @Override + public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { + // TODO Auto-generated method stub + } + + @Override + public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { + // TODO Auto-generated method stub + + } + + @Override + public X509Certificate[] getAcceptedIssuers() { + // TODO Auto-generated method stub + return null; + } + +} \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiCellUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiCellUtil.java new file mode 100644 index 0000000..dc769cc --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiCellUtil.java @@ -0,0 +1,134 @@ +/** + * + */ +package org.jeecgframework.poi.util; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; + +/** + * 处理单元格的数值 + * @Description [LOWCOD-2521]【autopoi】大数据导出方法【全局】 + * @author liusq + * @date 2022年1月4号 + */ +public class PoiCellUtil { + /** + * 读取单元格的值 + * + * @param sheet + * @param row + * @param column + * @return + */ + public static String getCellValue(Sheet sheet, int row, int column) { + String value = null; + if (isMergedRegion(sheet, row, column)) { + value = getMergedRegionValue(sheet, row, column); + } else { + Row rowData = sheet.getRow(row); + Cell cell = rowData.getCell(column); + value = getCellValue(cell); + } + return value; + } + + /** + * 获取合并单元格的值 + * + * @param sheet + * @param row + * @param column + * @return + */ + public static String getMergedRegionValue(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress ca = sheet.getMergedRegion(i); + int firstColumn = ca.getFirstColumn(); + int lastColumn = ca.getLastColumn(); + int firstRow = ca.getFirstRow(); + int lastRow = ca.getLastRow(); + + if (row >= firstRow && row <= lastRow) { + + if (column >= firstColumn && column <= lastColumn) { + Row fRow = sheet.getRow(firstRow); + Cell fCell = fRow.getCell(firstColumn); + + return getCellValue(fCell); + } + } + } + + return null; + } + + /** + * 判断指定的单元格是否是合并单元格 + * + * @param sheet + * @param row + * @param column + * @return + */ + public static boolean isMergedRegion(Sheet sheet, int row, int column) { + int sheetMergeCount = sheet.getNumMergedRegions(); + + for (int i = 0; i < sheetMergeCount; i++) { + CellRangeAddress ca = sheet.getMergedRegion(i); + int firstColumn = ca.getFirstColumn(); + int lastColumn = ca.getLastColumn(); + int firstRow = ca.getFirstRow(); + int lastRow = ca.getLastRow(); + + if (row >= firstRow && row <= lastRow) { + if (column >= firstColumn && column <= lastColumn) { + + return true; + } + } + } + + return false; + } + + /** + * 获取单元格的值 + * _NONE(-1), + * NUMERIC(0), + * STRING(1), + * FORMULA(2), + * BLANK(3), + * BOOLEAN(4), + * ERROR(5); + * @param cell + * @return + */ + public static String getCellValue(Cell cell) { + if (cell == null) { + return ""; + } + if (cell.getCellType() == CellType.STRING) { + return cell.getStringCellValue(); + } else if (cell.getCellType() == CellType.BOOLEAN) { + return String.valueOf(cell.getBooleanCellValue()); + } else if (cell.getCellType() == CellType.FORMULA) { + try { + return cell.getCellFormula(); + } catch (Exception e) { + return String.valueOf(cell.getNumericCellValue()); + } + } else if (cell.getCellType() == CellType.NUMERIC) { + return String.valueOf(cell.getNumericCellValue()); + } else if (cell.getCellType() == CellType.ERROR) { + return String.valueOf(cell.getErrorCellValue()); + } + return ""; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiElUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiElUtil.java new file mode 100644 index 0000000..34ae560 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiElUtil.java @@ -0,0 +1,278 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.util; + +import java.util.Collection; +import java.util.Map; + +import org.jeecgframework.poi.exception.excel.ExcelExportException; + +/** + * AutoPoi的el 表达式支持工具类 + * + * @author JEECG + * @date 2015年4月25日 下午12:13:21 + */ +public final class PoiElUtil { + + public static final String LENGTH = "le:"; + public static final String FOREACH = "fe:"; + public static final String FOREACH_NOT_CREATE = "!fe:"; + public static final String FOREACH_AND_SHIFT = "$fe:"; + public static final String FOREACH_COL = "#fe:"; + public static final String FOREACH_COL_VALUE = "v_fe:"; + public static final String START_STR = "{{"; + public static final String END_STR = "}}"; + public static final String WRAP = "]]"; + public static final String NUMBER_SYMBOL = "n:"; + public static final String FORMAT_DATE = "fd:"; + public static final String FORMAT_NUMBER = "fn:"; + public static final String IF_DELETE = "!if:"; + public static final String EMPTY = ""; + public static final String CONST = "'"; + public static final String NULL = "&NULL&"; + public static final String LEFT_BRACKET = "("; + public static final String RIGHT_BRACKET = ")"; + public static final String DICT_HANDLER = "dict:"; + + private PoiElUtil() { + } + + /** + * 解析字符串,支持 le,fd,fn,!if,三目 + * + * @param obj + * @param map + * @return + * @throws Exception + */ + public static Object eval(String text, Map map) throws Exception { + String tempText = new String(text); + Object obj = innerEval(text, map); + // 如果没有被处理而且这个值找map中存在就处理这个值 + if (tempText.equals(obj.toString()) && map.containsKey(tempText.split("\\.")[0])) { + return PoiPublicUtil.getParamsValue(tempText, map); + } + return obj; + } + + /** + * 解析字符串,支持 le,fd,fn,!if,三目 + * + * @param obj + * @param map + * @return + * @throws Exception + */ + public static Object innerEval(String text, Map map) throws Exception { + if (text.indexOf("?") != -1 && text.indexOf(":") != -1) { + return trinocular(text, map); + } + if (text.indexOf(LENGTH) != -1) { + return length(text, map); + } + if (text.indexOf(FORMAT_DATE) != -1) { + return formatDate(text, map); + } + if (text.indexOf(FORMAT_NUMBER) != -1) { + return formatNumber(text, map); + } + if (text.indexOf(IF_DELETE) != -1) { + return ifDelete(text, map); + } + if (text.startsWith("'")) { + return text.replace("'", ""); + } + return text; + } + + /** + * 是不是删除列 + * + * @param text + * @param map + * @return + * @throws Exception + */ + private static Object ifDelete(String text, Map map) throws Exception { + // 把多个空格变成一个空格 + text = text.replaceAll("\\s{1,}", " ").trim(); + String[] keys = getKey(IF_DELETE, text).split(" "); + text = text.replace(IF_DELETE, EMPTY); + return isTrue(keys, map); + } + + /** + * 是不是真 + * 这个方法两个地方用到 + * 1.三目表达式的判断,表达式需要设置空格 {{field == 1? field1:field2 }} 或者 {{field?field1:field2 }} + * 2.取非表达式(判断为真则当前excel的一整列会被干掉) {{!if:(field == 1)}} 或者 {{!if:(field)}} + * + * 如果字段field本身就能判断true或者false 他会走len==1的逻辑处理 + * 如果字段field需要结合其他固定值来判断true或者false 那么记住一定要再表达式里打空格 然后他会split空格 走len==3的逻辑处理 + * @param keys + * @param map + * @return + * @throws Exception + */ + private static Boolean isTrue(String[] keys, Map map) throws Exception { + //update-author:taoyan date:20200622 for:此处判断len当为1 + if (keys.length == 1) { + String constant = null; + if ((constant = isConstant(keys[0])) != null) { + return Boolean.valueOf(constant); + } + return Boolean.valueOf(PoiPublicUtil.getParamsValue(keys[0], map).toString()); + } + if (keys.length == 3) { + if(keys[0]==null || keys[2]==null){ + return false; + } + Object first = String.valueOf(eval(keys[0], map)); + Object second = String.valueOf(eval(keys[2], map)); + return PoiFunctionUtil.isTrue(first, keys[1], second); + } + throw new ExcelExportException("判断参数不对"); + } + + /** + * 判断是不是常量 + * + * @param string + * @return + */ + private static String isConstant(String param) { + if (param.indexOf("'") != -1) { + return param.replace("'", ""); + } + return null; + } + + /** + * 格式化数字 + * + * @param text + * @param map + * @return + * @throws Exception + */ + private static Object formatNumber(String text, Map map) throws Exception { + String[] key = getKey(FORMAT_NUMBER, text).split(";"); + text = text.replace(FORMAT_NUMBER, EMPTY); + return innerEval(replacinnerEvalue(text, PoiFunctionUtil.formatNumber(PoiPublicUtil.getParamsValue(key[0], map), key[1])), map); + } + + /** + * 格式化时间 + * + * @param text + * @param map + * @return + * @throws Exception + */ + private static Object formatDate(String text, Map map) throws Exception { + String[] key = getKey(FORMAT_DATE, text).split(";"); + text = text.replace(FORMAT_DATE, EMPTY); + return innerEval(replacinnerEvalue(text, PoiFunctionUtil.formatDate(PoiPublicUtil.getParamsValue(key[0], map), key[1])), map); + } + + /** + * 计算这个的长度 + * + * @param text + * @param map + * @throws Exception + */ + private static Object length(String text, Map map) throws Exception { + String key = getKey(LENGTH, text); + text = text.replace(LENGTH, EMPTY); + Object val = PoiPublicUtil.getParamsValue(key, map); + return innerEval(replacinnerEvalue(text, PoiFunctionUtil.length(val)), map); + } + + private static String replacinnerEvalue(String text, Object val) { + StringBuilder sb = new StringBuilder(); + sb.append(text.substring(0, text.indexOf(LEFT_BRACKET))); + sb.append(" "); + sb.append(val); + sb.append(" "); + sb.append(text.substring(text.indexOf(RIGHT_BRACKET) + 1, text.length())); + return sb.toString().trim(); + } + + private static String getKey(String prefix, String text) { + int leftBracket = 1, rigthBracket = 0, position = 0; + int index = text.indexOf(prefix) + prefix.length(); + while (text.charAt(index) == " ".charAt(0)) { + text = text.substring(0, index) + text.substring(index + 1, text.length()); + } + for (int i = text.indexOf(prefix + LEFT_BRACKET) + prefix.length() + 1; i < text.length(); i++) { + if (text.charAt(i) == LEFT_BRACKET.charAt(0)) { + leftBracket++; + } + if (text.charAt(i) == RIGHT_BRACKET.charAt(0)) { + rigthBracket++; + } + if (leftBracket == rigthBracket) { + position = i; + break; + } + } + return text.substring(text.indexOf(prefix + LEFT_BRACKET) + 1 + prefix.length(), position).trim(); + } + + public static void main(String[] args) { + System.out.println(getKey(IF_DELETE, "测试 " + IF_DELETE + " (小明)")); + } + + /** + * 三目运算 + * + * @return + * @throws Exception + */ + private static Object trinocular(String text, Map map) throws Exception { + // 把多个空格变成一个空格 + text = text.replaceAll("\\s{1,}", " ").trim(); + String testText = text.substring(0, text.indexOf("?")); + text = text.substring(text.indexOf("?") + 1, text.length()).trim(); + text = innerEval(text, map).toString(); + String[] keys = text.split(":"); + Object first = eval(keys[0].trim(), map); + Object second = eval(keys[1].trim(), map); + return isTrue(testText.split(" "), map) ? first : second; + } + + /** + * 解析字符串, 不支持 le,fd,fn,!if,三目 ,获取是集合的字段前缀 + * + * @param text + * @param map + * @return + * @throws Exception + */ + public static String evalFindName(String text, Map map) throws Exception { + String[] keys = text.split("\\."); + StringBuilder sb = new StringBuilder().append(keys[0]); + for (int i = 1; i < keys.length; i++) { + sb.append(".").append(keys[i]); + if (eval(sb.toString(), map) instanceof Collection) { + return sb.toString(); + } + } + return null; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiExcelGraphDataUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiExcelGraphDataUtil.java new file mode 100644 index 0000000..3e5c8a8 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiExcelGraphDataUtil.java @@ -0,0 +1,58 @@ +package org.jeecgframework.poi.util; + +import org.apache.poi.ss.usermodel.Drawing; +import org.apache.poi.ss.usermodel.Sheet; +import org.jeecgframework.poi.excel.graph.entity.ExcelGraph; +import org.jeecgframework.poi.excel.graph.entity.ExcelGraphElement; + +import java.util.List; + +/** + * 构建特殊数据结构 + * @Description [LOWCOD-2521]【autopoi】大数据导出方法【全局】 + * @author liusq + * @date 2022年1月4号 + */ +public class PoiExcelGraphDataUtil { + /** + * 构建获取数据最后行数 并写入到定义对象中 + * @param dataSourceSheet + * @param graph + */ + public static void buildGraphData(Sheet dataSourceSheet, ExcelGraph graph) { + if (graph != null && graph.getCategory() != null && graph.getValueList() != null + && graph.getValueList().size() > 0) { + graph.getCategory().setEndRowNum(dataSourceSheet.getLastRowNum()); + for (ExcelGraphElement e : graph.getValueList()) { + if (e != null) { + e.setEndRowNum(dataSourceSheet.getLastRowNum()); + } + } + } + } + + /** + * 构建多个图形对象 + * @param dataSourceSheet + * @param graphList + */ + public static void buildGraphData(Sheet dataSourceSheet, List graphList) { + if (graphList != null && graphList.size() > 0) { + for (ExcelGraph graph : graphList) { + buildGraphData(dataSourceSheet, graph); + } + } + } + + /** + * 获取画布,没有就创建一个 + * @param sheet + * @return + */ + public static Drawing getDrawingPatriarch(Sheet sheet){ + if(sheet.getDrawingPatriarch() == null){ + sheet.createDrawingPatriarch(); + } + return sheet.getDrawingPatriarch(); + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiExcelTempUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiExcelTempUtil.java new file mode 100644 index 0000000..4f3ba0f --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiExcelTempUtil.java @@ -0,0 +1,102 @@ +package org.jeecgframework.poi.util; + +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ss.usermodel.*; + +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * poi 4.0 07版本在 shift操作下有bug,不移动了单元格以及单元格样式,没有移动cell + * cell还是复用的原理的cell,导致wb输出的时候没有输出值 + * 等待修复的时候删除这个问题 + * + * @author by jueyue on 19-6-17. + */ +public class PoiExcelTempUtil { + + /** + * 把这N行的数据,cell重新设置下,修复因为shift的浅复制问题,导致文本不显示的错误 + * + * @param sheet + * @param startRow + * @param endRow + */ + public static void reset(Sheet sheet, int startRow, int endRow) { + if (sheet.getWorkbook() instanceof HSSFWorkbook) { + return; + } + for (int i = startRow; i <= endRow; i++) { + Row row = sheet.getRow(i); + if (row == null) { + continue; + } + int cellNum = row.getLastCellNum(); + for (int j = 0; j < cellNum; j++) { + if (row.getCell(j) == null) { + continue; + } + Map map = copyCell(row.getCell(j)); + row.removeCell(row.getCell(j)); + Cell cell = row.createCell(j); + cell.setCellStyle((CellStyle) map.get("cellStyle")); + if ((boolean) map.get("isDate")) { + cell.setCellValue((Date) map.get("value")); + } else { + CellType cellType = (CellType) map.get("cellType"); + switch (cellType) { + case NUMERIC: + cell.setCellValue((double) map.get("value")); + break; + case STRING: + cell.setCellValue((String) map.get("value")); + case FORMULA: + break; + case BLANK: + break; + case BOOLEAN: + cell.setCellValue((boolean) map.get("value")); + case ERROR: + break; + } + } + } + } + + } + + private static Map copyCell(Cell cell) { + Map map = new HashMap<>(); + map.put("cellType", cell.getCellType()); + map.put("isDate", CellType.NUMERIC == cell.getCellType() && DateUtil.isCellDateFormatted(cell)); + map.put("value", getValue(cell)); + map.put("cellStyle", cell.getCellStyle()); + return map; + } + + private static Object getValue(Cell cell) { + if (CellType.NUMERIC == cell.getCellType() && DateUtil.isCellDateFormatted(cell)) { + return cell.getDateCellValue(); + } + switch (cell.getCellType()) { + case _NONE: + return null; + case NUMERIC: + return cell.getNumericCellValue(); + case STRING: + return cell.getStringCellValue(); + case FORMULA: + return cell.getCellFormula(); + case BLANK: + break; + case BOOLEAN: + return cell.getBooleanCellValue(); + case ERROR: + break; + } + return null; + } + + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiFunctionUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiFunctionUtil.java new file mode 100644 index 0000000..d279ef1 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiFunctionUtil.java @@ -0,0 +1,167 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.util; + +import java.lang.reflect.Array; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Collection; +import java.util.Map; + +import org.jeecgframework.poi.exception.excel.ExcelExportException; + +/** + * if else,length,for each,fromatNumber,formatDate 满足模板的 el 表达式支持 + * + * @author JEECG + * @date 2015年4月24日 下午8:04:02 + */ +public final class PoiFunctionUtil { + + private static final String TWO_DECIMAL_STR = "###.00"; + private static final String THREE_DECIMAL_STR = "###.000"; + + private static final DecimalFormat TWO_DECIMAL = new DecimalFormat(TWO_DECIMAL_STR); + private static final DecimalFormat THREE_DECIMAL = new DecimalFormat(THREE_DECIMAL_STR); + + private static final String DAY_STR = "yyyy-MM-dd"; + private static final String TIME_STR = "yyyy-MM-dd HH:mm:ss"; + private static final String TIME__NO_S_STR = "yyyy-MM-dd HH:mm"; + + private static final SimpleDateFormat DAY_FORMAT = new SimpleDateFormat(DAY_STR); + private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat(TIME_STR); + private static final SimpleDateFormat TIME__NO_S_FORMAT = new SimpleDateFormat(TIME__NO_S_STR); + + private PoiFunctionUtil() { + } + + /** + * 获取对象的长度 + * + * @param obj + * @return + */ + @SuppressWarnings("rawtypes") + public static int length(Object obj) { + if (obj == null) { + return 0; + } + if (obj instanceof Map) { + return ((Map) obj).size(); + } + if (obj instanceof Collection) { + return ((Collection) obj).size(); + } + if (obj.getClass().isArray()) { + return Array.getLength(obj); + } + return String.valueOf(obj).length(); + } + + /** + * 格式化数字 + * + * @param obj + * @throws NumberFormatException + * @return + */ + public static String formatNumber(Object obj, String format) { + if (obj == null || obj.toString() == "") { + return ""; + } + double number = Double.valueOf(obj.toString()); + DecimalFormat decimalFormat = null; + if (TWO_DECIMAL.equals(format)) { + decimalFormat = TWO_DECIMAL; + } else if (THREE_DECIMAL_STR.equals(format)) { + decimalFormat = THREE_DECIMAL; + } else { + decimalFormat = new DecimalFormat(format); + } + return decimalFormat.format(number); + } + + /** + * 格式化时间 + * + * @param obj + * @return + */ + public static String formatDate(Object obj, String format) { + if (obj == null || obj.toString() == "") { + return ""; + } + SimpleDateFormat dateFormat = null; + if (DAY_STR.equals(format)) { + dateFormat = DAY_FORMAT; + } else if (TIME_STR.equals(format)) { + dateFormat = TIME_FORMAT; + } else if (TIME__NO_S_STR.equals(format)) { + dateFormat = TIME__NO_S_FORMAT; + } else { + dateFormat = new SimpleDateFormat(format); + } + return dateFormat.format(obj); + } + + /** + * 判断是不是成功 + * + * @param first + * @param operator + * @param second + * @return + */ + public static boolean isTrue(Object first, String operator, Object second) { + if (">".endsWith(operator)) { + return isGt(first, second); + } else if ("<".endsWith(operator)) { + return isGt(second, first); + } else if ("==".endsWith(operator)) { + if (first != null && second != null) { + return first.equals(second); + } + return first == second; + } else if ("!=".endsWith(operator)) { + if (first != null && second != null) { + return !first.equals(second); + } + return first != second; + } else { + throw new ExcelExportException("占不支持改操作符"); + } + } + + /** + * 前者是不是大于后者 + * + * @param first + * @param second + * @return + */ + private static boolean isGt(Object first, Object second) { + if (first == null || first.toString() == "") { + return false; + } + if (second == null || second.toString() == "") { + return true; + } + double one = Double.valueOf(first.toString()); + double two = Double.valueOf(second.toString()); + return one > two; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiMergeCellUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiMergeCellUtil.java new file mode 100644 index 0000000..8f49f62 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiMergeCellUtil.java @@ -0,0 +1,238 @@ +package org.jeecgframework.poi.util; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.util.CellRangeAddress; +import org.jeecgframework.poi.excel.entity.params.MergeEntity; +import org.jeecgframework.poi.exception.excel.ExcelExportException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 纵向合并单元格工具类 + * + * @author JEECG + * @date 2015年6月21日 上午11:21:40 + */ +public final class PoiMergeCellUtil { + private final static Logger LOGGER = LoggerFactory.getLogger(PoiMergeCellUtil.class); + private PoiMergeCellUtil() { + } + + /** + * 纵向合并相同内容的单元格 + * + * @param sheet + * @param startRow + * 开始行 + * @param columns + * 需要处理的列 + */ + public static void mergeCells(Sheet sheet, int startRow, Integer... columns) { + if (columns == null) { + throw new ExcelExportException("至少需要处理1列"); + } + Map mergeMap = new HashMap(); + for (int i = 0; i < columns.length; i++) { + mergeMap.put(columns[i], null); + } + mergeCells(sheet, mergeMap, startRow, sheet.getLastRowNum()); + } + + /** + * 纵向合并相同内容的单元格 + * + * @param sheet + * @param mergeMap + * key--列,value--依赖的列,没有传空 + * @param startRow + * 开始行 + */ + public static void mergeCells(Sheet sheet, Map mergeMap, int startRow) { + mergeCells(sheet, mergeMap, startRow, sheet.getLastRowNum()); + } + + /** + * 纵向合并相同内容的单元格 + * + * @param sheet + * @param mergeMap + * key--列,value--依赖的列,没有传空 + * @param startRow + * 开始行 + * @param endRow + * 结束行 + */ + public static void mergeCells(Sheet sheet, Map mergeMap, int startRow, int endRow) { + Map mergeDataMap = new HashMap(); + if (mergeMap.size() == 0) { + return; + } + Row row; + Set sets = mergeMap.keySet(); + String text; + for (int i = startRow; i <= endRow; i++) { + row = sheet.getRow(i); + for (Integer index : sets) { + if (row == null || row.getCell(index) == null) { + if (mergeDataMap.get(index) == null) { + continue; + } + if (mergeDataMap.get(index).getEndRow() == 0) { + mergeDataMap.get(index).setEndRow(i - 1); + } + } else { + text = row.getCell(index).getStringCellValue(); + if (StringUtils.isNotEmpty(text)) { + hanlderMergeCells(index, i, text, mergeDataMap, sheet, row.getCell(index), mergeMap.get(index)); + } else { + mergeCellOrContinue(index, mergeDataMap, sheet); + } + } + } + } + if (mergeDataMap.size() > 0) { + for (Integer index : mergeDataMap.keySet()) { + //update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + try{ + sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), mergeDataMap.get(index).getEndRow(), index, index)); + }catch (IllegalArgumentException e){ + LOGGER.error("合并单元格错误日志:"+e.getMessage()); + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + } + } + + } + + /** + * 处理合并单元格 + * + * @param index + * @param rowNum + * @param text + * @param mergeDataMap + * @param sheet + * @param cell + * @param delys + */ + private static void hanlderMergeCells(Integer index, int rowNum, String text, Map mergeDataMap, Sheet sheet, Cell cell, int[] delys) { + if (mergeDataMap.containsKey(index)) { + if (checkIsEqualByCellContents(mergeDataMap.get(index), text, cell, delys, rowNum)) { + mergeDataMap.get(index).setEndRow(rowNum); + } else { + //update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + try{ + sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), mergeDataMap.get(index).getEndRow(), index, index)); + }catch (IllegalArgumentException e){ + LOGGER.error("合并单元格错误日志:"+e.getMessage()); + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + mergeDataMap.put(index, createMergeEntity(text, rowNum, cell, delys)); + } + } else { + mergeDataMap.put(index, createMergeEntity(text, rowNum, cell, delys)); + } + } + + /** + * 字符为空的情况下判断 + * + * @param index + * @param mergeDataMap + * @param sheet + */ + private static void mergeCellOrContinue(Integer index, Map mergeDataMap, Sheet sheet) { + if (mergeDataMap.containsKey(index) && mergeDataMap.get(index).getEndRow() != mergeDataMap.get(index).getStartRow()) { + //update-begin-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + try{ + sheet.addMergedRegion(new CellRangeAddress(mergeDataMap.get(index).getStartRow(), mergeDataMap.get(index).getEndRow(), index, index)); + }catch (IllegalArgumentException e){ + LOGGER.error("合并单元格错误日志:"+e.getMessage()); + e.fillInStackTrace(); + } + //update-end-author:wangshuai date:20201118 for:一对多导出needMerge 子表数据对应数量小于2时报错 github#1840、gitee I1YH6B + mergeDataMap.remove(index); + } + } + + private static MergeEntity createMergeEntity(String text, int rowNum, Cell cell, int[] delys) { + MergeEntity mergeEntity = new MergeEntity(text, rowNum, rowNum); + // 存在依赖关系 + if (delys != null && delys.length != 0) { + List list = new ArrayList(delys.length); + mergeEntity.setRelyList(list); + for (int i = 0; i < delys.length; i++) { + list.add(getCellNotNullText(cell, delys[i], rowNum)); + } + } + return mergeEntity; + } + + private static boolean checkIsEqualByCellContents(MergeEntity mergeEntity, String text, Cell cell, int[] delys, int rowNum) { + // 没有依赖关系 + if (delys == null || delys.length == 0) { + return mergeEntity.getText().equals(text); + } + // 存在依赖关系 + if (mergeEntity.getText().equals(text)) { + for (int i = 0; i < delys.length; i++) { + if (!getCellNotNullText(cell, delys[i], rowNum).equals(mergeEntity.getRelyList().get(i))) { + return false; + } + } + return true; + } + return false; + } + + /** + * 获取一个单元格的值,确保这个单元格必须有值,不然向上查询 + * + * @param cell + * @param index + * @param rowNum + * @return + */ + private static String getCellNotNullText(Cell cell, int index, int rowNum) { + String temp = cell.getRow().getCell(index).getStringCellValue(); + while (StringUtils.isEmpty(temp)) { + temp = cell.getRow().getSheet().getRow(--rowNum).getCell(index).getStringCellValue(); + } + return temp; + } + //update-begin---author:liusq Date:20220104 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + /** + *处理合并的单元格区域 + * @param sheet + * @param firstRow 开始行 + * @param lastRow 结束行 + * @param firstCol 开始列 + * @param lastCol 结束列 + * @date 2022年1月4号 + */ + public static void addMergedRegion(Sheet sheet, int firstRow, int lastRow, int firstCol, int lastCol) { + try { + //添加合并的单元格区域 + sheet.addMergedRegion(new CellRangeAddress(firstRow, lastRow, firstCol, lastCol)); + } catch (Exception e) { + LOGGER.debug("发生了一次合并单元格错误,{},{},{},{}", new Integer[]{ + firstRow, lastRow, firstCol, lastCol + }); + // 忽略掉合并的错误,不打印异常 + LOGGER.debug(e.getMessage(), e); + } + } + //update-end---author:liusq Date:20220104 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiPublicUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiPublicUtil.java new file mode 100644 index 0000000..458916d --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiPublicUtil.java @@ -0,0 +1,561 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.util; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.math.BigDecimal; +import java.net.URISyntaxException; +import java.util.*; + +import javax.imageio.ImageIO; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.hssf.usermodel.HSSFClientAnchor; +import org.apache.poi.hssf.usermodel.HSSFPicture; +import org.apache.poi.hssf.usermodel.HSSFPictureData; +import org.apache.poi.hssf.usermodel.HSSFShape; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.ooxml.POIXMLDocumentPart; +import org.apache.poi.ss.usermodel.PictureData; +import org.apache.poi.xssf.usermodel.XSSFClientAnchor; +import org.apache.poi.xssf.usermodel.XSSFDrawing; +import org.apache.poi.xssf.usermodel.XSSFPicture; +import org.apache.poi.xssf.usermodel.XSSFShape; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.jeecgframework.poi.excel.annotation.Excel; +import org.jeecgframework.poi.excel.annotation.ExcelCollection; +import org.jeecgframework.poi.excel.annotation.ExcelEntity; +import org.jeecgframework.poi.excel.annotation.ExcelIgnore; +import org.jeecgframework.poi.excel.entity.vo.PoiBaseConstants; +import org.jeecgframework.poi.word.entity.WordImageEntity; +import org.jeecgframework.poi.word.entity.params.ExcelListEntity; +import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.util.ClassUtils; + +/** + * AutoPoi 的公共基础类 + * + * @author JEECG + * @date 2015年4月5日 上午12:59:22 + */ +public final class PoiPublicUtil { + + private static final Logger LOGGER = LoggerFactory.getLogger(PoiPublicUtil.class); + + private PoiPublicUtil() { + + } + + @SuppressWarnings({ "unchecked" }) + public static Map mapFor(Object... mapping) { + Map map = new HashMap(); + for (int i = 0; i < mapping.length; i += 2) { + map.put((K) mapping[i], (V) mapping[i + 1]); + } + return map; + } + + /** + * 彻底创建一个对象 + * + * @param clazz + * @return + */ + public static Object createObject(Class clazz, String targetId) { + Object obj = null; + Method setMethod; + try { + if (clazz.equals(Map.class)) { + return new LinkedHashMap(); + } + obj = clazz.newInstance(); + Field[] fields = getClassFields(clazz); + for (Field field : fields) { + if (isNotUserExcelUserThis(null, field, targetId)) { + continue; + } + if (isCollection(field.getType())) { + ExcelCollection collection = field.getAnnotation(ExcelCollection.class); + setMethod = getMethod(field.getName(), clazz, field.getType()); + setMethod.invoke(obj, collection.type().newInstance()); + } else if (!isJavaClass(field)) { + setMethod = getMethod(field.getName(), clazz, field.getType()); + setMethod.invoke(obj, createObject(field.getType(), targetId)); + } + } + + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + throw new RuntimeException("创建对象异常"); + } + return obj; + + } + + /** + * 获取class的 包括父类的 + * + * @param clazz + * @return + */ + public static Field[] getClassFields(Class clazz) { + List list = new ArrayList(); + Field[] fields; + do { + fields = clazz.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + list.add(fields[i]); + } + clazz = clazz.getSuperclass(); + } while (clazz != Object.class && clazz != null); + return list.toArray(fields); + } + + /** + * @param photoByte + * @return + */ + public static String getFileExtendName(byte[] photoByte) { + String strFileExtendName = "JPG"; + if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56) && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97)) { + strFileExtendName = "GIF"; + } else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70)) { + strFileExtendName = "JPG"; + } else if ((photoByte[0] == 66) && (photoByte[1] == 77)) { + strFileExtendName = "BMP"; + } else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71)) { + strFileExtendName = "PNG"; + } + return strFileExtendName; + } + + /** + * 获取GET方法 + * + * @param name + * @param pojoClass + * @return + * @throws Exception + */ + public static Method getMethod(String name, Class pojoClass) throws Exception { + StringBuffer getMethodName = new StringBuffer(PoiBaseConstants.GET); + getMethodName.append(name.substring(0, 1).toUpperCase()); + getMethodName.append(name.substring(1)); + Method method = null; + try { + method = pojoClass.getMethod(getMethodName.toString(), new Class[] {}); + } catch (Exception e) { + method = pojoClass.getMethod(getMethodName.toString().replace(PoiBaseConstants.GET, PoiBaseConstants.IS), new Class[] {}); + } + return method; + } + + /** + * 获取SET方法 + * + * @param name + * @param pojoClass + * @param type + * @return + * @throws Exception + */ + public static Method getMethod(String name, Class pojoClass, Class type) throws Exception { + StringBuffer getMethodName = new StringBuffer(PoiBaseConstants.SET); + getMethodName.append(name.substring(0, 1).toUpperCase()); + getMethodName.append(name.substring(1)); + return pojoClass.getMethod(getMethodName.toString(), new Class[] { type }); + } + + //update-begin-author:taoyan date:20180615 for:TASK #2798 导入扩展方法,支持自定义导入字段转换规则 + /** + * 获取get方法 通过EXCEL注解exportConvert判断是否支持值的转换 + * @param name + * @param pojoClass + * @param convert + * @return + * @throws Exception + */ + public static Method getMethod(String name, Class pojoClass,boolean convert) throws Exception { + StringBuffer getMethodName = new StringBuffer(); + if(convert){ + getMethodName.append(PoiBaseConstants.CONVERT); + } + getMethodName.append(PoiBaseConstants.GET); + getMethodName.append(name.substring(0, 1).toUpperCase()); + getMethodName.append(name.substring(1)); + Method method = null; + try { + method = pojoClass.getMethod(getMethodName.toString(), new Class[] {}); + } catch (Exception e) { + method = pojoClass.getMethod(getMethodName.toString().replace(PoiBaseConstants.GET, PoiBaseConstants.IS), new Class[] {}); + } + return method; + } + + /** + * 获取set方法 通过EXCEL注解importConvert判断是否支持值的转换 + * @param name + * @param pojoClass + * @param type + * @param convert + * @return + * @throws Exception + */ + public static Method getMethod(String name, Class pojoClass, Class type,boolean convert) throws Exception { + StringBuffer setMethodName = new StringBuffer(); + if(convert){ + setMethodName.append(PoiBaseConstants.CONVERT); + } + setMethodName.append(PoiBaseConstants.SET); + setMethodName.append(name.substring(0, 1).toUpperCase()); + setMethodName.append(name.substring(1)); + return pojoClass.getMethod(setMethodName.toString(), new Class[] { type }); + } + //update-end-author:taoyan date:20180615 for:TASK #2798 导入扩展方法,支持自定义导入字段转换规则 + + /** + * 获取Excel2003图片 + * + * @param sheet + * 当前sheet对象 + * @param workbook + * 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictrues03(HSSFSheet sheet, HSSFWorkbook workbook) { + Map sheetIndexPicMap = new HashMap(); + List pictures = workbook.getAllPictures(); + if (!pictures.isEmpty()) { + for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren()) { + HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor(); + if (shape instanceof HSSFPicture) { + HSSFPicture pic = (HSSFPicture) shape; + int pictureIndex = pic.getPictureIndex() - 1; + HSSFPictureData picData = pictures.get(pictureIndex); + String picIndex = String.valueOf(anchor.getRow1()) + "_" + String.valueOf(anchor.getCol1()); + sheetIndexPicMap.put(picIndex, picData); + } + } + return sheetIndexPicMap; + } else { + return null; + } + } + + /** + * 获取Excel2007图片 + * + * @param sheet + * 当前sheet对象 + * @param workbook + * 工作簿对象 + * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData + */ + public static Map getSheetPictrues07(XSSFSheet sheet, XSSFWorkbook workbook) { + Map sheetIndexPicMap = new HashMap(); + for (POIXMLDocumentPart dr : sheet.getRelations()) { + if (dr instanceof XSSFDrawing) { + XSSFDrawing drawing = (XSSFDrawing) dr; + List shapes = drawing.getShapes(); + for (XSSFShape shape : shapes) { + XSSFPicture pic = (XSSFPicture) shape; + XSSFClientAnchor anchor = pic.getPreferredSize(); + CTMarker ctMarker = anchor.getFrom(); + String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol(); + sheetIndexPicMap.put(picIndex, pic.getPictureData()); + } + } + } + return sheetIndexPicMap; + } + + public static String getWebRootPath(String filePath) { + try { + String path = null; + try { + path = PoiPublicUtil.class.getClassLoader().getResource("").toURI().getPath(); + } catch (URISyntaxException e) { + //e.printStackTrace(); + //update-begin-author:taoyan date:20211116 for: JAR包分离 发布出空指针 https://gitee.com/jeecg/jeecg-boot/issues/I4CMHK + }catch (NullPointerException e) { + path = PoiPublicUtil.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + } + //update-end-author:taoyan date:20211116 for: JAR包分离 发布出空指针 https://gitee.com/jeecg/jeecg-boot/issues/I4CMHK + //update-begin--Author:zhangdaihao Date:20190424 for:解决springboot 启动模式,上传路径获取为空问题--------------------- + if (path == null || path == "") { + //解决springboot 启动模式,上传路径获取为空问题 + path = ClassUtils.getDefaultClassLoader().getResource("").getPath(); + } + //update-end--Author:zhangdaihao Date:20190424 for:解决springboot 启动模式,上传路径获取为空问题---------------------- + LOGGER.debug("--- getWebRootPath ----filePath--- " + path); + path = path.replace("WEB-INF/classes/", ""); + path = path.replace("file:/", ""); + LOGGER.debug("--- path--- " + path); + LOGGER.debug("--- filePath--- " + filePath); + return path + filePath; + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + /** + * 判断是不是集合的实现类 + * + * @param clazz + * @return + */ + public static boolean isCollection(Class clazz) { + return Collection.class.isAssignableFrom(clazz); + } + + /** + * 是不是java基础类 + * + * @param field + * @return + */ + public static boolean isJavaClass(Field field) { + Class fieldType = field.getType(); + boolean isBaseClass = false; + if (fieldType.isArray()) { + isBaseClass = false; + } else if (fieldType.isPrimitive() || fieldType.getPackage() == null || fieldType.getPackage().getName().equals("java.lang") || fieldType.getPackage().getName().equals("java.math") || fieldType.getPackage().getName().equals("java.sql") || fieldType.getPackage().getName().equals("java.util")) { + isBaseClass = true; + } + return isBaseClass; + } + + /** + * 判断是否不要在这个excel操作中 + * + * @param + * @param field + * @param targetId + * @return + */ + public static boolean isNotUserExcelUserThis(List exclusionsList, Field field, String targetId) { + boolean boo = true; + if (field.getAnnotation(ExcelIgnore.class) != null) { + boo = true; + } else if (boo && field.getAnnotation(ExcelCollection.class) != null && isUseInThis(field.getAnnotation(ExcelCollection.class).name(), targetId) && (exclusionsList == null || !exclusionsList.contains(field.getAnnotation(ExcelCollection.class).name()))) { + boo = false; + } else if (boo && field.getAnnotation(Excel.class) != null && isUseInThis(field.getAnnotation(Excel.class).name(), targetId) && (exclusionsList == null || !exclusionsList.contains(field.getAnnotation(Excel.class).name()))) { + boo = false; + } else if (boo && field.getAnnotation(ExcelEntity.class) != null && isUseInThis(field.getAnnotation(ExcelEntity.class).name(), targetId) && (exclusionsList == null || !exclusionsList.contains(field.getAnnotation(ExcelEntity.class).name()))) { + boo = false; + } + return boo; + } + + /** + * 判断是不是使用 + * + * @param exportName + * @param targetId + * @return + */ + private static boolean isUseInThis(String exportName, String targetId) { + return targetId == null || exportName.equals("") || exportName.indexOf("_") < 0 || exportName.indexOf(targetId) != -1; + } + + private static Integer getImageType(String type) { + if (type.equalsIgnoreCase("JPG") || type.equalsIgnoreCase("JPEG")) { + return XWPFDocument.PICTURE_TYPE_JPEG; + } + if (type.equalsIgnoreCase("GIF")) { + return XWPFDocument.PICTURE_TYPE_GIF; + } + if (type.equalsIgnoreCase("BMP")) { + return XWPFDocument.PICTURE_TYPE_GIF; + } + if (type.equalsIgnoreCase("PNG")) { + return XWPFDocument.PICTURE_TYPE_PNG; + } + return XWPFDocument.PICTURE_TYPE_JPEG; + } + + /** + * 返回流和图片类型 + * + * @Author JEECG + * @date 2013-11-20 + * @param entity + * @return (byte[]) isAndType[0],(Integer)isAndType[1] + * @throws Exception + */ + public static Object[] getIsAndType(WordImageEntity entity) throws Exception { + Object[] result = new Object[2]; + String type; + if (entity.getType().equals(WordImageEntity.URL)) { + ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream(); + BufferedImage bufferImg; + String path = Thread.currentThread().getContextClassLoader().getResource("").toURI().getPath() + entity.getUrl(); + path = path.replace("WEB-INF/classes/", ""); + path = path.replace("file:/", ""); + bufferImg = ImageIO.read(new File(path)); + //update-begin-author:taoYan date:20211203 for: Excel 导出图片的文件带小数点符号 导出报错 https://gitee.com/jeecg/jeecg-boot/issues/I4JNHR + ImageIO.write(bufferImg, entity.getUrl().substring(entity.getUrl().lastIndexOf(".") + 1, entity.getUrl().length()), byteArrayOut); + //update-end-author:taoYan date:20211203 for: Excel 导出图片的文件带小数点符号 导出报错 https://gitee.com/jeecg/jeecg-boot/issues/I4JNHR + result[0] = byteArrayOut.toByteArray(); + type = entity.getUrl().split("/.")[entity.getUrl().split("/.").length - 1]; + } else { + result[0] = entity.getData(); + type = PoiPublicUtil.getFileExtendName(entity.getData()); + } + result[1] = getImageType(type); + return result; + } + + /** + * 获取参数值 + * + * @param params + * @param map + * @return + */ + @SuppressWarnings("rawtypes") + public static Object getParamsValue(String params, Object object) throws Exception { + if (params.indexOf(".") != -1) { + String[] paramsArr = params.split("\\."); + return getValueDoWhile(object, paramsArr, 0); + } + if (object instanceof Map) { + return ((Map) object).get(params); + } + return getMethod(params, object.getClass()).invoke(object, new Object[] {}); + } + + /** + * 解析数据 + * + * @Author JEECG + * @date 2013-11-16 + * @return + */ + public static Object getRealValue(String currentText, Map map) throws Exception { + String params = ""; + while (currentText.indexOf("{{") != -1) { + params = currentText.substring(currentText.indexOf("{{") + 2, currentText.indexOf("}}")); + Object obj = getParamsValue(params.trim(), map); + // 判断图片或者是集合 + // update-begin-author:taoyan date:20210914 for:autopoi模板导出,赋值的方法建议增加空判断或抛出异常说明。 /issues/3005 + if(obj==null){ + obj = ""; + } + // update-end-author:taoyan date:20210914 for:autopoi模板导出,赋值的方法建议增加空判断或抛出异常说明。/issues/3005 + if (obj instanceof WordImageEntity || obj instanceof List || obj instanceof ExcelListEntity) { + return obj; + } else { + currentText = currentText.replace("{{" + params + "}}", obj.toString()); + } + } + return currentText; + } + + /** + * 通过遍历过去对象值 + * + * @param object + * @param paramsArr + * @param index + * @return + * @throws Exception + */ + @SuppressWarnings("rawtypes") + public static Object getValueDoWhile(Object object, String[] paramsArr, int index) throws Exception { + if (object == null) { + return ""; + } + if (object instanceof WordImageEntity) { + return object; + } + if (object instanceof Map) { + object = ((Map) object).get(paramsArr[index]); + } else { + object = getMethod(paramsArr[index], object.getClass()).invoke(object, new Object[] {}); + } + return (index == paramsArr.length - 1) ? (object == null ? "" : object) : getValueDoWhile(object, paramsArr, ++index); + } + + /** + * double to String 防止科学计数法 + * + * @param value + * @return + */ + public static String doubleToString(Double value) { + String temp = value.toString(); + if (temp.contains("E")) { + BigDecimal bigDecimal = new BigDecimal(temp); + temp = bigDecimal.toPlainString(); + } + //---update-begin-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------ + return ExcelUtil.remove0Suffix(temp); + //---update-end-----autor:scott------date:20191016-------for:excel导入数字类型,去掉后缀.0------ + } + + /** + * 判断是否是数值类型 + * @param xclass + * @return + */ + public static boolean isNumber(String xclass){ + if(xclass==null){ + return false; + } + String temp = xclass.toLowerCase(); + if(temp.indexOf("int")>=0 || temp.indexOf("double")>=0 || temp.indexOf("decimal")>=0){ + return true; + } + return false; + } + //update-begin---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + /** + * 统一 key的获取规则 + * @param key + * @param targetId + * @date 2022年1月4号 + * @return + */ + public static String getValueByTargetId(String key, String targetId, String defalut) { + if (StringUtils.isEmpty(targetId) || key.indexOf("_") < 0) { + return key; + } + String[] arr = key.split(","); + String[] tempArr; + for (String str : arr) { + tempArr = str.split("_"); + if (tempArr == null || tempArr.length < 2) { + return defalut; + } + if (targetId.equals(tempArr[1])) { + return tempArr[0]; + } + } + return defalut; + } + //update-end---author:liusq Date:20211217 for:[LOWCOD-2521]【autopoi】大数据导出方法【全局】---- + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiReflectorUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiReflectorUtil.java new file mode 100644 index 0000000..e6c91b7 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiReflectorUtil.java @@ -0,0 +1,374 @@ +package org.jeecgframework.poi.util; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.lang.reflect.ReflectPermission; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * 反射工具类,缓存读取的class信息,省的一直获取 + * @Description [LOWCOD-2521]【autopoi】大数据导出方法【全局】 + * @author liusq + * @date 2022年1月4号 + */ +public final class PoiReflectorUtil { + + private static final Map, PoiReflectorUtil> CACHE_REFLECTOR = new ConcurrentHashMap, PoiReflectorUtil>(); + + private Map getMethods = new HashMap(); + private Map setMethods = new HashMap(); + private Map enumMethods = new HashMap(); + private List fieldList = new ArrayList(); + + private Class type; + + private PoiReflectorUtil(Class clazz) { + this.type = clazz; + addGetMethods(clazz); + addFields(clazz); + addSetMethods(clazz); + } + + public static PoiReflectorUtil forClass(Class clazz) { + return new PoiReflectorUtil(clazz); + } + + public static PoiReflectorUtil fromCache(Class clazz) { + if (!CACHE_REFLECTOR.containsKey(clazz)) { + CACHE_REFLECTOR.put(clazz, new PoiReflectorUtil(clazz)); + } + return CACHE_REFLECTOR.get(clazz); + } + + private void addGetMethods(Class cls) { + Map> conflictingGetters = new HashMap>(); + Method[] methods = getClassMethods(cls); + for (Method method : methods) { + String name = method.getName(); + if (name.startsWith("get") && name.length() > 3) { + if (method.getParameterTypes().length == 0) { + name = methodToProperty(name); + addMethodConflict(conflictingGetters, name, method); + } + } else if (name.startsWith("is") && name.length() > 2) { + if (method.getParameterTypes().length == 0) { + name = methodToProperty(name); + addMethodConflict(conflictingGetters, name, method); + } + } + } + resolveGetterConflicts(conflictingGetters); + } + + private void resolveGetterConflicts(Map> conflictingGetters) { + for (String propName : conflictingGetters.keySet()) { + List getters = conflictingGetters.get(propName); + Iterator iterator = getters.iterator(); + Method firstMethod = iterator.next(); + if (getters.size() == 1) { + addGetMethod(propName, firstMethod); + } else { + Method getter = firstMethod; + Class getterType = firstMethod.getReturnType(); + while (iterator.hasNext()) { + Method method = iterator.next(); + Class methodType = method.getReturnType(); + if (methodType.equals(getterType)) { + throw new RuntimeException( + "Illegal overloaded getter method with ambiguous type for property " + + propName + " in class " + + firstMethod.getDeclaringClass() + + ". This breaks the JavaBeans " + + "specification and can cause unpredicatble results."); + } else if (methodType.isAssignableFrom(getterType)) { + // OK getter type is descendant + } else if (getterType.isAssignableFrom(methodType)) { + getter = method; + getterType = methodType; + } else { + throw new RuntimeException( + "Illegal overloaded getter method with ambiguous type for property " + + propName + " in class " + + firstMethod.getDeclaringClass() + + ". This breaks the JavaBeans " + + "specification and can cause unpredicatble results."); + } + } + addGetMethod(propName, getter); + } + } + } + + private void addGetMethod(String name, Method method) { + if (isValidPropertyName(name)) { + getMethods.put(name, method); + } + } + + private void addSetMethods(Class cls) { + Map> conflictingSetters = new HashMap>(); + Method[] methods = getClassMethods(cls); + for (Method method : methods) { + String name = method.getName(); + if (name.startsWith("set") && name.length() > 3) { + if (method.getParameterTypes().length == 1) { + name = methodToProperty(name); + addMethodConflict(conflictingSetters, name, method); + } + } + } + resolveSetterConflicts(conflictingSetters); + } + + private static String methodToProperty(String name) { + if (name.startsWith("is")) { + name = name.substring(2); + } else if (name.startsWith("get") || name.startsWith("set")) { + name = name.substring(3); + } else { + throw new RuntimeException("Error parsing property name '" + name + + "'. Didn't start with 'is', 'get' or 'set'."); + } + + if (name.length() == 1 || (name.length() > 1 && !Character.isUpperCase(name.charAt(1)))) { + name = name.substring(0, 1).toLowerCase(Locale.ENGLISH) + name.substring(1); + } + + return name; + } + + private void addMethodConflict(Map> conflictingMethods, String name, + Method method) { + List list = conflictingMethods.get(name); + if (list == null) { + list = new ArrayList(); + conflictingMethods.put(name, list); + } + list.add(method); + } + + private void resolveSetterConflicts(Map> conflictingSetters) { + for (String propName : conflictingSetters.keySet()) { + List setters = conflictingSetters.get(propName); + Method firstMethod = setters.get(0); + if (setters.size() == 1) { + addSetMethod(propName, firstMethod); + } else { + Iterator methods = setters.iterator(); + Method setter = null; + while (methods.hasNext()) { + Method method = methods.next(); + if (method.getParameterTypes().length == 1) { + setter = method; + break; + } + } + if (setter == null) { + throw new RuntimeException( + "Illegal overloaded setter method with ambiguous type for property " + + propName + " in class " + + firstMethod.getDeclaringClass() + + ". This breaks the JavaBeans " + + "specification and can cause unpredicatble results."); + } + addSetMethod(propName, setter); + } + } + } + + private void addSetMethod(String name, Method method) { + if (isValidPropertyName(name)) { + setMethods.put(name, method); + } + } + + private void addFields(Class clazz) { + Field[] fields = clazz.getDeclaredFields(); + for (Field field : fields) { + if (canAccessPrivateMethods()) { + try { + field.setAccessible(true); + } catch (Exception e) { + // Ignored. This is only a final precaution, nothing we can do. + } + } + if (field.isAccessible() && !"serialVersionUID".equalsIgnoreCase(field.getName())) { + this.fieldList.add(field); + } + } + if (clazz.getSuperclass() != null) { + addFields(clazz.getSuperclass()); + } + } + + private boolean isValidPropertyName(String name) { + return !(name.startsWith("$") || "serialVersionUID".equals(name) || "class".equals(name)); + } + + /* + * This method returns an array containing all methods + * declared in this class and any superclass. + * We use this method, instead of the simpler Class.getMethods(), + * because we want to look for private methods as well. + * + * @param cls The class + * @return An array containing all methods in this class + */ + private Method[] getClassMethods(Class cls) { + HashMap uniqueMethods = new HashMap(); + Class currentClass = cls; + while (currentClass != null) { + addUniqueMethods(uniqueMethods, currentClass.getDeclaredMethods()); + + // we also need to look for interface methods - + // because the class may be abstract + Class[] interfaces = currentClass.getInterfaces(); + for (Class anInterface : interfaces) { + addUniqueMethods(uniqueMethods, anInterface.getMethods()); + } + + currentClass = currentClass.getSuperclass(); + } + + Collection methods = uniqueMethods.values(); + + return methods.toArray(new Method[methods.size()]); + } + + private void addUniqueMethods(HashMap uniqueMethods, Method[] methods) { + for (Method currentMethod : methods) { + if (!currentMethod.isBridge()) { + String signature = getSignature(currentMethod); + // check to see if the method is already known + // if it is known, then an extended class must have + // overridden a method + if (!uniqueMethods.containsKey(signature)) { + if (canAccessPrivateMethods()) { + try { + currentMethod.setAccessible(true); + } catch (Exception e) { + // Ignored. This is only a final precaution, nothing we can do. + } + } + + uniqueMethods.put(signature, currentMethod); + } + } + } + } + + private String getSignature(Method method) { + StringBuilder sb = new StringBuilder(); + Class returnType = method.getReturnType(); + if (returnType != null) { + sb.append(returnType.getName()).append('#'); + } + sb.append(method.getName()); + Class[] parameters = method.getParameterTypes(); + for (int i = 0; i < parameters.length; i++) { + if (i == 0) { + sb.append(':'); + } else { + sb.append(','); + } + sb.append(parameters[i].getName()); + } + return sb.toString(); + } + + private boolean canAccessPrivateMethods() { + try { + SecurityManager securityManager = System.getSecurityManager(); + if (null != securityManager) { + securityManager.checkPermission(new ReflectPermission("suppressAccessChecks")); + } + } catch (SecurityException e) { + return false; + } + return true; + } + + public Method getGetMethod(String propertyName) { + Method method = getMethods.get(propertyName); + if (method == null) { + throw new RuntimeException( + "There is no getter for property named '" + propertyName + "' in '" + type + "'"); + } + return method; + } + + public Method getSetMethod(String propertyName) { + Method method = setMethods.get(propertyName); + if (method == null) { + throw new RuntimeException( + "There is no setter for property named '" + propertyName + "' in '" + type + "'"); + } + return method; + } + + /** + * 获取field 值 + * + * @param obj + * @param property + * @return + */ + public Object getValue(Object obj, String property) { + Object value = null; + Method m = getMethods.get(property); + if (m != null) { + try { + value = m.invoke(obj, new Object[]{}); + } catch (Exception ex) { + } + } + return value; + } + + /** + * 设置field值 + * + * @param obj 对象 + * @param property + * @param object 属性值 + * @return + */ + public boolean setValue(Object obj, String property, Object object) { + Method m = setMethods.get(property); + if (m != null) { + try { + m.invoke(obj, object); + return true; + } catch (Exception ex) { + return false; + } + } + return false; + } + + public Map getGetMethods() { + return getMethods; + } + + public List getFieldList() { + return fieldList; + } + + public Object execEnumStaticMethod(String staticMethod, Object params) { + if (!enumMethods.containsKey(setMethods)) { + try { + enumMethods.put(staticMethod,type.getMethod(staticMethod,params.getClass())); + } catch (NoSuchMethodException e) { + throw new RuntimeException( + "There is no enum for property named '" + staticMethod + "' in '" + type + "'"); + } + } + try { + return enumMethods.get(staticMethod).invoke(null,params); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiSheetUtility.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiSheetUtility.java new file mode 100644 index 0000000..732a066 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/util/PoiSheetUtility.java @@ -0,0 +1,104 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.util; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.Row; +import org.apache.poi.ss.usermodel.Sheet; + +/** + * 国外高手的,不过也不好,慎用,效率不行 Helper functions to aid in the management of sheets + */ +public class PoiSheetUtility extends Object { + + /** + * Given a sheet, this method deletes a column from a sheet and moves all + * the columns to the right of it to the left one cell. + * + * Note, this method will not update any formula references. + * + * @param sheet + * @param column + */ + public static void deleteColumn(Sheet sheet, int columnToDelete) { + int maxColumn = 0; + for (int r = 0; r < sheet.getLastRowNum() + 1; r++) { + Row row = sheet.getRow(r); + + // if no row exists here; then nothing to do; next! + if (row == null) + continue; + + // if the row doesn't have this many columns then we are good; next! + int lastColumn = row.getLastCellNum(); + if (lastColumn > maxColumn) + maxColumn = lastColumn; + + if (lastColumn < columnToDelete) + continue; + + for (int x = columnToDelete + 1; x < lastColumn + 1; x++) { + Cell oldCell = row.getCell(x - 1); + if (oldCell != null) + row.removeCell(oldCell); + + Cell nextCell = row.getCell(x); + if (nextCell != null) { + Cell newCell = row.createCell(x - 1, nextCell.getCellType()); + cloneCell(newCell, nextCell); + } + } + } + + // Adjust the column widths + for (int c = 0; c < maxColumn; c++) { + sheet.setColumnWidth(c, sheet.getColumnWidth(c + 1)); + } + } + + /* + * Takes an existing Cell and merges all the styles and forumla into the new + * one + */ + private static void cloneCell(Cell cNew, Cell cOld) { + cNew.setCellComment(cOld.getCellComment()); + cNew.setCellStyle(cOld.getCellStyle()); + + switch (cNew.getCellType()) { + case BOOLEAN: { + cNew.setCellValue(cOld.getBooleanCellValue()); + break; + } + case NUMERIC: { + cNew.setCellValue(cOld.getNumericCellValue()); + break; + } + case STRING: { + cNew.setCellValue(cOld.getStringCellValue()); + break; + } + case ERROR: { + cNew.setCellValue(cOld.getErrorCellValue()); + break; + } + case FORMULA: { + cNew.setCellFormula(cOld.getCellFormula()); + break; + } + } + + } +} \ No newline at end of file diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/WordExportUtil.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/WordExportUtil.java new file mode 100644 index 0000000..5b87de1 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/WordExportUtil.java @@ -0,0 +1,62 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.word; + +import java.util.Map; + +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.jeecgframework.poi.word.parse.ParseWord07; + +/** + * Word使用模板导出工具类 + * + * @author JEECG + * @date 2013-11-16 + * @version 1.0 + */ +public final class WordExportUtil { + + private WordExportUtil() { + + } + + /** + * 解析Word2007版本 + * + * @param url + * 模板地址 + * @param map + * 解析数据源 + * @return + */ + public static XWPFDocument exportWord07(String url, Map map) throws Exception { + return new ParseWord07().parseWord(url, map); + } + + /** + * 解析Word2007版本 + * + * @param XWPFDocument + * 模板 + * @param map + * 解析数据源 + * @return + */ + public static void exportWord07(XWPFDocument document, Map map) throws Exception { + new ParseWord07().parseWord(document, map); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/MyXWPFDocument.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/MyXWPFDocument.java new file mode 100644 index 0000000..b4fe844 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/MyXWPFDocument.java @@ -0,0 +1,115 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.word.entity; + +import java.io.InputStream; + +import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.poi.xwpf.usermodel.XWPFRun; +import org.apache.xmlbeans.XmlException; +import org.apache.xmlbeans.XmlToken; +import org.openxmlformats.schemas.drawingml.x2006.main.CTNonVisualDrawingProps; +import org.openxmlformats.schemas.drawingml.x2006.main.CTPositiveSize2D; +import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTInline; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 扩充document,修复图片插入失败问题问题 + * + * @author JEECG + * @date 2013-11-20 + * @version 1.0 + */ +public class MyXWPFDocument extends XWPFDocument { + + private static final Logger LOGGER = LoggerFactory.getLogger(MyXWPFDocument.class); + + private static String PICXML = "" + "" + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + " " + + " " + " " + " " + " " + " " + " " + " " + " " + " " + ""; + + public MyXWPFDocument() { + super(); + } + + public MyXWPFDocument(InputStream in) throws Exception { + super(in); + } + + public MyXWPFDocument(OPCPackage opcPackage) throws Exception { + super(opcPackage); + } + + public void createPicture(String blipId, int id, int width, int height) { + final int EMU = 9525; + width *= EMU; + height *= EMU; + CTInline inline = createParagraph().createRun().getCTR().addNewDrawing().addNewInline(); + String picXml = String.format(PICXML, id, blipId, width, height); + XmlToken xmlToken = null; + try { + xmlToken = XmlToken.Factory.parse(picXml); + } catch (XmlException xe) { + LOGGER.error(xe.getMessage(), xe.fillInStackTrace()); + } + inline.set(xmlToken); + + inline.setDistT(0); + inline.setDistB(0); + inline.setDistL(0); + inline.setDistR(0); + + CTPositiveSize2D extent = inline.addNewExtent(); + extent.setCx(width); + extent.setCy(height); + + CTNonVisualDrawingProps docPr = inline.addNewDocPr(); + docPr.setId(id); + docPr.setName("Picture " + id); + docPr.setDescr("Generated"); + } + + public void createPicture(XWPFRun run, String blipId, int id, int width, int height) { + final int EMU = 9525; + width *= EMU; + height *= EMU; + CTInline inline = run.getCTR().addNewDrawing().addNewInline(); + String picXml = String.format(PICXML, id, blipId, width, height); + XmlToken xmlToken = null; + try { + xmlToken = XmlToken.Factory.parse(picXml); + } catch (XmlException xe) { + LOGGER.error(xe.getMessage(), xe.fillInStackTrace()); + } + inline.set(xmlToken); + + inline.setDistT(0); + inline.setDistB(0); + inline.setDistL(0); + inline.setDistR(0); + + CTPositiveSize2D extent = inline.addNewExtent(); + extent.setCx(width); + extent.setCy(height); + + CTNonVisualDrawingProps docPr = inline.addNewDocPr(); + docPr.setId(id); + docPr.setName("Picture " + id); + docPr.setDescr("Generated"); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/WordImageEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/WordImageEntity.java new file mode 100644 index 0000000..7912592 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/WordImageEntity.java @@ -0,0 +1,101 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.word.entity; + +/** + * word导出,图片设置和图片信息 + * + * @author JEECG + * @date 2013-11-17 + * @version 1.0 + */ +public class WordImageEntity { + + public static String URL = "url"; + public static String Data = "data"; + /** + * 图片输入方式 + */ + private String type = URL; + /** + * 图片宽度 + */ + private int width; + // 图片高度 + private int height; + // 图片地址 + private String url; + // 图片信息 + private byte[] data; + + public WordImageEntity() { + + } + + public WordImageEntity(byte[] data, int width, int height) { + this.data = data; + this.width = width; + this.height = height; + this.type = Data; + } + + public WordImageEntity(String url, int width, int height) { + this.url = url; + this.width = width; + this.height = height; + } + + public byte[] getData() { + return data; + } + + public int getHeight() { + return height; + } + + public String getType() { + return type; + } + + public String getUrl() { + return url; + } + + public int getWidth() { + return width; + } + + public void setData(byte[] data) { + this.data = data; + } + + public void setHeight(int height) { + this.height = height; + } + + public void setType(String type) { + this.type = type; + } + + public void setUrl(String url) { + this.url = url; + } + + public void setWidth(int width) { + this.width = width; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/params/ExcelListEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/params/ExcelListEntity.java new file mode 100644 index 0000000..d3cd5c5 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/params/ExcelListEntity.java @@ -0,0 +1,98 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.word.entity.params; + +import java.util.List; + +import org.jeecgframework.poi.excel.entity.ExcelBaseParams; +import org.jeecgframework.poi.handler.inter.IExcelDataHandler; + +/** + * Excel 导出对象 + * + * @author JEECG + * @date 2014年8月9日 下午10:21:13 + */ +public class ExcelListEntity extends ExcelBaseParams { + + /** + * 数据源 + */ + private List list; + + /** + * 实体类对象 + */ + private Class clazz; + + /** + * 表头行数 + */ + private int headRows = 1; + + public ExcelListEntity() { + + } + + public ExcelListEntity(List list, Class clazz) { + this.list = list; + this.clazz = clazz; + } + + public ExcelListEntity(List list, Class clazz, IExcelDataHandler dataHanlder) { + this.list = list; + this.clazz = clazz; + setDataHanlder(dataHanlder); + } + + public ExcelListEntity(List list, Class clazz, IExcelDataHandler dataHanlder, int headRows) { + this.list = list; + this.clazz = clazz; + this.headRows = headRows; + setDataHanlder(dataHanlder); + } + + public ExcelListEntity(List list, Class clazz, int headRows) { + this.list = list; + this.clazz = clazz; + this.headRows = headRows; + } + + public Class getClazz() { + return clazz; + } + + public int getHeadRows() { + return headRows; + } + + public List getList() { + return list; + } + + public void setClazz(Class clazz) { + this.clazz = clazz; + } + + public void setHeadRows(int headRows) { + this.headRows = headRows; + } + + public void setList(List list) { + this.list = list; + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/params/ListParamEntity.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/params/ListParamEntity.java new file mode 100644 index 0000000..291a2f1 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/entity/params/ListParamEntity.java @@ -0,0 +1,93 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.word.entity.params; + +/** + * Excel 对象导出结构 + * + * @author JEECG + * @date 2014年7月26日 下午11:14:48 + */ +public class ListParamEntity { + // 唯一值,在遍历中重复使用 + public static final String SINGLE = "single"; + // 属于数组类型 + public static final String LIST = "list"; + /** + * 属性名称 + */ + private String name; + /** + * 目标 + */ + private String target; + /** + * 当是唯一值的时候直接求出值 + */ + private Object value; + /** + * 数据类型,SINGLE || LIST + */ + private String type; + + public ListParamEntity() { + + } + + public ListParamEntity(String name, Object value) { + this.name = name; + this.value = value; + this.type = LIST; + } + + public ListParamEntity(String name, String target) { + this.name = name; + this.target = target; + this.type = LIST; + } + + public String getName() { + return name; + } + + public String getTarget() { + return target; + } + + public String getType() { + return type; + } + + public Object getValue() { + return value; + } + + public void setName(String name) { + this.name = name; + } + + public void setTarget(String target) { + this.target = target; + } + + public void setType(String type) { + this.type = type; + } + + public void setValue(Object value) { + this.value = value; + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/ParseWord07.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/ParseWord07.java new file mode 100644 index 0000000..2fedf8c --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/ParseWord07.java @@ -0,0 +1,301 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.word.parse; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.xwpf.usermodel.XWPFDocument; +import org.apache.poi.xwpf.usermodel.XWPFFooter; +import org.apache.poi.xwpf.usermodel.XWPFHeader; +import org.apache.poi.xwpf.usermodel.XWPFParagraph; +import org.apache.poi.xwpf.usermodel.XWPFRun; +import org.apache.poi.xwpf.usermodel.XWPFTable; +import org.apache.poi.xwpf.usermodel.XWPFTableCell; +import org.apache.poi.xwpf.usermodel.XWPFTableRow; +import org.jeecgframework.poi.cache.WordCache; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.jeecgframework.poi.word.entity.MyXWPFDocument; +import org.jeecgframework.poi.word.entity.WordImageEntity; +import org.jeecgframework.poi.word.entity.params.ExcelListEntity; +import org.jeecgframework.poi.word.parse.excel.ExcelEntityParse; +import org.jeecgframework.poi.word.parse.excel.ExcelMapParse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 解析07版的Word,替换文字,生成表格,生成图片 + * + * @author JEECG + * @date 2013-11-16 + * @version 1.0 + */ +@SuppressWarnings({ "unchecked", "rawtypes" }) +public class ParseWord07 { + + private static final Logger LOGGER = LoggerFactory.getLogger(ParseWord07.class); + + /** + * 添加图片 + * + * @Author JEECG + * @date 2013-11-20 + * @param obj + * @param currentRun + * @throws Exception + */ + private void addAnImage(WordImageEntity obj, XWPFRun currentRun) throws Exception { + Object[] isAndType = PoiPublicUtil.getIsAndType(obj); + String picId; + try { + picId = currentRun.getParagraph().getDocument().addPictureData((byte[]) isAndType[0], (Integer) isAndType[1]); + ((MyXWPFDocument) currentRun.getParagraph().getDocument()).createPicture(currentRun, picId, currentRun.getParagraph().getDocument().getNextPicNameNumber((Integer) isAndType[1]), obj.getWidth(), obj.getHeight()); + + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + + } + + /** + * 根据条件改变值 + * + * @param map + * @Author JEECG + * @date 2013-11-16 + */ + private void changeValues(XWPFParagraph paragraph, XWPFRun currentRun, String currentText, List runIndex, Map map) throws Exception { + Object obj = PoiPublicUtil.getRealValue(currentText, map); + if (obj instanceof WordImageEntity) {// 如果是图片就设置为图片 + currentRun.setText("", 0); + addAnImage((WordImageEntity) obj, currentRun); + } else { + currentText = obj.toString(); + currentRun.setText(currentText, 0); + } + for (int k = 0; k < runIndex.size(); k++) { + paragraph.getRuns().get(runIndex.get(k)).setText("", 0); + } + runIndex.clear(); + } + + /** + * 判断是不是迭代输出 + * + * @Author JEECG + * @date 2013-11-18 + * @return + * @throws Exception + */ + private Object checkThisTableIsNeedIterator(XWPFTableCell cell, Map map) throws Exception { + String text = cell.getText().trim(); + //begin-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + // 判断是不是迭代输出 + if (text != null&&text.startsWith("{{") && text.indexOf("$fe:") != -1) { + return PoiPublicUtil.getRealValue(text.replace("$fe:", "").trim(), map); + } + //end-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + return null; + } + + /** + * 解析所有的文本 + * + * @Author JEECG + * @date 2013-11-17 + * @param paragraphs + * @param map + */ + private void parseAllParagraphic(List paragraphs, Map map) throws Exception { + XWPFParagraph paragraph; + for (int i = 0; i < paragraphs.size(); i++) { + paragraph = paragraphs.get(i); + if (paragraph.getText().indexOf("{{") != -1) { + parseThisParagraph(paragraph, map); + } + + } + + } + + /** + * 解析这个段落 + * + * @Author JEECG + * @date 2013-11-16 + * @param paragraph + * @param map + */ + private void parseThisParagraph(XWPFParagraph paragraph, Map map) throws Exception { + XWPFRun run; + XWPFRun currentRun = null;// 拿到的第一个run,用来set值,可以保存格式 + String currentText = "";// 存放当前的text + String text; + Boolean isfinde = false;// 判断是不是已经遇到{{ + List runIndex = new ArrayList();// 存储遇到的run,把他们置空 + for (int i = 0; i < paragraph.getRuns().size(); i++) { + run = paragraph.getRuns().get(i); + text = run.getText(0); + if (StringUtils.isEmpty(text)) { + continue; + }// 如果为空或者""这种这继续循环跳过 + if (isfinde) { + currentText += text; + if (currentText.indexOf("{{") == -1) { + isfinde = false; + runIndex.clear(); + } else { + runIndex.add(i); + } + if (currentText.indexOf("}}") != -1) { + changeValues(paragraph, currentRun, currentText, runIndex, map); + currentText = ""; + isfinde = false; + } + } else if (text.indexOf("{") >= 0) {// 判断是不是开始 + currentText = text; + isfinde = true; + currentRun = run; + } else { + currentText = ""; + } + if (currentText.indexOf("}}") != -1) { + changeValues(paragraph, currentRun, currentText, runIndex, map); + isfinde = false; + } + } + + } + + private void parseThisRow(List cells, Map map) throws Exception { + for (XWPFTableCell cell : cells) { + parseAllParagraphic(cell.getParagraphs(), map); + } + } + + /** + * 解析这个表格 + * + * @Author JEECG + * @date 2013-11-17 + * @param table + * @param map + */ + private void parseThisTable(XWPFTable table, Map map) throws Exception { + XWPFTableRow row; + List cells; + Object listobj; + for (int i = 0; i < table.getNumberOfRows(); i++) { + row = table.getRow(i); + cells = row.getTableCells(); + //begin-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + listobj = checkThisTableIsNeedIterator(cells.get(0), map); + if (listobj == null) { + parseThisRow(cells, map); + } else if (listobj instanceof ExcelListEntity) { + new ExcelEntityParse().parseNextRowAndAddRow(table, i, (ExcelListEntity) listobj); + i = i + ((ExcelListEntity) listobj).getList().size() - 1;//删除之后要往上挪一行,然后加上跳过新建的行数 + } else { + ExcelMapParse.parseNextRowAndAddRow(table, i, (List) listobj); + i = i + ((List) listobj).size() - 1;//删除之后要往上挪一行,然后加上跳过新建的行数 + } + /*if (cells.size() == 1) { + listobj = checkThisTableIsNeedIterator(cells.get(0), map); + if (listobj == null) { + parseThisRow(cells, map); + } else if (listobj instanceof ExcelListEntity) { + table.removeRow(i);// 删除这一行 + excelEntityParse.parseNextRowAndAddRow(table, i, (ExcelListEntity) listobj); + } else { + table.removeRow(i);// 删除这一行 + ExcelMapParse.parseNextRowAndAddRow(table, i, (List) listobj); + } + } else { + parseThisRow(cells, map); + }*/ + //end-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + } + } + + /** + * 解析07版的Word并且进行赋值 + * + * @Author JEECG + * @date 2013-11-16 + * @return + * @throws Exception + */ + public XWPFDocument parseWord(String url, Map map) throws Exception { + MyXWPFDocument doc = WordCache.getXWPFDocumen(url); + parseWordSetValue(doc, map); + return doc; + } + + /** + * 解析07版的Word并且进行赋值 + * + * @Author JEECG + * @date 2013-11-16 + * @return + * @throws Exception + */ + public void parseWord(XWPFDocument document, Map map) throws Exception { + parseWordSetValue((MyXWPFDocument) document, map); + } + + private void parseWordSetValue(MyXWPFDocument doc, Map map) throws Exception { + // 第一步解析文档 + parseAllParagraphic(doc.getParagraphs(), map); + // 第二步解析页眉,页脚 + parseHeaderAndFoot(doc, map); + // 第三步解析所有表格 + XWPFTable table; + Iterator itTable = doc.getTablesIterator(); + while (itTable.hasNext()) { + table = itTable.next(); + if (table.getText().indexOf("{{") != -1) { + parseThisTable(table, map); + } + } + + } + + /** + * 解析页眉和页脚 + * + * @param doc + * @param map + * @throws Exception + */ + private void parseHeaderAndFoot(MyXWPFDocument doc, Map map) throws Exception { + List headerList = doc.getHeaderList(); + for (XWPFHeader xwpfHeader : headerList) { + for (int i = 0; i < xwpfHeader.getListParagraph().size(); i++) { + parseThisParagraph(xwpfHeader.getListParagraph().get(i), map); + } + } + List footerList = doc.getFooterList(); + for (XWPFFooter xwpfFooter : footerList) { + for (int i = 0; i < xwpfFooter.getListParagraph().size(); i++) { + parseThisParagraph(xwpfFooter.getListParagraph().get(i), map); + } + } + + } +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/excel/ExcelEntityParse.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/excel/ExcelEntityParse.java new file mode 100644 index 0000000..a1f092c --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/excel/ExcelEntityParse.java @@ -0,0 +1,215 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.word.parse.excel; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.apache.commons.lang3.StringUtils; +import org.apache.poi.xwpf.usermodel.XWPFTable; +import org.apache.poi.xwpf.usermodel.XWPFTableCell; +import org.apache.poi.xwpf.usermodel.XWPFTableRow; +import org.jeecgframework.poi.excel.annotation.ExcelTarget; +import org.jeecgframework.poi.excel.entity.params.ExcelExportEntity; +import org.jeecgframework.poi.excel.export.base.ExportBase; +import org.jeecgframework.poi.exception.word.WordExportException; +import org.jeecgframework.poi.exception.word.enmus.WordExportEnum; +import org.jeecgframework.poi.util.PoiPublicUtil; +import org.jeecgframework.poi.word.entity.params.ExcelListEntity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * 解析实体类对象 复用注解 + * + * @author JEECG + * @date 2014年8月9日 下午10:30:57 + */ +public class ExcelEntityParse extends ExportBase { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelEntityParse.class); + + private static void checkExcelParams(ExcelListEntity entity) { + if (entity.getList() == null || entity.getClazz() == null) { + throw new WordExportException(WordExportEnum.EXCEL_PARAMS_ERROR); + } + + } + + private int createCells(int index, Object t, List excelParams, XWPFTable table, short rowHeight) throws Exception { + ExcelExportEntity entity; + XWPFTableRow row = table.createRow(); + row.setHeight(rowHeight); + int maxHeight = 1, cellNum = 0; + for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + if (entity.getList() != null) { + Collection list = (Collection) entity.getMethod().invoke(t, new Object[] {}); + int listC = 0; + for (Object obj : list) { + createListCells(index + listC, cellNum, obj, entity.getList(), table); + listC++; + } + cellNum += entity.getList().size(); + if (list != null && list.size() > maxHeight) { + maxHeight = list.size(); + } + } else { + Object value = getCellValue(entity, t); + if (entity.getType() == 1) { + setCellValue(row, value, cellNum++); + } + } + } + // 合并需要合并的单元格 + cellNum = 0; + for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + if (entity.getList() != null) { + cellNum += entity.getList().size(); + } else if (entity.isNeedMerge()) { + table.setCellMargins(index, index + maxHeight - 1, cellNum, cellNum); + cellNum++; + } + } + return maxHeight; + } + + /** + * 创建List之后的各个Cells + * + * @param styles + */ + public void createListCells(int index, int cellNum, Object obj, List excelParams, XWPFTable table) throws Exception { + ExcelExportEntity entity; + XWPFTableRow row; + if (table.getRow(index) == null) { + row = table.createRow(); + row.setHeight(getRowHeight(excelParams)); + } else { + row = table.getRow(index); + } + for (int k = 0, paramSize = excelParams.size(); k < paramSize; k++) { + entity = excelParams.get(k); + Object value = getCellValue(entity, obj); + if (entity.getType() == 1) { + setCellValue(row, value, cellNum++); + } + } + } + + /** + * 获取表头数据 + * + * @param table + * @param index + * @return + */ + private Map getTitleMap(XWPFTable table, int index, int headRows) { + if (index < headRows) { + throw new WordExportException(WordExportEnum.EXCEL_NO_HEAD); + } + Map map = new HashMap(); + String text; + for (int j = 0; j < headRows; j++) { + List cells = table.getRow(index - j - 1).getTableCells(); + for (int i = 0; i < cells.size(); i++) { + text = cells.get(i).getText(); + if (StringUtils.isEmpty(text)) { + throw new WordExportException(WordExportEnum.EXCEL_HEAD_HAVA_NULL); + } + map.put(text, i); + } + } + return map; + } + + /** + * 解析上一行并生成更多行 + * + * @param table + * @param i + * @param listobj + */ + public void parseNextRowAndAddRow(XWPFTable table, int index, ExcelListEntity entity) { + checkExcelParams(entity); + // 获取表头数据 + Map titlemap = getTitleMap(table, index, entity.getHeadRows()); + try { + // 得到所有字段 + Field fileds[] = PoiPublicUtil.getClassFields(entity.getClazz()); + ExcelTarget etarget = entity.getClazz().getAnnotation(ExcelTarget.class); + String targetId = null; + if (etarget != null) { + targetId = etarget.value(); + } + // 获取实体对象的导出数据 + List excelParams = new ArrayList(); + getAllExcelField(null, targetId, fileds, excelParams, entity.getClazz(), null); + // 根据表头进行筛选排序 + sortAndFilterExportField(excelParams, titlemap); + short rowHeight = getRowHeight(excelParams); + Iterator its = entity.getList().iterator(); + while (its.hasNext()) { + Object t = its.next(); + index += createCells(index, t, excelParams, table, rowHeight); + } + } catch (Exception e) { + LOGGER.error(e.getMessage(), e); + } + } + + private void setCellValue(XWPFTableRow row, Object value, int cellNum) { + if (row.getCell(cellNum++) != null) { + row.getCell(cellNum - 1).setText(value == null ? "" : value.toString()); + } else { + row.createCell().setText(value == null ? "" : value.toString()); + } + } + + /** + * 对导出序列进行排序和塞选 + * + * @param excelParams + * @param titlemap + * @return + */ + private void sortAndFilterExportField(List excelParams, Map titlemap) { + for (int i = excelParams.size() - 1; i >= 0; i--) { + if (excelParams.get(i).getList() != null && excelParams.get(i).getList().size() > 0) { + sortAndFilterExportField(excelParams.get(i).getList(), titlemap); + if (excelParams.get(i).getList().size() == 0) { + excelParams.remove(i); + } else { + excelParams.get(i).setOrderNum(i); + } + } else { + if (titlemap.containsKey(excelParams.get(i).getName())) { + excelParams.get(i).setOrderNum(i); + } else { + excelParams.remove(i); + } + } + } + sortAllParams(excelParams); + } + +} diff --git a/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/excel/ExcelMapParse.java b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/excel/ExcelMapParse.java new file mode 100644 index 0000000..25b6a76 --- /dev/null +++ b/autopoi/autopoi/src/main/java/org/jeecgframework/poi/word/parse/excel/ExcelMapParse.java @@ -0,0 +1,80 @@ +/** + * Copyright 2013-2015 JEECG (jeecgos@163.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jeecgframework.poi.word.parse.excel; + +import java.util.List; + +import org.apache.poi.xwpf.usermodel.XWPFTable; +import org.apache.poi.xwpf.usermodel.XWPFTableCell; +import org.apache.poi.xwpf.usermodel.XWPFTableRow; +import org.jeecgframework.poi.util.PoiPublicUtil; + +/** + * 处理和生成Map 类型的数据变成表格 + * + * @author JEECG + * @date 2014年8月9日 下午10:28:46 + */ +public final class ExcelMapParse { + + /** + * 解析参数行,获取参数列表 + * + * @Author JEECG + * @date 2013-11-18 + * @param currentRow + * @return + */ + private static String[] parseCurrentRowGetParams(XWPFTableRow currentRow) { + List cells = currentRow.getTableCells(); + String[] params = new String[cells.size()]; + String text; + for (int i = 0; i < cells.size(); i++) { + text = cells.get(i).getText(); + params[i] = text == null ? "" : text.trim().replace("{{", "").replace("}}", ""); + } + return params; + } + + /** + * 解析下一行,并且生成更多的行 + * + * @Author JEECG + * @date 2013-11-18 + * @param table + * @param listobj2 + */ + public static void parseNextRowAndAddRow(XWPFTable table, int index, List list) throws Exception { + XWPFTableRow currentRow = table.getRow(index); + String[] params = parseCurrentRowGetParams(currentRow); + table.removeRow(index);// 移除这一行 + int cellIndex = 0;// 创建完成对象一行好像多了一个cell + for (Object obj : list) { + //begin-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + currentRow = table.insertNewTableRow(index++); + for (cellIndex = 0; cellIndex < currentRow.getTableCells().size(); cellIndex++) { + String text = PoiPublicUtil.getValueDoWhile(obj, params[cellIndex].split("\\."), 0).toString(); + currentRow.getTableCells().get(cellIndex).setText(text); + } + //end-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】--------//-------author:liusq------date:20210129-----for:-------poi3升级到4兼容改造工作【重要敏感修改点】-------- + for (; cellIndex < params.length; cellIndex++) { + currentRow.createCell().setText(PoiPublicUtil.getValueDoWhile(obj, params[cellIndex].split("\\."), 0).toString()); + } + } + + } + +} diff --git a/autopoi/pom.xml b/autopoi/pom.xml new file mode 100644 index 0000000..04a855c --- /dev/null +++ b/autopoi/pom.xml @@ -0,0 +1,282 @@ + + 4.0.0 + org.jeecgframework.boot3 + autopoi-parent + + 3.7.0 + pom + + autopoi-parent + http://www.jeecg.com + + + autopoi + autopoi-web + + + office 工具类 基于 poi + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + scm:git:https://github.com/zhangdaiscott/autopoi.git + scm:git:https://github.com/zhangdaiscott/autopoi.git + https://github.com/zhangdaiscott/autopoi + + + + jeecg + jeecgos@163.com + + + + + 3.7.0 + 5.2.2 + 2.9.1 + 29.0-jre + 3.10 + 1.7.30 + 6.0.13 + + + + + + org.apache.poi + poi + ${poi.version} + + + org.apache.poi + poi-ooxml + ${poi.version} + + + + + + + + + org.apache.poi + poi-ooxml-full + ${poi.version} + + + + xerces + xercesImpl + ${xerces.version} + true + + + org.apache.poi + poi-scratchpad + ${poi.version} + + + + + + + com.google.guava + guava + ${guava.version} + + + + org.apache.commons + commons-lang3 + ${commons-lang.version} + + + + + + org.slf4j + slf4j-api + ${slf4j.version} + + + org.slf4j + slf4j-log4j12 + ${slf4j.version} + provided + + + + + org.springframework + spring-webmvc + ${spring.version} + true + + + + jakarta.servlet + jakarta.servlet-api + 6.0.0 + provided + true + + + + + org.jeecgframework.boot3 + autopoi + ${autopoi.version} + + + + + + + jeecg + + + + maven-compiler-plugin + + 17 + 17 + UTF-8 + + + + + org.apache.maven.plugins + maven-source-plugin + + + package + + jar-no-fork + + + + + + + + + + release + + + + maven-compiler-plugin + + 17 + 17 + UTF-8 + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + + package + + jar + + + UTF-8 + -Xdoclint:none + + + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.6 + + + sign-artifacts + verify + + sign + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + true + + oss + https://oss.sonatype.org/ + true + + + + + + + oss + https://oss.sonatype.org/content/repositories/snapshots/ + + + oss + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 17 + 17 + UTF-8 + + + + + + + + github + LoadUp Apache Maven Packages + https://maven.pkg.github.com/loadup-cloud/loadup-packages + + + github + LoadUp Apache Maven Packages + https://maven.pkg.github.com/loadup-cloud/loadup-packages + + + \ No newline at end of file