From 9b782f258d87bae776e840ab7d959ed34dd356c8 Mon Sep 17 00:00:00 2001 From: kaiux Date: Wed, 23 Oct 2019 16:12:11 +0800 Subject: [PATCH 01/38] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=AF=B9Excel=E6=89=B9?= =?UTF-8?q?=E6=B3=A8=E7=9A=84=E8=AF=BB=E5=8F=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/analysis/v03/XlsSaxAnalyser.java | 38 ++++++++ .../excel/analysis/v07/XlsxCellHandler.java | 8 ++ .../excel/analysis/v07/XlsxRowHandler.java | 26 ++++++ .../excel/analysis/v07/XlsxSaxAnalyser.java | 17 +++- .../v07/handlers/CountRowCellHandler.java | 5 ++ .../v07/handlers/DefaultCellHandler.java | 5 ++ .../handlers/ProcessResultCellHandler.java | 5 ++ .../read/metadata/holder/ReadRowHolder.java | 32 +++++++ .../demo/read/DemoCellCommentsListener.java | 85 ++++++++++++++++++ .../easyexcel/test/demo/read/ReadTest.java | 17 ++++ src/test/resources/demo/demo.xlsx | Bin 10117 -> 12291 bytes 11 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index 21977a4..e5df4bf 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -3,10 +3,12 @@ package com.alibaba.excel.analysis.v03; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.TreeMap; +import com.alibaba.excel.util.StringUtils; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; @@ -19,6 +21,11 @@ import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.ss.usermodel.Comment; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Workbook; +import org.apache.poi.ss.usermodel.WorkbookFactory; +import org.apache.poi.ss.util.CellAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -74,11 +81,18 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { private HSSFWorkbook stubWorkbook; private List recordHandlers = new ArrayList(); private AnalysisContext analysisContext; + private Workbook poiWorkbook; + private Map rowComments; public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) { this.analysisContext = context; this.records = new TreeMap(); this.poifsFileSystem = poifsFileSystem; + try { + this.poiWorkbook = WorkbookFactory.create(poifsFileSystem); + } catch (IOException e) { + e.printStackTrace(); + } analysisContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem); } @@ -139,6 +153,7 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { thisRow = handler.getRow(); thisColumn = handler.getColumn(); cellData = handler.getCellData(); + handleComments(thisRow, thisColumn); if (cellData != null) { cellData.checkEmpty(); if (CellDataTypeEnum.EMPTY != cellData.getType()) { @@ -170,6 +185,26 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { processLastCellOfRow(record); } + public void handleComments(int row, int col) { + if (null == this.poiWorkbook || null == analysisContext.readSheetHolder() || row < 0 || col < 0) { + return; + } + Sheet currentSheet = poiWorkbook.getSheetAt(analysisContext.readSheetHolder().getSheetNo()); + Map cellComments = currentSheet.getCellComments(); + if (CollectionUtils.isEmpty(cellComments)) { + return; + } + Comment comment = cellComments.get(new CellAddress(row, col)); + if (null == comment) { + return; + } + String commentsStr = comment.getString().toString(); + if (!StringUtils.isEmpty(commentsStr)) { + rowComments = rowComments == null ? new HashMap(8) : rowComments; + rowComments.put(col, commentsStr); + } + } + private boolean ignoreRecord(Record record) { return analysisContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid && record.getSid() != BOFRecord.sid; @@ -188,6 +223,9 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { } analysisContext.readRowHolder( new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration())); + if (!CollectionUtils.isEmpty(rowComments)) { + analysisContext.readRowHolder().setRowComments(rowComments); + } analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext); records.clear(); lastColumnNumber = -1; diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java index a4db7f4..3068725 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java @@ -34,4 +34,12 @@ public interface XlsxCellHandler { * Tag name */ void endHandle(String name); + + /** + * Set the comment of the cell + * + * @param comment + * cell comment + */ + void handleComments(String comment); } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java index ececb47..b6702c1 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java @@ -2,7 +2,12 @@ package com.alibaba.excel.analysis.v07; import java.util.List; +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.util.StringUtils; +import org.apache.poi.ss.util.CellAddress; +import org.apache.poi.xssf.model.CommentsTable; import org.apache.poi.xssf.model.StylesTable; +import org.apache.poi.xssf.usermodel.XSSFComment; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; @@ -17,6 +22,12 @@ public class XlsxRowHandler extends DefaultHandler { private List cellHandlers; private XlsxRowResultHolder rowResultHolder; + private CommentsTable commentsTable; + + public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable, CommentsTable commentsTable) { + this(analysisContext, stylesTable); + this.commentsTable = commentsTable; + } public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable) { this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, stylesTable); @@ -33,6 +44,7 @@ public class XlsxRowHandler extends DefaultHandler { for (XlsxCellHandler cellHandler : cellHandlers) { if (cellHandler.support(name)) { cellHandler.startHandle(name, attributes); + handleComment(cellHandler, attributes.getValue(ExcelXmlConstants.POSITION)); } } } @@ -52,4 +64,18 @@ public class XlsxRowHandler extends DefaultHandler { rowResultHolder.appendCurrentCellValue(ch, start, length); } } + + private void handleComment(XlsxCellHandler cellHandler, String address) { + if (StringUtils.isEmpty(address) || null == commentsTable) { + return; + } + XSSFComment xssfComment = commentsTable.getCellComments().get(new CellAddress(address)); + if (null == xssfComment) { + return; + } + String comments = xssfComment.getString().toString(); + if (!StringUtils.isEmpty(comments)) { + cellHandler.handleComments(comments); + } + } } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java index dd468b4..591932e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java @@ -17,6 +17,7 @@ import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.eventusermodel.XSSFReader; +import org.apache.poi.xssf.model.CommentsTable; import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.usermodel.XSSFRelation; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; @@ -46,6 +47,14 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { private AnalysisContext analysisContext; private List sheetList; private Map sheetMap; + + /** + * excel comments + * key: sheetNo + * value: CommentsTanle + */ + private Map commentsTableMap; + /** * Current style information */ @@ -77,6 +86,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { stylesTable = xssfReader.getStylesTable(); sheetList = new ArrayList(); sheetMap = new HashMap(); + commentsTableMap = new HashMap(); XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); int index = 0; if (!ite.hasNext()) { @@ -86,6 +96,10 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { InputStream inputStream = ite.next(); sheetList.add(new ReadSheet(index, ite.getSheetName())); sheetMap.put(index, inputStream); + CommentsTable commentsTable = ite.getSheetComments(); + if (null != commentsTable) { + commentsTableMap.put(index, commentsTable); + } index++; } } @@ -181,7 +195,8 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { analysisContext.readWorkbookHolder().getGlobalConfiguration()); if (readSheet != null) { analysisContext.currentSheet(readSheet); - parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(analysisContext, stylesTable)); + Integer sheetNo = readSheet.getSheetNo(); + parseXmlSource(sheetMap.get(sheetNo), new XlsxRowHandler(analysisContext, stylesTable, commentsTableMap.get(sheetNo))); // The last sheet is read analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext); } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java index ea63409..c92ec6c 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java @@ -39,4 +39,9 @@ public class CountRowCellHandler implements XlsxCellHandler { } + @Override + public void handleComments(String comment) { + + } + } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java index 0d44a95..2dc0fdb 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -160,6 +160,11 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder } } + @Override + public void handleComments(String comment) { + analysisContext.readRowHolder().addComments(curCol, comment); + } + @Override public void appendCurrentCellValue(char[] ch, int start, int length) { String currentTag = currentTagDeque.peek(); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java index 9581646..32b75ed 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java @@ -45,4 +45,9 @@ public class ProcessResultCellHandler implements XlsxCellHandler { rowResultHandler.clearResult(); } + @Override + public void handleComments(String comment) { + + } + } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java index 9916015..24079f7 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java @@ -3,6 +3,10 @@ package com.alibaba.excel.read.metadata.holder; import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.Holder; +import com.alibaba.excel.util.CollectionUtils; + +import java.util.HashMap; +import java.util.Map; /** * sheet holder @@ -24,6 +28,34 @@ public class ReadRowHolder implements Holder { */ private GlobalConfiguration globalConfiguration; + /** + * Return row comments + * key: col index + * value: comments + */ + private Map rowComments; + + public Map getRowComments() { + return rowComments; + } + + public void setRowComments(Map rowComments) { + this.rowComments = rowComments; + } + + public void addComments(Integer index, String comments) { + this.rowComments = this.rowComments == null ? new HashMap(8) : this.rowComments; + this.rowComments.put(index, comments); + } + + public String getComments(Integer index) { + if (CollectionUtils.isEmpty(rowComments)) { + return null; + } else { + return rowComments.get(index); + } + } + public ReadRowHolder(Integer rowIndex, GlobalConfiguration globalConfiguration) { this.rowIndex = rowIndex; this.globalConfiguration = globalConfiguration; diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java new file mode 100644 index 0000000..733005c --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java @@ -0,0 +1,85 @@ +package com.alibaba.easyexcel.test.demo.read; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.exception.ExcelDataConvertException; +import com.alibaba.excel.util.CollectionUtils; +import com.alibaba.fastjson.JSON; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * 读取单元格的批注 + * + * @author: kaiux + * @date: 2019-10-23 14:10 + **/ +public class DemoCellCommentsListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoCellCommentsListener.class); + /** + * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 + */ + private static final int BATCH_COUNT = 5; + List list = new ArrayList(); + + /** + * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。 + * + * @param exception + * @param context + * @throws Exception + */ + @Override + public void onException(Exception exception, AnalysisContext context) { + LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage()); + if (exception instanceof ExcelDataConvertException) { + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception; + LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(), + excelDataConvertException.getColumnIndex()); + } + } + + /** + * 这里会一行行的返回头 + * + * @param headMap + * @param context + */ + @Override + public void invokeHeadMap(Map headMap, AnalysisContext context) { + Map rowComments = context.readRowHolder().getRowComments(); + LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap)); + if (!CollectionUtils.isEmpty(rowComments)) { + for (Integer i : rowComments.keySet()) { + LOGGER.info("解析到头数据低{}列包含批注:{}", i, rowComments.get(i)); + } + } + } + + @Override + public void invoke(DemoData data, AnalysisContext context) { + LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); + if (list.size() >= BATCH_COUNT) { + saveData(); + list.clear(); + } + } + + @Override + public void doAfterAllAnalysed(AnalysisContext context) { + saveData(); + LOGGER.info("所有数据解析完成!"); + } + + /** + * 加上存储数据库 + */ + private void saveData() { + LOGGER.info("{}条数据,开始存储数据库!", list.size()); + LOGGER.info("存储数据库成功!"); + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java index 9ebafa4..112c529 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java @@ -161,6 +161,23 @@ public class ReadTest { EasyExcel.read(fileName, DemoData.class, new DemoHeadDataListener()).sheet().doRead(); } + /** + * 读取单元格批注 + * + *

+ * 1. 创建excel对应的实体对象 参照{@link DemoData} + *

+ * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} + *

+ * 3. 直接读即可 + */ + @Test + public void commentsRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + // 这里 需要指定读用哪个class去读,然后读取第一个sheet + EasyExcel.read(fileName, DemoData.class, new DemoCellCommentsListener()).sheet().doRead(); + } + /** * 读取公式和单元格类型 * diff --git a/src/test/resources/demo/demo.xlsx b/src/test/resources/demo/demo.xlsx index 303733cf81ddf2a0f6760f487d0552aec56f2bef..48d3f87abd209ef857fe68ace222647bf9254ab7 100644 GIT binary patch literal 12291 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 literal 10117 zcmaia1yo$ivi9Ka?h-sekRZX`A-KEypuvN?1ozz+nN;BT#0A@A>*a1Lo<2A<#h94rpWlM)rve{pkkuFR~gC zCw*2B06-BG06_jHnVyXey|b0&=jb*GFh+FYOP@#NDj+i*sl2f~I0l=3+YXQMLbZ1i z*&27?B+zzM;0Q_cnho}2KoZP&Azs_O$G3!(Q-PD~yh1fNknk@M>0!)+t>!AY4K!E# zC;ATUIMG$PMW6kBfFReJgoJCMOI+YgUbM=pv{%VJLwsIrx3J{|&!m-pG%&)d(03bDab30Ca)@~s zwRslOo6~gcQSKck`}7CMR?ut4Q7WD-#@Fbt|RR_H0bpe3l8i3+uP+Ljk_Q@hqpF5?}9*j4i zskLk25V<=y;V>pB5y!k!_DGgr=#h=e{6d9^Nr??VEE1`}EvmLa1w>bxj^BhDcUUuc&9m2Iwv}>U^%svI;AwiA z{fMk4tF1(sgf3lt<)bI5TKd?6EMYQPtPrm|9?(D=cod)=^7YTV6Y_)hDG7JPBkslP zg3<&TXW57}g~dhWk|}IE3>$vP2Rt$bc%st;sC?bEo4|U8>)$;G*b`jNmcM+)zY`$- zCU64US=gHz89BW4FDVrQlH5;H^q+hX_Wz>&#lraO5s23S&Jm+`FH-Jvsy0qVy!l2W zGm*E$Y8F%Em|&v63O>O~7+E);zX*bghU&H>>4Ow_dTY~m%65^&}kG>?jYGv^!*%5On%}jg2IX; zH9_+&YV7g~zxT}uLLD%J=NU!tStF*XiiwjwLaIlXow~yO%qOi?9>V5kJ~s0DFgM>L zSXa>ZSv*x5Q&%xJTu1FGj@!;0j@#EHbcC4)!C&X3SJE(ymYKXm+8E?2-lLIyUq#ce zb1{GbZmnyFr!Ie;m+yuuloLKyTe`^FKD3h^@&(*~%&X^ITTGc-H+aOnP-Q6?s@O<| zB-DJHTP6g3-aph4n{;cKzJ)__W^^(zReR~VX{1(EDA zXMB@6ve>y0s;3yTlOy8eDk@B&iFY5 z-(CfA6I5{tJ?lY$h2CY?tI_CaXUq=P_gT)k(#8goqh%JWhBfc*>JrLJ=y|^_;UV>X z3b>|835-)(KZ?X6cNM^ox_YiS;4+tFDd{%8t9jjX7`*cgFxtAg7Vz^(kEQ zamC#>gJ<3~t2ZK1L>l3~qJ zkVi@l!+9eZj5aq~M4p-R-J&R6`DjsL53fkaNeAuB6cgP#@VgNfqJfD(GrGoTbeq}; zcPdtEdWiY>k`d);Up$IsR4$MGB|3qnX~Jt8E{w1rV^EqnGzZL4w_O%Cf>+GPMPWBUEb%~@wN zAO{?(%sTNkzuClxP_!yCSDB3~njkDAU;x2ju;9$}xFwi_K?GNBf=$DDeBdJdgf`zY z5$8x6mQWoWWzx_?DlPG)>Rsp7)X-)FOI2N~binJ`NbDxGh=Z7+^sI;~6>VfvT3J)) zFj$h=($%ACVwMe7D{-*2)GAy!>?+?54H26>iix<@hJ(>U+Zp203L~PC3>WRZwcxz& zUH0F zJ8iCj6Gu-g0>DQcU`7Dq_XI(S3m-m$-Jr~0GPk-`nY(>f+V6N0y4xX zBKXur0evW5h>U<`u2z9`g*OZURT)sRU1;5jp(&OOLHJgELft}u6f6{=_?P4oQ2<9L zfOZo^8MZaY20)x1Ij2Ef`pRnnnlBLBYl5p){kLpyDS+56ax0OJ=hH+cPXTxky7KIR zqb0S^#IhSGKHqxkVFwul^q7YLl_xaGZxKn1lb5Wp&IXKl1h*0iNgW=+mZ_nK*5nno zBFY==LXp-ujRUKem4)q0E6bXE;JO`vQ(*iWaVgvwM;{7@Kp%LKw|I!pb1*fsGI|jqe}?Ufi-ZIK67haV4}X#UBK~!F?W-*U z@mTOZMOQp44m>PIDYWG2J}19b)7w>MnHeVh9BRKg;lwi|)6ghAw@OCV$>+u|(0JtK zC7uF~x|*J8UvAU5uY9aUhaPl|N7sXP%BBx4PGT}XJ_o5o zHEk0nSkJm&*bk#IMAwY$2xK^Xdeknrsvcbr*Nv(RC9;W!P$4~IllS55q*%1&rw5>A z!L=*9&r7Z(hwvzA%L1`e&9oxBsYs-!aF4#OpTi_((zERo_5`)27iDd*YHkv{PW^^Gz zLapTQiQVRMCBj#%Slj?p;*O9mF=;fWE*@}uC{aQFN@K4nX!`zX5}iQ=Gi|XOABv)N zk3?OuFr22Tp=OW!Js8*fz2oJk{J_hP?2Vp}M+=wn@n3ADI3ONIZwtqd<9^%;X5e3m??fyTjWDlai^dA5^fK^o+HHoUWo-CR@+QAltWd1|>| z6xh#=)S7QpEUg#=#k$LFWQe^M9BA9a$SPA;pVN+tm zr=Jy>w(8~=Yw8p#-(5C0j-`20De#rb+(6wt8iatu`>jT`@T;S~YAF+&8iSPml!5`Z zq{$S+MPUH}U1iccFNW^0gkz!Qg0MA!Xo=}jv8un3z(s!ho0WQb?|iU!_MM2JSR;!v zxZ$r$XRon$lnUp*&b+mY5*TS>N>*Xq6kelP-1TFZ=&kU;4HVvkvO^L;&n77AU7Gtj zfP9bmvGrKMX)&kM_VU<&2@(N6$`~Zegd(dmApyo|40FxJYdwHXfi60GG1e{xr}_bUXTYK$$yO~u29G}V{s<-?(N*L%AsCFp{2 zlL*24HPV{|be4_Xv6aoqOm<4i3mWZ^Z+F@MSvT!>kCWI4XLMA~w2UH3$j1-ri#<}-rNN9dA9 z*nH0c+(FL7sHob8bGZ%7RsSyzQSiq>IXt7TL$?Lysj=UCQ%Tj4@ZfLuoWmwyedpah)|Zj5G9D|9%=n{Nao#4!%k#(yopp?W;8q1se_#4YP?Rwg zBvE(FfWhC=dY)Qan`9SipX~5mlF|3eY9cv_Okb(Y2yG1APxKs3$WvuxB!|~=^Hff* zN>aV)Q8eEf9?}c5F45|IRB_CZu583<8Ag*vPwHez0%>CX#t&gk@ul{?Oub)gCkABr z6q}#wM0(sWZlvbwjpE8gn~O-y|%2)>$%8WTXbt539k?EPcy{z8tGjTB>S~`(}!Hxi$0@w?lUU zncODI?~G{rvET@YQLlt;9AwddHe~76p8`@3OwMDFl~4>zjFa83>j&bj?r2Vl+1RAG z2HjlAP~F(TH6ded{2ti@Pj2PuM!(VK+KL)3XHA8H1!wK>_|i-^HLT$39i+)F3Sv3fK#Q}wL>3g& zdN>-X<7mq+7u5l&l%I0?EP@v6;EdaI7-o5#w*XwUd14zP$aG0@+`L8`$H7u%VZkmC z%pMt1ehRN%PjWIw67}1uIuiX(l~7$x6Jdd!;LY-z0PU-t$7VM^MC~a0`>oO39pf5T zL02W4%hK?fOPB1bNRL9`( zFI`-V%^v(X5J;8nb}%g_#-(KtCVM2-=J!jRH{~gdm5!L|tC}$GA;eNwf0?w%;Bi61&_=erg47@Oy}6U0udr28Fz3%=+-`4YyH4Yq*a29v-Zg2x?_~9 zq$3mWS+N)`tRQhMjJ`gC(93K_K_RKfBM!vMySMN*HhwjLov!=FAe;W3k%wPOL6K@7FR zGXc?VmAWCQO9BXdgRs=m9kHuj0$*m+!u30Z(uD)o@V~OOSq=D8%)_$}kiKS$H87GB zMs>mh-AbB{h;a~OK{!`h>b;nhqlBkhWLXvpi6~FU=YRj*ACc+A*q@7Sa~rJ1KC7Va zZsQd+SN8!49pY@AC;C_SA{ZhvC*FF!2JYQyA4GeC%V3(Yc9*!mXro%Z{iZC#{eA5H zEW;#Yx0$Ley8w?WcNMMD%%SLINvUW7JcPNT6od|jWQnF3OWgWAbi>znX?p0^#gMhE z<~7FBjEY*+Vjs0+D$2aw1ubwLF^J1C*DQYW(KEVdNBXD*PWUO3rF(yyj!didoY1R9 zy=Is|yY(d3i*TFnLpp_Iu_xD4&OT9D+3*RW06Ue)3XW<)O~hdqW=J^!4zn_{q*)keVg=gShBa#Fz2s1sk25J#N02r{eB+lTR5`G*ehovpjQJ0zq~Jl`v{XQ7lJ)vO&Mmmk`k z4jZb%?im~$cW?vi4plRvmTa@S-C6XtQ+16)L_3)2F>-7T&1GQW;Y7$Oy<1z~NvzkP zXcF7WmrS+p%yhJ!=;olQxab*DowW5JulYq~_P`m0CG@=Jq`Ao;O_>r2AWaX4=a<35 z2??D|lql7NVN5Wd9sEWHD!DnjR&x$9Mv7y$WqKk2+?oi`R@m*lhKr`F9eJxKf%(2% zP*~VVS#u%F4(@w{#k)ZkMODwq_cV185?8kAYAFFM?$y)5ll>zkQi>vhIhrvs`=t>E zM0H?&{^W{%Nc;5aUi_(dr1QEl1FlJgtD zXR7`n=M(*)R^p%F*a&4nr#JvBR^fGnOPIX8s}F`s(YoU7M?g(JD%Xu?I61H#ImVa@ z%cnugHPa(B9HJ4b=52;@Fv#U=Rx(XYM&$0_X0M%{U2-iDH$kxdn)knOl<-hP-6MXvcL!wK|im z`EZS@)sEt{qjMF_5N%Jkia&ib;TwWW9S1$aqn=7a)KkiA941MkPgXtbuXzmeh+?r+ z-BmJ8HC2f|dT{2e?m_XT&0x0yL&fgMGN;lsPPUF$e{@`~gIkz+nsQc*q!J_DijIQE zc=FR4teGdYM)L3*V#ToHk&YPR!A2Uvy zmqTfuHxGsqG(;Q%s@;z_yVu)L!D2iPd{+EhhWg+uVm(>PJ|miF0pG7q$DURdzcdmQ zghYN4p*XwnBfBMx=MI2sbT_kzD!}8OmF_QQ1RWJ0c|?)}UHO^o4mAU3(KQjZJ5Wv< zTQtgcsjY{d$5NL?6ksV7+Zv=oZ8qMjtH>9-9WKOrAT7%}ER9wXY&cfb(T#Y<2O*SH zg_gha;{y%e1su$D#*X8SG&~03fIRB3wvgS$=BCLd8Y+)NhBQiKSW6?z!+ zPeRWJD}g>yBr4jBfs#=^d?hoUEc5n$lvtM?OP-P?0)217oFb{YR#7Zsstkh1QwR6m zmdfTjoz4u}eyZ? zvWI0#2~|i2BwG}2Dmol?hG8B={Upk>dJ3FACxu8S(eqkzx{y`1kd}Ocy$(m ziPTs=9LT`9Z`HDaGFE%C+DB?U9%Dy6SlE8?UR*;wlL!VUrh!b$E7PZVKGh7-s6*5O zfio$hJi~(M!_sHu#_f08bAs;YB_B<;{H9`3=#mH@!CL?zA3vqJb~JDMCkjjEb(d#f zYKncaA_y#pI^uzLmlRyI{?Rf!XNKM2mRCPga`2YTVW7wgyXNzJc=E!+%sfkYk-Ak2 z*g5?D+043uaQe;l7w`G=rqAIf1cKUNtyY580E5j1B|94sHAj5=9l z6+*G%h4v8n{!ZE$qC@@%zkvuP;Rr+D+!5+9Q557t=9mQ6wDyOEgIRQF^-Oy?96AN| zC}`&9`gUZxZ4;I}Syc_7LWmkkTx(Qe?!kKNTZ!q1>3-_TaP)VW^6E+>>>;Q{LWSOj zc@wPu>>#5%Clzs=Em&wv@REbHo^G0ryg!?oxtvt;)7dt|)CafN?rpx-?bFkPeYhBZ z{|M}uHFa4fUd`y_PXaf3+D!c7K2#H|Bgxb4~Hscn{1ydbz<-yt7SfWj= z5w0Hi=eX~79PQ5Dzn=AUe1P~9!8FacyDU!#!ab#8k$xliTqV&50xf=JU!(eDIv9|J zFU9VBS=@HsdK4&1(~$5v_|kwFS*?g0OjOd%k*^=(P-Y41cbKPfG}||+r>hU}j6fMl zgRIIy!b=1{uDR5+H>G=80^6h?yz5~U;kffQ~B z(yLVZ_8=fM(dIy{I_EaW+YDvJR}sYs1dYZjFrf=Rk+;4fd-QG7XTx_#C+=&L3Q=YA z)O+o@=@OIFudFW13@u@MutLMQ@Lk^*Tu75?oNl|vJKtetv-zlc80M*5NB85ztWsNx zL9c%-q&miXC*#LEcU^APJ2cnyaiM(dRow8zrZa%9~vK@ep`I90^DCT^v{%~(L+z$7rE=u=MZ_LS=tE$WyawR>7KNqhgYK1 z<1htUwAy}i6TckocsX1ODGXVrNhv67|< zFc(FecJPLs6a8C1-wm$VS$eW4EqD20ra(^W7_*UWMOnUdP8Q+(cf1C#d|8{UWvzQp zM7q)mWu>{kFVFfPq!eS3qwM_ z8?tlc={t0i2rMZzrb7_c^iNa>`MIvyVoRIUttmqkLY^^j%{Ml-+1?g4qEX!^#^Fbv zwfjiM)ZMuj@4~~PBW8C(SM2ovO@{s(oKVQkMdwd2iaxmo+^6f4Tlh`(&#nCn-KJ=1 z3%}>;g8xGx!zFGFQEZj%o7{@254T`G5hBWHKcsl?E(y3wFfiSsv_TKyT^1>sXZBle zWjyqASe?PtqJ0E(0*cPVy)Re$23}F=@4lXc_yj3JHjOo<(x9?O+edD<&nKbDg=5p- z5i_aCu}4R)$M@zlN9RIS&-7MXJmp-*;Mf^|_adPzE!RXQ6Ee~Scfl&V*vaBTX4xES zy5RLl_9h%ka%#A0lWpu~6!zRSF`jBH8VRHa&W5!DHX&!yh7{v=&D9*;s@exX`x~-z z2V)EP>v(t_lC&O@lYU$JC`(C>Yh0;|A%@K#Ti-9=e0))NZo7O1Z~f!};vjx!jx_{< z)(%G24myf1Hb(YZ&t9N3w$Hl#*$c$oAVqyu($|$!!tfR*>ccEN1JiU9pj`>%3TR(+ zLd`&p1(ll?vfKN%Ie2csuAM}qCcw9EIe4S?iCi~VVRq2&;+=;yk*bfJDmje_iHQXt zE8+YCe7*%zqHN9g)Huc)(LuR*U2x+;-`u2jh*zWt9bs-HoBELM!@KkL+m_&XW2zPv zBS$!}l?D1IRauL8lpr*QKgNvp26~f@nn&e@?0OTF31mmgE;G?S8A;iA*Mi4aTWH2P=SLg20 zbXr~)M_M9|jutDR+06S%PzZe@8v<8FE2<%YomY??QPW8gJYKS@ph5~pZnF*9cC;6> zqM9l;j$q+iICeRb5RKOtoKV9(sURO47#{7c7jQl#vgW4YWbQ-U8HYxGNH?!{Y69jQ zl%rU08`!M#JzOmfWOLj+9dRI_=)aD$-_0*C4fM330U!Y4r*~fx0N`KD^;^LI?SY;J z{O+S!CH&hT{i*b&M|$S?trUvre|Ua9LH|wJbG_pCcy8Kx9{=d?`BUG^4xeY@-})&3 z$@ZUqpO+B5>|ObrJM?L1|E2VQI$2(_zihqun;q`SgZ$0@S0l!MTl5phf5!8oIl%wZ zn((~be>cgWD7_*6hrfC`(U*?xSf>0zueqQIWOa;zvb}a|9cemQo_r0-QN;m zQGZMLD|z?d!1{CTq)%txUxlle8edkp{?;h|Pqx47T`vW^40Zk%;7#yL?>}MtZR~h1NGPR|1*PMmtW;` WSxJcJpaX#V^pbwkM*8ac+y4XORCGoF From b1e12aa4185a00a113626b9d0113cd2c055919ae Mon Sep 17 00:00:00 2001 From: zhouqinglai Date: Thu, 24 Oct 2019 13:07:34 +0800 Subject: [PATCH 02/38] =?UTF-8?q?[fix]=20=E8=A7=A3=E5=86=B3=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E5=AD=98=E5=9C=A8=E7=9A=84=E7=A9=BA=E6=8C=87=E9=92=88?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/alibaba/excel/context/WriteContextImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index f136ea0..6e691fd 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -429,7 +429,9 @@ public class WriteContextImpl implements WriteContext { OutputStream outputStream = encryptor.getDataStream(fileSystem); opcPackage.save(outputStream); } finally { - opcPackage.close(); + if (opcPackage != null) { + opcPackage.close(); + } } return fileSystem; } From f065e370ab2fa7891aa5838cef4b855cfc9ade2f Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Wed, 4 Dec 2019 18:51:58 +0800 Subject: [PATCH 03/38] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- .../excel/constant/BuiltinFormats.java | 204 +++ .../com/alibaba/excel/util/DateUtils.java | 200 ++- .../excel/util/NumberDataFormatterUtils.java | 154 ++ .../easyexcel/test/demo/read/ReadTest.java | 16 +- .../easyexcel/test/demo/web/WebTest.java | 2 +- .../easyexcel/test/temp/Lock2Test.java | 2 +- .../test/temp/dataformat/DataFormatData.java | 16 + .../test/temp/dataformat/DataFormatTest.java | 127 ++ .../test/temp/dataformat/DataFormatter1.java | 1292 +++++++++++++++++ .../easyexcel/test/temp/simple/Wirte.java | 2 +- 11 files changed, 2005 insertions(+), 14 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/constant/BuiltinFormats.java create mode 100644 src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatData.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatter1.java diff --git a/README.md b/README.md index 1251ebd..72cc016 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja /** * 最简单的读 *

1. 创建excel对应的实体对象 参照{@link DemoData} - *

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + *

2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} *

3. 直接读即可 */ @Test @@ -81,7 +81,7 @@ DEMO代码地址:[https://github.com/alibaba/easyexcel/blob/master/src/test/ja /** * 文件上传 *

1. 创建excel对应的实体对象 参照{@link UploadData} - *

2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} + *

2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} *

3. 直接读即可 */ @PostMapping("upload") diff --git a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java new file mode 100644 index 0000000..7b3c5bb --- /dev/null +++ b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java @@ -0,0 +1,204 @@ +package com.alibaba.excel.constant; + +import com.alibaba.excel.util.StringUtils; + +/** + * Excel's built-in format conversion.Currently only supports Chinese. + * + *

+ * If it is not Chinese, it is recommended to directly modify the builtinFormats, which will better support + * internationalization in the future. + * + *

+ * Specific correspondence please see: + * https://docs.microsoft.com/en-us/dotnet/api/documentformat.openxml.spreadsheet.numberingformat?view=openxml-2.8.1 + * + * @author Jiaju Zhuang + **/ +public class BuiltinFormats { + + public static String[] builtinFormats = { + // 0 + "General", + // 1 + "0", + // 2 + "0.00", + // 3 + "#,##0", + // 4 + "#,##0.00", + // 5 + "\"$\"#,##0_);(\"$\"#,##0)", + // 6 + "\"$\"#,##0_);[Red](\"$\"#,##0)", + // 7 + "\"$\"#,##0.00_);(\"$\"#,##0.00)", + // 8 + "\"$\"#,##0.00_);[Red](\"$\"#,##0.00)", + // 9 + "0%", + // 10 + "0.00%", + // 11 + "0.00E+00", + // 12 + "# ?/?", + // 13 + "# ??/??", + // 14 + "m/d/yy", + // 15 + "d-mmm-yy", + // 16 + "d-mmm", + // 17 + "mmm-yy", + // 18 + "h:mm AM/PM", + // 19 + "h:mm:ss AM/PM", + // 20 + "h:mm", + // 21 + "h:mm:ss", + // 22 + "m/d/yy h:mm", + // 23-26 No specific correspondence found in the official documentation. + // 23 + null, + // 24 + null, + // 25 + null, + // 26 + null, + // 27 + "yyyy\"5E74\"m\"6708\"", + // 28 + "m\"6708\"d\"65E5\"", + // 29 + "m\"6708\"d\"65E5\"", + // 30 + "m-d-yy", + // 31 + "yyyy\"5E74\"m\"6708\"d\"65E5\"", + // 32 + "h\"65F6\"mm\"5206\"", + // 33 + "h\"65F6\"mm\"5206\"ss\"79D2\"", + // 34 + "4E0A5348/4E0B5348h\"65F6\"mm\"5206\"", + // 35 + "4E0A5348/4E0B5348h\"65F6\"mm\"5206\"ss\"79D2\"", + // 36 + "yyyy\"5E74\"m\"6708\"", + // 37 + "#,##0_);(#,##0)", + // 38 + "#,##0_);[Red](#,##0)", + // 39 + "#,##0.00_);(#,##0.00)", + // 40 + "#,##0.00_);[Red](#,##0.00)", + // 41 + "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)", + // 42 + "_(\"$\"* #,##0_);_(\"$\"* (#,##0);_(\"$\"* \"-\"_);_(@_)", + // 43 + "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)", + // 44 + "_(\"$\"* #,##0.00_);_(\"$\"* (#,##0.00);_(\"$\"* \"-\"??_);_(@_)", + // 45 + "mm:ss", + // 46 + "[h]:mm:ss", + // 47 + "mm:ss.0", + // 48 + "##0.0E+0", + // 49 + "@", + // 50 + "yyyy\"5E74\"m\"6708\"", + // 51 + "m\"6708\"d\"65E5\"", + // 52 + "yyyy\"5E74\"m\"6708\"", + // 53 + "m\"6708\"d\"65E5\"", + // 54 + "m\"6708\"d\"65E5\"", + // 55 + "4E0A5348/4E0B5348h\"65F6\"mm\"5206\"", + // 56 + "4E0A5348/4E0B5348h\"65F6\"mm\"5206\"ss\"79D2\"", + // 57 + "yyyy\"5E74\"m\"6708\"", + // 58 + "m\"6708\"d\"65E5\"", + // 59 + "t0", + // 60 + "t0.00", + // 61 + "t#,##0", + // 62 + "t#,##0.00", + // 63-66 No specific correspondence found in the official documentation. + // 63 + null, + // 64 + null, + // 65 + null, + // 66 + null, + // 67 + "t0%", + // 68 + "t0.00%", + // 69 + "t# ?/?", + // 70 + "t# ??/??", + // 71 + "0E27/0E14/0E1B0E1B0E1B0E1B", + // 72 + "0E27-0E140E140E14-0E1B0E1B", + // 73 + "0E27-0E140E140E14", + // 74 + "0E140E140E14-0E1B0E1B", + // 75 + "0E0A:0E190E19", + // 76 + "0E0A:0E190E19:0E170E17", + // 77 + "0E27/0E14/0E1B0E1B0E1B0E1B 0E0A:0E190E19", + // 78 + "0E190E19:0E170E17", + // 79 + "[0E0A]:0E190E19:0E170E17", + // 80 + "0E190E19:0E170E17.0", + // 81 + "d/m/bb", + // end + }; + + public static String getBuiltinFormat(Integer index) { + if (index == null || index < 0 || index >= builtinFormats.length) { + return null; + } + return builtinFormats[index]; + } + + public static String getFormat(Integer index, String format) { + if (!StringUtils.isEmpty(format)) { + return format; + } + return getBuiltinFormat(index); + } + +} diff --git a/src/main/java/com/alibaba/excel/util/DateUtils.java b/src/main/java/com/alibaba/excel/util/DateUtils.java index a581a95..dfc8d20 100644 --- a/src/main/java/com/alibaba/excel/util/DateUtils.java +++ b/src/main/java/com/alibaba/excel/util/DateUtils.java @@ -1,10 +1,15 @@ package com.alibaba.excel.util; +import java.text.Format; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; -import com.alibaba.excel.exception.ExcelDataConvertException; +import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.ExcelNumberFormat; +import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; /** * Date utils @@ -12,6 +17,9 @@ import com.alibaba.excel.exception.ExcelDataConvertException; * @author Jiaju Zhuang **/ public class DateUtils { + + + public static final String DATE_FORMAT_10 = "yyyy-MM-dd"; public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss"; public static final String DATE_FORMAT_17 = "yyyyMMdd HH:mm:ss"; @@ -101,4 +109,194 @@ public class DateUtils { } return new SimpleDateFormat(dateFormat).format(date); } + +// +// /** +// * Determine if it is a date format. +// * +// * @param dataFormat +// * @param dataFormatString +// * @return +// */ +// public static boolean isDateFormatted(Integer dataFormat, String dataFormatString) { +// if (cell == null) { +// return false; +// } +// boolean isDate = false; +// +// double d = cell.getNumericCellValue(); +// if (DateUtil.isValidExcelDate(d)) { +// ExcelNumberFormat nf = ExcelNumberFormat.from(cell, cfEvaluator); +// if (nf == null) { +// return false; +// } +// bDate = isADateFormat(nf); +// } +// return bDate; +// } +// +// private String getFormattedDateString(Cell cell, ConditionalFormattingEvaluator cfEvaluator) { +// if (cell == null) { +// return null; +// } +// Format dateFormat = getFormat(cell, cfEvaluator); +// synchronized (dateFormat) { +// if(dateFormat instanceof ExcelStyleDateFormatter) { +// // Hint about the raw excel value +// ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted( +// cell.getNumericCellValue() +// ); +// } +// Date d = cell.getDateCellValue(); +// return performDateFormatting(d, dateFormat); +// } +// } +// +// +// public static boolean isADateFormat(int formatIndex, String formatString) { +// // First up, is this an internal date format? +// if (isInternalDateFormat(formatIndex)) { +// return true; +// } +// if (StringUtils.isEmpty(formatString)) { +// return false; +// } +// +// // check the cache first +// if (isCached(formatString, formatIndex)) { +// return lastCachedResult.get(); +// } +// +// String fs = formatString; +// /*if (false) { +// // Normalize the format string. The code below is equivalent +// // to the following consecutive regexp replacements: +// +// // Translate \- into just -, before matching +// fs = fs.replaceAll("\\\\-","-"); +// // And \, into , +// fs = fs.replaceAll("\\\\,",","); +// // And \. into . +// fs = fs.replaceAll("\\\\\\.","."); +// // And '\ ' into ' ' +// fs = fs.replaceAll("\\\\ "," "); +// +// // If it end in ;@, that's some crazy dd/mm vs mm/dd +// // switching stuff, which we can ignore +// fs = fs.replaceAll(";@", ""); +// +// // The code above was reworked as suggested in bug 48425: +// // simple loop is more efficient than consecutive regexp replacements. +// }*/ +// final int length = fs.length(); +// StringBuilder sb = new StringBuilder(length); +// for (int i = 0; i < length; i++) { +// char c = fs.charAt(i); +// if (i < length - 1) { +// char nc = fs.charAt(i + 1); +// if (c == '\\') { +// switch (nc) { +// case '-': +// case ',': +// case '.': +// case ' ': +// case '\\': +// // skip current '\' and continue to the next char +// continue; +// } +// } else if (c == ';' && nc == '@') { +// i++; +// // skip ";@" duplets +// continue; +// } +// } +// sb.append(c); +// } +// fs = sb.toString(); +// +// // short-circuit if it indicates elapsed time: [h], [m] or [s] +// if (date_ptrn4.matcher(fs).matches()) { +// cache(formatString, formatIndex, true); +// return true; +// } +// // If it starts with [DBNum1] or [DBNum2] or [DBNum3] +// // then it could be a Chinese date +// fs = date_ptrn5.matcher(fs).replaceAll(""); +// // If it starts with [$-...], then could be a date, but +// // who knows what that starting bit is all about +// fs = date_ptrn1.matcher(fs).replaceAll(""); +// // If it starts with something like [Black] or [Yellow], +// // then it could be a date +// fs = date_ptrn2.matcher(fs).replaceAll(""); +// // You're allowed something like dd/mm/yy;[red]dd/mm/yy +// // which would place dates before 1900/1904 in red +// // For now, only consider the first one +// final int separatorIndex = fs.indexOf(';'); +// if (0 < separatorIndex && separatorIndex < fs.length() - 1) { +// fs = fs.substring(0, separatorIndex); +// } +// +// // Ensure it has some date letters in it +// // (Avoids false positives on the rest of pattern 3) +// if (!date_ptrn3a.matcher(fs).find()) { +// return false; +// } +// +// // If we get here, check it's only made up, in any case, of: +// // y m d h s - \ / , . : [ ] T +// // optionally followed by AM/PM +// +// boolean result = date_ptrn3b.matcher(fs).matches(); +// cache(formatString, formatIndex, result); +// return result; +// } +// +// /** +// * Given a format ID this will check whether the format represents an internal excel date format or not. +// * +// * @see #isADateFormat(int, java.lang.String) +// */ +// public static boolean isInternalDateFormat(int format) { +// switch (format) { +// // Internal Date Formats as described on page 427 in +// // Microsoft Excel Dev's Kit... +// // 14-22 +// case 0x0e: +// case 0x0f: +// case 0x10: +// case 0x11: +// case 0x12: +// case 0x13: +// case 0x14: +// case 0x15: +// case 0x16: +// // 27-36 +// case 0x1b: +// case 0x1c: +// case 0x1d: +// case 0x1e: +// case 0x1f: +// case 0x20: +// case 0x21: +// case 0x22: +// case 0x23: +// case 0x24: +// // 45-47 +// case 0x2d: +// case 0x2e: +// case 0x2f: +// // 50-58 +// case 0x32: +// case 0x33: +// case 0x34: +// case 0x35: +// case 0x36: +// case 0x37: +// case 0x38: +// case 0x39: +// case 0x3a: +// return true; +// } +// return false; +// } } diff --git a/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java b/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java new file mode 100644 index 0000000..6a4b9c5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java @@ -0,0 +1,154 @@ +//package com.alibaba.excel.util; +// +//import java.text.Format; +// +//import org.apache.poi.ss.format.CellFormat; +//import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; +//import org.apache.poi.ss.usermodel.Cell; +//import org.apache.poi.ss.usermodel.DataFormatter; +//import org.apache.poi.ss.usermodel.DateUtil; +//import org.apache.poi.ss.usermodel.ExcelNumberFormat; +//import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; +//import org.apache.poi.util.POILogger; +// +///** +// * Convert number data, including date. +// * +// * @author Jiaju Zhuang +// **/ +//public class NumberDataFormatterUtils { +// +// /** +// * +// * @param data +// * Not null. +// * @param dataFormatString +// * Not null. +// * @return +// */ +// public String format(Double data, Integer dataFormat, String dataFormatString) { +// +// if (DateUtil.isCellDateFormatted(cell, cfEvaluator)) { +// return getFormattedDateString(cell, cfEvaluator); +// } +// return getFormattedNumberString(cell, cfEvaluator); +// +// } +// +// private String getFormattedDateString(Double data,String dataFormatString) { +// +// +// if (cell == null) { +// return null; +// } +// Format dateFormat = getFormat(cell, cfEvaluator); +// synchronized (dateFormat) { +// if (dateFormat instanceof ExcelStyleDateFormatter) { +// // Hint about the raw excel value +// ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(cell.getNumericCellValue()); +// } +// Date d = cell.getDateCellValue(); +// return performDateFormatting(d, dateFormat); +// } +// } +// +// +// /** +// * Return a Format for the given cell if one exists, otherwise try to +// * create one. This method will return null if the any of the +// * following is true: +// *

    +// *
  • the cell's style is null
  • +// *
  • the style's data format string is null or empty
  • +// *
  • the format string cannot be recognized as either a number or date
  • +// *
+// * +// * @param cell The cell to retrieve a Format for +// * @return A Format for the format String +// */ +// private Format getFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator) { +// if (cell == null) return null; +// +// ExcelNumberFormat numFmt = ExcelNumberFormat.from(cell, cfEvaluator); +// +// if ( numFmt == null) { +// return null; +// } +// +// int formatIndex = numFmt.getIdx(); +// String formatStr = numFmt.getFormat(); +// if(formatStr == null || formatStr.trim().length() == 0) { +// return null; +// } +// return getFormat(cell.getNumericCellValue(), formatIndex, formatStr, isDate1904(cell)); +// } +// +// private boolean isDate1904(Cell cell) { +// if ( cell != null && cell.getSheet().getWorkbook() instanceof Date1904Support) { +// return ((Date1904Support)cell.getSheet().getWorkbook()).isDate1904(); +// +// } +// return false; +// } +// +// private Format getFormat(double cellValue, int formatIndex, String formatStrIn, boolean use1904Windowing) { +// localeChangedObservable.checkForLocaleChange(); +// +// // Might be better to separate out the n p and z formats, falling back to p when n and z are not set. +// // That however would require other code to be re factored. +// // String[] formatBits = formatStrIn.split(";"); +// // int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2; +// // String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0]; +// +// String formatStr = formatStrIn; +// +// // Excel supports 2+ part conditional data formats, eg positive/negative/zero, +// // or (>1000),(>0),(0),(negative). As Java doesn't handle these kinds +// // of different formats for different ranges, just +ve/-ve, we need to +// // handle these ourselves in a special way. +// // For now, if we detect 2+ parts, we call out to CellFormat to handle it +// // TODO Going forward, we should really merge the logic between the two classes +// if (formatStr.contains(";") && +// (formatStr.indexOf(';') != formatStr.lastIndexOf(';') +// || rangeConditionalPattern.matcher(formatStr).matches() +// ) ) { +// try { +// // Ask CellFormat to get a formatter for it +// CellFormat cfmt = CellFormat.getInstance(locale, formatStr); +// // CellFormat requires callers to identify date vs not, so do so +// Object cellValueO = Double.valueOf(cellValue); +// if (DateUtil.isADateFormat(formatIndex, formatStr) && +// // don't try to handle Date value 0, let a 3 or 4-part format take care of it +// ((Double)cellValueO).doubleValue() != 0.0) { +// cellValueO = DateUtil.getJavaDate(cellValue, use1904Windowing); +// } +// // Wrap and return (non-cachable - CellFormat does that) +// return new DataFormatter.CellFormatResultWrapper( cfmt.apply(cellValueO) ); +// } catch (Exception e) { +// logger.log(POILogger.WARN, "Formatting failed for format " + formatStr + ", falling back", e); +// } +// } +// +// // Excel's # with value 0 will output empty where Java will output 0. This hack removes the # from the format. +// if (emulateCSV && cellValue == 0.0 && formatStr.contains("#") && !formatStr.contains("0")) { +// formatStr = formatStr.replaceAll("#", ""); +// } +// +// // See if we already have it cached +// Format format = formats.get(formatStr); +// if (format != null) { +// return format; +// } +// +// // Is it one of the special built in types, General or @? +// if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) { +// return generalNumberFormat; +// } +// +// // Build a formatter, and cache it +// format = createFormat(cellValue, formatIndex, formatStr); +// formats.put(formatStr, format); +// return format; +// } +// +//} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java index 0dc22aa..c3f4ada 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java @@ -33,7 +33,7 @@ public class ReadTest { *

* 1. 创建excel对应的实体对象 参照{@link DemoData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} *

* 3. 直接读即可 */ @@ -60,7 +60,7 @@ public class ReadTest { *

* 1. 创建excel对应的实体对象,并使用{@link ExcelProperty}注解. 参照{@link IndexOrNameData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link IndexOrNameDataListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link IndexOrNameDataListener} *

* 3. 直接读即可 */ @@ -76,7 +76,7 @@ public class ReadTest { *

* 1. 创建excel对应的实体对象 参照{@link DemoData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} *

* 3. 直接读即可 */ @@ -108,7 +108,7 @@ public class ReadTest { *

* 1. 创建excel对应的实体对象 参照{@link ConverterData}.里面可以使用注解{@link DateTimeFormat}、{@link NumberFormat}或者自定义注解 *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link ConverterDataListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link ConverterDataListener} *

* 3. 直接读即可 */ @@ -130,7 +130,7 @@ public class ReadTest { *

* 1. 创建excel对应的实体对象 参照{@link DemoData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener} *

* 3. 设置headRowNumber参数,然后读。 这里要注意headRowNumber如果不指定, 会根据你传入的class的{@link ExcelProperty#value()}里面的表头的数量来决定行数, * 如果不传入class则默认为1.当然你指定了headRowNumber不管是否传入class都是以你传入的为准。 @@ -150,7 +150,7 @@ public class ReadTest { *

* 1. 创建excel对应的实体对象 参照{@link DemoData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} *

* 3. 直接读即可 */ @@ -167,7 +167,7 @@ public class ReadTest { *

* 1. 创建excel对应的实体对象 参照{@link DemoData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} *

* 3. 直接读即可 */ @@ -184,7 +184,7 @@ public class ReadTest { *

* 1. 创建excel对应的实体对象 参照{@link ExceptionDemoData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExceptionListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExceptionListener} *

* 3. 直接读即可 */ diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java index 98f400a..b80022d 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/web/WebTest.java @@ -85,7 +85,7 @@ public class WebTest { *

* 1. 创建excel对应的实体对象 参照{@link UploadData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} + * 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener} *

* 3. 直接读即可 */ diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java index 052b60b..1682aa1 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java @@ -29,7 +29,7 @@ public class Lock2Test { @Test public void test() throws Exception { - File file = new File("D:\\test\\000001.xlsx"); + File file = new File("D:\\test\\headt1.xlsx"); List list = EasyExcel.read(file).sheet().headRowNumber(0).doReadSync(); LOGGER.info("数据:{}", list.size()); diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatData.java b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatData.java new file mode 100644 index 0000000..d057d8e --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatData.java @@ -0,0 +1,16 @@ +package com.alibaba.easyexcel.test.temp.dataformat; + +import com.alibaba.excel.metadata.CellData; + +import lombok.Data; + +/** + * TODO + * + * @author 罗成 + **/ +@Data +public class DataFormatData { + private CellData date; + private CellData num; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java new file mode 100644 index 0000000..d9c7bb2 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java @@ -0,0 +1,127 @@ +package com.alibaba.easyexcel.test.temp.dataformat; + +import java.io.File; +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.temp.Lock2Test; +import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; + +/** + * 格式测试 + * + * @author Jiaju Zhuang + **/ +@Ignore +public class DataFormatTest { + private static final Logger LOGGER = LoggerFactory.getLogger(Lock2Test.class); + + @Test + public void test() throws Exception { + File file = new File("D:\\test\\dataformat.xlsx"); + + List list = + EasyExcel.read(file, DataFormatData.class, null).sheet().headRowNumber(0).doReadSync(); + LOGGER.info("数据:{}", list.size()); + for (DataFormatData data : list) { + Integer dataFormat = data.getDate().getDataFormat(); + + String dataFormatString = data.getDate().getDataFormatString(); + + if (dataFormat == null || dataFormatString == null) { + + } else { + LOGGER.info("格式化:{};{}:{}", dataFormat, dataFormatString, + DateUtil.isADateFormat(dataFormat, dataFormatString)); + } + + LOGGER.info("返回数据:{}", JSON.toJSONString(data)); + } + } + + @Test + public void testxls() throws Exception { + File file = new File("D:\\test\\dataformat.xls"); + + List list = + EasyExcel.read(file, DataFormatData.class, null).sheet().headRowNumber(0).doReadSync(); + LOGGER.info("数据:{}", list.size()); + for (DataFormatData data : list) { + Integer dataFormat = data.getDate().getDataFormat(); + + String dataFormatString = data.getDate().getDataFormatString(); + + if (dataFormat == null || dataFormatString == null) { + + } else { + LOGGER.info("格式化:{};{}:{}", dataFormat, dataFormatString, + DateUtil.isADateFormat(dataFormat, dataFormatString)); + } + + LOGGER.info("返回数据:{}", JSON.toJSONString(data)); + } + } + + @Test + public void test3() throws IOException { + String file = "D:\\test\\dataformat1.xlsx"; + XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file); + Sheet xssfSheet = xssfWorkbook.getSheetAt(0); + Cell cell = xssfSheet.getRow(0).getCell(0); + DataFormatter d = new DataFormatter(); + System.out.println(d.formatCellValue(cell)); + } + + @Test + public void test31() throws IOException { + System.out.println(DateUtil.isADateFormat(181, "[DBNum1][$-404]m\"\u6708\"d\"\u65e5\";@")); + } + + @Test + public void test43() throws IOException { + SimpleDateFormat s = new SimpleDateFormat("yyyy'年'm'月'd'日' h'点'mm'哈哈哈m'"); + System.out.println(s.format(new Date())); + } + + @Test + public void test463() throws IOException { + SimpleDateFormat s = new SimpleDateFormat("[$-804]yyyy年m月"); + System.out.println(s.format(new Date())); + } + + @Test + public void test1() throws Exception { + System.out.println(DateUtil.isADateFormat(181, "yyyy\"年啊\"m\"月\"d\"日\"\\ h")); + System.out.println(DateUtil.isADateFormat(180, "yyyy\"年\"m\"月\"d\"日\"\\ h\"点\"")); + } + + @Test + public void test2() throws Exception { + List list1 = new ArrayList(3000); + long start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + list1.clear(); + } + System.out.println("end:" + (System.currentTimeMillis() - start)); + start = System.currentTimeMillis(); + for (int i = 0; i < 10000; i++) { + list1 = new ArrayList(3000); + } + System.out.println("end:" + (System.currentTimeMillis() - start)); + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatter1.java b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatter1.java new file mode 100644 index 0000000..0239ed5 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatter1.java @@ -0,0 +1,1292 @@ +/* + * ==================================================================== Licensed to the Apache Software Foundation (ASF) + * under one or more contributor license agreements. See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. The ASF licenses this file to You 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. + * + * 2012 - Alfresco Software, Ltd. Alfresco Software has modified source of this file The details of changes as svn diff + * can be found in svn at location root/projects/3rd-party/src + * ==================================================================== + */ +package com.alibaba.easyexcel.test.temp.dataformat; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DateFormat; +import java.text.DateFormatSymbols; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.FieldPosition; +import java.text.Format; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Observable; +import java.util.Observer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.poi.ss.format.CellFormat; +import org.apache.poi.ss.format.CellFormatResult; +import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; +import org.apache.poi.ss.usermodel.Cell; +import org.apache.poi.ss.usermodel.CellType; +import org.apache.poi.ss.usermodel.DataFormatter; +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.ExcelGeneralNumberFormat; +import org.apache.poi.ss.usermodel.ExcelNumberFormat; +import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; +import org.apache.poi.ss.usermodel.FormulaError; +import org.apache.poi.ss.usermodel.FormulaEvaluator; +import org.apache.poi.ss.usermodel.FractionFormat; +import org.apache.poi.ss.util.DateFormatConverter; +import org.apache.poi.ss.util.NumberToTextConverter; +import org.apache.poi.util.LocaleUtil; +import org.apache.poi.util.POILogFactory; +import org.apache.poi.util.POILogger; + +/** + * DataFormatter contains methods for formatting the value stored in an Cell. This can be useful for reports and GUI + * presentations when you need to display data exactly as it appears in Excel. Supported formats include currency, SSN, + * percentages, decimals, dates, phone numbers, zip codes, etc. + *

+ * Internally, formats will be implemented using subclasses of {@link Format} such as {@link DecimalFormat} and + * {@link java.text.SimpleDateFormat}. Therefore the formats used by this class must obey the same pattern rules as + * these Format subclasses. This means that only legal number pattern characters ("0", "#", ".", "," etc.) may appear in + * number formats. Other characters can be inserted before or after the number pattern to form a + * prefix or suffix. + *

+ *

+ * For example the Excel pattern "$#,##0.00 "USD"_);($#,##0.00 "USD")" + * will be correctly formatted as "$1,000.00 USD" or "($1,000.00 USD)". However the pattern + * "00-00-00" is incorrectly formatted by DecimalFormat as "000000--". For Excel formats that are not + * compatible with DecimalFormat, you can provide your own custom {@link Format} implementation via + * DataFormatter.addFormat(String,Format). The following custom formats are already provided by this class: + *

+ * + *
+ * 
  • SSN "000-00-0000"
  • + *
  • Phone Number "(###) ###-####"
  • + *
  • Zip plus 4 "00000-0000"
  • + *
+ *
+ *

+ * If the Excel format pattern cannot be parsed successfully, then a default format will be used. The default number + * format will mimic the Excel General format: "#" for whole numbers and "#.##########" for decimal numbers. You can + * override the default format pattern with + * DataFormatter.setDefaultNumberFormat(Format). Note: the default format will only be used when a Format + * cannot be created from the cell's data format string. + * + *

+ * Note that by default formatted numeric values are trimmed. Excel formats can contain spacers and padding and the + * default behavior is to strip them off. + *

+ *

+ * Example: + *

+ *

+ * Consider a numeric cell with a value 12.343 and format "##.##_ ". The trailing underscore + * and space ("_ ") in the format adds a space to the end and Excel formats this cell as "12.34 ", but + * DataFormatter trims the formatted value and returns "12.34". + *

+ * You can enable spaces by passing the emulateCSV=true flag in the DateFormatter cosntructor. + * If set to true, then the output tries to conform to what you get when you take an xls or xlsx in Excel and Save As + * CSV file: + *
    + *
  • returned values are not trimmed
  • + *
  • Invalid dates are formatted as 255 pound signs ("#")
  • + *
  • simulate Excel's handling of a format string of all # when the value is 0. Excel will output "", + * DataFormatter will output "0". + *
+ *

+ * Some formats are automatically "localized" by Excel, eg show as mm/dd/yyyy when loaded in Excel in some Locales but + * as dd/mm/yyyy in others. These are always returned in the "default" (US) format, as stored in the file. Some format + * strings request an alternate locale, eg [$-809]d/m/yy h:mm AM/PM which explicitly requests UK locale. + * These locale directives are (currently) ignored. You can use {@link DateFormatConverter} to do some of this + * localisation if you need it. + */ +public class DataFormatter1 implements Observer { + private static final String defaultFractionWholePartFormat = "#"; + private static final String defaultFractionFractionPartFormat = "#/##"; + /** Pattern to find a number format: "0" or "#" */ + private static final Pattern numPattern = Pattern.compile("[0#]+"); + + /** Pattern to find days of week as text "ddd...." */ + private static final Pattern daysAsText = Pattern.compile("([d]{3,})", Pattern.CASE_INSENSITIVE); + + /** Pattern to find "AM/PM" marker */ + private static final Pattern amPmPattern = Pattern.compile("((A|P)[M/P]*)", Pattern.CASE_INSENSITIVE); + + /** Pattern to find formats with condition ranges e.g. [>=100] */ + private static final Pattern rangeConditionalPattern = + Pattern.compile(".*\\[\\s*(>|>=|<|<=|=)\\s*[0-9]*\\.*[0-9].*"); + + /** + * A regex to find locale patterns like [$$-1009] and [$?-452]. Note that we don't currently process these into + * locales + */ + private static final Pattern localePatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+\\])"); + + /** + * A regex to match the colour formattings rules. Allowed colours are: Black, Blue, Cyan, Green, Magenta, Red, + * White, Yellow, "Color n" (1<=n<=56) + */ + private static final Pattern colorPattern = Pattern.compile("(\\[BLACK\\])|(\\[BLUE\\])|(\\[CYAN\\])|(\\[GREEN\\])|" + + "(\\[MAGENTA\\])|(\\[RED\\])|(\\[WHITE\\])|(\\[YELLOW\\])|" + + "(\\[COLOR\\s*\\d\\])|(\\[COLOR\\s*[0-5]\\d\\])", Pattern.CASE_INSENSITIVE); + + /** + * A regex to identify a fraction pattern. This requires that replaceAll("\\?", "#") has already been called + */ + private static final Pattern fractionPattern = Pattern.compile("(?:([#\\d]+)\\s+)?(#+)\\s*\\/\\s*([#\\d]+)"); + + /** + * A regex to strip junk out of fraction formats + */ + private static final Pattern fractionStripper = Pattern.compile("(\"[^\"]*\")|([^ \\?#\\d\\/]+)"); + + /** + * A regex to detect if an alternate grouping character is used in a numeric format + */ + private static final Pattern alternateGrouping = Pattern.compile("([#0]([^.#0])[#0]{3})"); + + /** + * Cells formatted with a date or time format and which contain invalid date or time values show 255 pound signs + * ("#"). + */ + private static final String invalidDateTimeString; + static { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < 255; i++) + buf.append('#'); + invalidDateTimeString = buf.toString(); + } + + /** + * The decimal symbols of the locale used for formatting values. + */ + private DecimalFormatSymbols decimalSymbols; + + /** + * The date symbols of the locale used for formatting values. + */ + private DateFormatSymbols dateSymbols; + + /** + * A default date format, if no date format was given + */ + private DateFormat defaultDateformat; + + /** General format for numbers. */ + private Format generalNumberFormat; + + /** A default format to use when a number pattern cannot be parsed. */ + private Format defaultNumFormat; + + /** + * A map to cache formats. Map formats + */ + private final Map formats = new HashMap(); + + private final boolean emulateCSV; + + /** stores the locale valid it the last formatting call */ + private Locale locale; + + /** stores if the locale should change according to {@link LocaleUtil#getUserLocale()} */ + private boolean localeIsAdapting; + + private class LocaleChangeObservable extends Observable { + void checkForLocaleChange() { + checkForLocaleChange(LocaleUtil.getUserLocale()); + } + + void checkForLocaleChange(Locale newLocale) { + if (!localeIsAdapting) + return; + if (newLocale.equals(locale)) + return; + super.setChanged(); + notifyObservers(newLocale); + } + } + + /** the Observable to notify, when the locale has been changed */ + private final LocaleChangeObservable localeChangedObservable = new LocaleChangeObservable(); + + /** For logging any problems we find */ + private static POILogger logger = POILogFactory.getLogger(DataFormatter.class); + + /** + * Creates a formatter using the {@link Locale#getDefault() default locale}. + */ + public DataFormatter1() { + this(false); + } + + /** + * Creates a formatter using the {@link Locale#getDefault() default locale}. + * + * @param emulateCSV + * whether to emulate CSV output. + */ + public DataFormatter1(boolean emulateCSV) { + this(LocaleUtil.getUserLocale(), true, emulateCSV); + } + + /** + * Creates a formatter using the given locale. + */ + public DataFormatter1(Locale locale) { + this(locale, false); + } + + /** + * Creates a formatter using the given locale. + * + * @param emulateCSV + * whether to emulate CSV output. + */ + public DataFormatter1(Locale locale, boolean emulateCSV) { + this(locale, false, emulateCSV); + } + + /** + * Creates a formatter using the given locale. + * + * @param localeIsAdapting + * (true only if locale is not user-specified) + * @param emulateCSV + * whether to emulate CSV output. + */ + private DataFormatter1(Locale locale, boolean localeIsAdapting, boolean emulateCSV) { + this.localeIsAdapting = true; + localeChangedObservable.addObserver(this); + // localeIsAdapting must be true prior to this first checkForLocaleChange call. + localeChangedObservable.checkForLocaleChange(locale); + // set localeIsAdapting so subsequent checks perform correctly + // (whether a specific locale was provided to this DataFormatter or DataFormatter should + // adapt to the current user locale as the locale changes) + this.localeIsAdapting = localeIsAdapting; + this.emulateCSV = emulateCSV; + } + + /** + * Return a Format for the given cell if one exists, otherwise try to create one. This method will return + * null if the any of the following is true: + *

    + *
  • the cell's style is null
  • + *
  • the style's data format string is null or empty
  • + *
  • the format string cannot be recognized as either a number or date
  • + *
+ * + * @param cell + * The cell to retrieve a Format for + * @return A Format for the format String + */ + private Format getFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator) { + if (cell == null) + return null; + + ExcelNumberFormat numFmt = ExcelNumberFormat.from(cell, cfEvaluator); + + if (numFmt == null) { + return null; + } + + int formatIndex = numFmt.getIdx(); + String formatStr = numFmt.getFormat(); + if (formatStr == null || formatStr.trim().length() == 0) { + return null; + } + return getFormat(cell.getNumericCellValue(), formatIndex, formatStr); + } + + private Format getFormat(double cellValue, int formatIndex, String formatStrIn) { + localeChangedObservable.checkForLocaleChange(); + + // Might be better to separate out the n p and z formats, falling back to p when n and z are not set. + // That however would require other code to be re factored. + // String[] formatBits = formatStrIn.split(";"); + // int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2; + // String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0]; + + String formatStr = formatStrIn; + + // Excel supports 2+ part conditional data formats, eg positive/negative/zero, + // or (>1000),(>0),(0),(negative). As Java doesn't handle these kinds + // of different formats for different ranges, just +ve/-ve, we need to + // handle these ourselves in a special way. + // For now, if we detect 2+ parts, we call out to CellFormat to handle it + // TODO Going forward, we should really merge the logic between the two classes + if (formatStr.contains(";") && (formatStr.indexOf(';') != formatStr.lastIndexOf(';') + || rangeConditionalPattern.matcher(formatStr).matches())) { + try { + // Ask CellFormat to get a formatter for it + CellFormat cfmt = CellFormat.getInstance(locale, formatStr); + // CellFormat requires callers to identify date vs not, so do so + Object cellValueO = Double.valueOf(cellValue); + if (DateUtil.isADateFormat(formatIndex, formatStr) && + // don't try to handle Date value 0, let a 3 or 4-part format take care of it + ((Double)cellValueO).doubleValue() != 0.0) { + cellValueO = DateUtil.getJavaDate(cellValue); + } + // Wrap and return (non-cachable - CellFormat does that) + return new CellFormatResultWrapper(cfmt.apply(cellValueO)); + } catch (Exception e) { + logger.log(POILogger.WARN, "Formatting failed for format " + formatStr + ", falling back", e); + } + } + + // Excel's # with value 0 will output empty where Java will output 0. This hack removes the # from the format. + if (emulateCSV && cellValue == 0.0 && formatStr.contains("#") && !formatStr.contains("0")) { + formatStr = formatStr.replaceAll("#", ""); + } + + // See if we already have it cached + Format format = formats.get(formatStr); + if (format != null) { + return format; + } + + // Is it one of the special built in types, General or @? + if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) { + return generalNumberFormat; + } + + // Build a formatter, and cache it + format = createFormat(cellValue, formatIndex, formatStr); + formats.put(formatStr, format); + return format; + } + + /** + * Create and return a Format based on the format string from a cell's style. If the pattern cannot be parsed, + * return a default pattern. + * + * @param cell + * The Excel cell + * @return A Format representing the excel format. May return null. + */ + public Format createFormat(Cell cell) { + + int formatIndex = cell.getCellStyle().getDataFormat(); + String formatStr = cell.getCellStyle().getDataFormatString(); + return createFormat(cell.getNumericCellValue(), formatIndex, formatStr); + } + + private Format createFormat(double cellValue, int formatIndex, String sFormat) { + localeChangedObservable.checkForLocaleChange(); + + String formatStr = sFormat; + + // Remove colour formatting if present + Matcher colourM = colorPattern.matcher(formatStr); + while (colourM.find()) { + String colour = colourM.group(); + + // Paranoid replacement... + int at = formatStr.indexOf(colour); + if (at == -1) + break; + String nFormatStr = formatStr.substring(0, at) + formatStr.substring(at + colour.length()); + if (nFormatStr.equals(formatStr)) + break; + + // Try again in case there's multiple + formatStr = nFormatStr; + colourM = colorPattern.matcher(formatStr); + } + + // Strip off the locale information, we use an instance-wide locale for everything + Matcher m = localePatternGroup.matcher(formatStr); + while (m.find()) { + String match = m.group(); + String symbol = match.substring(match.indexOf('$') + 1, match.indexOf('-')); + if (symbol.indexOf('$') > -1) { + symbol = symbol.substring(0, symbol.indexOf('$')) + '\\' + + symbol.substring(symbol.indexOf('$'), symbol.length()); + } + formatStr = m.replaceAll(symbol); + m = localePatternGroup.matcher(formatStr); + } + + // Check for special cases + if (formatStr == null || formatStr.trim().length() == 0) { + return getDefaultFormat(cellValue); + } + + if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) { + return generalNumberFormat; + } + + if ("".equals("")||(DateUtil.isADateFormat(formatIndex, formatStr) && DateUtil.isValidExcelDate(cellValue))) { + return createDateFormat(formatStr, cellValue); + } + // Excel supports fractions in format strings, which Java doesn't + if (formatStr.contains("#/") || formatStr.contains("?/")) { + String[] chunks = formatStr.split(";"); + for (String chunk1 : chunks) { + String chunk = chunk1.replaceAll("\\?", "#"); + Matcher matcher = fractionStripper.matcher(chunk); + chunk = matcher.replaceAll(" "); + chunk = chunk.replaceAll(" +", " "); + Matcher fractionMatcher = fractionPattern.matcher(chunk); + // take the first match + if (fractionMatcher.find()) { + String wholePart = (fractionMatcher.group(1) == null) ? "" : defaultFractionWholePartFormat; + return new FractionFormat(wholePart, fractionMatcher.group(3)); + } + } + + // Strip custom text in quotes and escaped characters for now as it can cause performance problems in + // fractions. + // String strippedFormatStr = formatStr.replaceAll("\\\\ ", " ").replaceAll("\\\\.", + // "").replaceAll("\"[^\"]*\"", " ").replaceAll("\\?", "#"); + // System.out.println("formatStr: "+strippedFormatStr); + return new FractionFormat(defaultFractionWholePartFormat, defaultFractionFractionPartFormat); + } + + if (numPattern.matcher(formatStr).find()) { + return createNumberFormat(formatStr, cellValue); + } + + if (emulateCSV) { + return new ConstantStringFormat(cleanFormatForNumber(formatStr)); + } + // TODO - when does this occur? + return null; + } + + private Format createDateFormat(String pFormatStr, double cellValue) { + String formatStr = pFormatStr; + formatStr = formatStr.replaceAll("\\\\-", "-"); + formatStr = formatStr.replaceAll("\\\\,", ","); + formatStr = formatStr.replaceAll("\\\\\\.", "."); // . is a special regexp char + formatStr = formatStr.replaceAll("\\\\ ", " "); + formatStr = formatStr.replaceAll("\\\\/", "/"); // weird: m\\/d\\/yyyy + formatStr = formatStr.replaceAll(";@", ""); + formatStr = formatStr.replaceAll("\"/\"", "/"); // "/" is escaped for no reason in: mm"/"dd"/"yyyy + formatStr = formatStr.replace("\"\"", "'"); // replace Excel quoting with Java style quoting + formatStr = formatStr.replaceAll("\\\\T", "'T'"); // Quote the T is iso8601 style dates + + boolean hasAmPm = false; + Matcher amPmMatcher = amPmPattern.matcher(formatStr); + while (amPmMatcher.find()) { + formatStr = amPmMatcher.replaceAll("@"); + hasAmPm = true; + amPmMatcher = amPmPattern.matcher(formatStr); + } + formatStr = formatStr.replaceAll("@", "a"); + + Matcher dateMatcher = daysAsText.matcher(formatStr); + if (dateMatcher.find()) { + String match = dateMatcher.group(0).toUpperCase(Locale.ROOT).replaceAll("D", "E"); + formatStr = dateMatcher.replaceAll(match); + } + + // Convert excel date format to SimpleDateFormat. + // Excel uses lower and upper case 'm' for both minutes and months. + // From Excel help: + /* + The "m" or "mm" code must appear immediately after the "h" or"hh" + code or immediately before the "ss" code; otherwise, Microsoft + Excel displays the month instead of minutes." + */ + + StringBuilder sb = new StringBuilder(); + char[] chars = formatStr.toCharArray(); + boolean mIsMonth = true; + List ms = new ArrayList(); + boolean isElapsed = false; + for (int j = 0; j < chars.length; j++) { + char c = chars[j]; + if (c == '\'') { + sb.append(c); + j++; + + // skip until the next quote + while (j < chars.length) { + c = chars[j]; + sb.append(c); + if (c == '\'') { + break; + } + j++; + } + } else if (c == '[' && !isElapsed) { + isElapsed = true; + mIsMonth = false; + sb.append(c); + } else if (c == ']' && isElapsed) { + isElapsed = false; + sb.append(c); + } else if (isElapsed) { + if (c == 'h' || c == 'H') { + sb.append('H'); + } else if (c == 'm' || c == 'M') { + sb.append('m'); + } else if (c == 's' || c == 'S') { + sb.append('s'); + } else { + sb.append(c); + } + } else if (c == 'h' || c == 'H') { + mIsMonth = false; + if (hasAmPm) { + sb.append('h'); + } else { + sb.append('H'); + } + } else if (c == 'm' || c == 'M') { + if (mIsMonth) { + sb.append('M'); + ms.add(Integer.valueOf(sb.length() - 1)); + } else { + sb.append('m'); + } + } else if (c == 's' || c == 'S') { + sb.append('s'); + // if 'M' precedes 's' it should be minutes ('m') + for (int index : ms) { + if (sb.charAt(index) == 'M') { + sb.replace(index, index + 1, "m"); + } + } + mIsMonth = true; + ms.clear(); + } else if (Character.isLetter(c)) { + mIsMonth = true; + ms.clear(); + if (c == 'y' || c == 'Y') { + sb.append('y'); + } else if (c == 'd' || c == 'D') { + sb.append('d'); + } else { + sb.append(c); + } + } else { + if (Character.isWhitespace(c)) { + ms.clear(); + } + sb.append(c); + } + } + formatStr = sb.toString(); + + try { + return new ExcelStyleDateFormatter(formatStr, dateSymbols); + } catch (IllegalArgumentException iae) { + logger.log(POILogger.DEBUG, "Formatting failed for format " + formatStr + ", falling back", iae); + // the pattern could not be parsed correctly, + // so fall back to the default number format + return getDefaultFormat(cellValue); + } + + } + + private String cleanFormatForNumber(String formatStr) { + StringBuilder sb = new StringBuilder(formatStr); + + if (emulateCSV) { + // Requested spacers with "_" are replaced by a single space. + // Full-column-width padding "*" are removed. + // Not processing fractions at this time. Replace ? with space. + // This matches CSV output. + for (int i = 0; i < sb.length(); i++) { + char c = sb.charAt(i); + if (c == '_' || c == '*' || c == '?') { + if (i > 0 && sb.charAt((i - 1)) == '\\') { + // It's escaped, don't worry + continue; + } + if (c == '?') { + sb.setCharAt(i, ' '); + } else if (i < sb.length() - 1) { + // Remove the character we're supposed + // to match the space of / pad to the + // column width with + if (c == '_') { + sb.setCharAt(i + 1, ' '); + } else { + sb.deleteCharAt(i + 1); + } + // Remove the character too + sb.deleteCharAt(i); + i--; + } + } + } + } else { + // If they requested spacers, with "_", + // remove those as we don't do spacing + // If they requested full-column-width + // padding, with "*", remove those too + for (int i = 0; i < sb.length(); i++) { + char c = sb.charAt(i); + if (c == '_' || c == '*') { + if (i > 0 && sb.charAt((i - 1)) == '\\') { + // It's escaped, don't worry + continue; + } + if (i < sb.length() - 1) { + // Remove the character we're supposed + // to match the space of / pad to the + // column width with + sb.deleteCharAt(i + 1); + } + // Remove the _ too + sb.deleteCharAt(i); + i--; + } + } + } + + // Now, handle the other aspects like + // quoting and scientific notation + for (int i = 0; i < sb.length(); i++) { + char c = sb.charAt(i); + // remove quotes and back slashes + if (c == '\\' || c == '"') { + sb.deleteCharAt(i); + i--; + + // for scientific/engineering notation + } else if (c == '+' && i > 0 && sb.charAt(i - 1) == 'E') { + sb.deleteCharAt(i); + i--; + } + } + + return sb.toString(); + } + + private static class InternalDecimalFormatWithScale extends Format { + + private static final Pattern endsWithCommas = Pattern.compile("(,+)$"); + private BigDecimal divider; + private static final BigDecimal ONE_THOUSAND = new BigDecimal(1000); + private final DecimalFormat df; + + private static final String trimTrailingCommas(String s) { + return s.replaceAll(",+$", ""); + } + + public InternalDecimalFormatWithScale(String pattern, DecimalFormatSymbols symbols) { + df = new DecimalFormat(trimTrailingCommas(pattern), symbols); + setExcelStyleRoundingMode(df); + Matcher endsWithCommasMatcher = endsWithCommas.matcher(pattern); + if (endsWithCommasMatcher.find()) { + String commas = (endsWithCommasMatcher.group(1)); + BigDecimal temp = BigDecimal.ONE; + for (int i = 0; i < commas.length(); ++i) { + temp = temp.multiply(ONE_THOUSAND); + } + divider = temp; + } else { + divider = null; + } + } + + private Object scaleInput(Object obj) { + if (divider != null) { + if (obj instanceof BigDecimal) { + obj = ((BigDecimal)obj).divide(divider, RoundingMode.HALF_UP); + } else if (obj instanceof Double) { + obj = (Double)obj / divider.doubleValue(); + } else { + throw new UnsupportedOperationException(); + } + } + return obj; + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + obj = scaleInput(obj); + return df.format(obj, toAppendTo, pos); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + throw new UnsupportedOperationException(); + } + } + + private Format createNumberFormat(String formatStr, double cellValue) { + String format = cleanFormatForNumber(formatStr); + DecimalFormatSymbols symbols = decimalSymbols; + + // Do we need to change the grouping character? + // eg for a format like #'##0 which wants 12'345 not 12,345 + Matcher agm = alternateGrouping.matcher(format); + if (agm.find()) { + char grouping = agm.group(2).charAt(0); + // Only replace the grouping character if it is not the default + // grouping character for the US locale (',') in order to enable + // correct grouping for non-US locales. + if (grouping != ',') { + symbols = DecimalFormatSymbols.getInstance(locale); + + symbols.setGroupingSeparator(grouping); + String oldPart = agm.group(1); + String newPart = oldPart.replace(grouping, ','); + format = format.replace(oldPart, newPart); + } + } + + try { + return new InternalDecimalFormatWithScale(format, symbols); + } catch (IllegalArgumentException iae) { + logger.log(POILogger.DEBUG, "Formatting failed for format " + formatStr + ", falling back", iae); + // the pattern could not be parsed correctly, + // so fall back to the default number format + return getDefaultFormat(cellValue); + } + } + + /** + * Returns a default format for a cell. + * + * @param cell + * The cell + * @return a default format + */ + public Format getDefaultFormat(Cell cell) { + return getDefaultFormat(cell.getNumericCellValue()); + } + + private Format getDefaultFormat(double cellValue) { + localeChangedObservable.checkForLocaleChange(); + + // for numeric cells try user supplied default + if (defaultNumFormat != null) { + return defaultNumFormat; + + // otherwise use general format + } + return generalNumberFormat; + } + + /** + * Performs Excel-style date formatting, using the supplied Date and format + */ + private String performDateFormatting(Date d, Format dateFormat) { + return (dateFormat != null ? dateFormat : defaultDateformat).format(d); + } + + /** + * Returns the formatted value of an Excel date as a String based on the cell's DataFormat. + * i.e. "Thursday, January 02, 2003" , "01/02/2003" , "02-Jan" , etc. + *

+ * If any conditional format rules apply, the highest priority with a number format is used. If no rules contain a + * number format, or no rules apply, the cell's style format is used. If the style does not have a format, the + * default date format is applied. + * + * @param cell + * to format + * @param cfEvaluator + * ConditionalFormattingEvaluator (if available) + * @return Formatted value + */ + private String getFormattedDateString(Cell cell, ConditionalFormattingEvaluator cfEvaluator) { + Format dateFormat = getFormat(cell, cfEvaluator); + if (dateFormat instanceof ExcelStyleDateFormatter) { + // Hint about the raw excel value + ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(cell.getNumericCellValue()); + } + Date d = cell.getDateCellValue(); + return performDateFormatting(d, dateFormat); + } + + /** + * Returns the formatted value of an Excel number as a String based on the cell's DataFormat. + * Supported formats include currency, percents, decimals, phone number, SSN, etc.: "61.54%", "$100.00", "(800) + * 555-1234". + *

+ * Format comes from either the highest priority conditional format rule with a specified format, or from the cell + * style. + * + * @param cell + * The cell + * @param cfEvaluator + * if available, or null + * @return a formatted number string + */ + private String getFormattedNumberString(Cell cell, ConditionalFormattingEvaluator cfEvaluator) { + + Format numberFormat = getFormat(cell, cfEvaluator); + double d = cell.getNumericCellValue(); + if (numberFormat == null) { + return String.valueOf(d); + } + String formatted = numberFormat.format(new Double(d)); + return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation + } + + /** + * Formats the given raw cell value, based on the supplied format index and string, according to excel style rules. + * + * @see #formatCellValue(Cell) + */ + public String formatRawCellContents(double value, int formatIndex, String formatString) { + return formatRawCellContents(value, formatIndex, formatString, false); + } + + /** + * Formats the given raw cell value, based on the supplied format index and string, according to excel style rules. + * + * @see #formatCellValue(Cell) + */ + public String formatRawCellContents(double value, int formatIndex, String formatString, boolean use1904Windowing) { + localeChangedObservable.checkForLocaleChange(); + + // Is it a date? + if (DateUtil.isADateFormat(formatIndex, formatString)) { + if (DateUtil.isValidExcelDate(value)) { + Format dateFormat = getFormat(value, formatIndex, formatString); + if (dateFormat instanceof ExcelStyleDateFormatter) { + // Hint about the raw excel value + ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(value); + } + Date d = DateUtil.getJavaDate(value, use1904Windowing); + return performDateFormatting(d, dateFormat); + } + // RK: Invalid dates are 255 #s. + if (emulateCSV) { + return invalidDateTimeString; + } + } + + // else Number + Format numberFormat = getFormat(value, formatIndex, formatString); + if (numberFormat == null) { + return String.valueOf(value); + } + + // When formatting 'value', double to text to BigDecimal produces more + // accurate results than double to Double in JDK8 (as compared to + // previous versions). However, if the value contains E notation, this + // would expand the values, which we do not want, so revert to + // original method. + String result; + final String textValue = NumberToTextConverter.toText(value); + if (textValue.indexOf('E') > -1) { + result = numberFormat.format(new Double(value)); + } else { + result = numberFormat.format(new BigDecimal(textValue)); + } + // Complete scientific notation by adding the missing +. + if (result.indexOf('E') > -1 && !result.contains("E-")) { + result = result.replaceFirst("E", "E+"); + } + return result; + } + + /** + *

+ * Returns the formatted value of a cell as a String regardless of the cell type. If the Excel format + * pattern cannot be parsed then the cell value will be formatted using a default format. + *

+ *

+ * When passed a null or blank cell, this method will return an empty String (""). Formulas in formula type cells + * will not be evaluated. + *

+ * + * @param cell + * The cell + * @return the formatted cell value as a String + */ + public String formatCellValue(Cell cell) { + return formatCellValue(cell, null); + } + + /** + *

+ * Returns the formatted value of a cell as a String regardless of the cell type. If the Excel number + * format pattern cannot be parsed then the cell value will be formatted using a default format. + *

+ *

+ * When passed a null or blank cell, this method will return an empty String (""). Formula cells will be evaluated + * using the given {@link FormulaEvaluator} if the evaluator is non-null. If the evaluator is null, then the formula + * String will be returned. The caller is responsible for setting the currentRow on the evaluator + *

+ * + * @param cell + * The cell (can be null) + * @param evaluator + * The FormulaEvaluator (can be null) + * @return a string value of the cell + */ + public String formatCellValue(Cell cell, FormulaEvaluator evaluator) { + return formatCellValue(cell, evaluator, null); + } + + /** + *

+ * Returns the formatted value of a cell as a String regardless of the cell type. If the Excel number + * format pattern cannot be parsed then the cell value will be formatted using a default format. + *

+ *

+ * When passed a null or blank cell, this method will return an empty String (""). Formula cells will be evaluated + * using the given {@link FormulaEvaluator} if the evaluator is non-null. If the evaluator is null, then the formula + * String will be returned. The caller is responsible for setting the currentRow on the evaluator + *

+ *

+ * When a ConditionalFormattingEvaluator is present, it is checked first to see if there is a number format to + * apply. If multiple rules apply, the last one is used. If no ConditionalFormattingEvaluator is present, no rules + * apply, or the applied rules do not define a format, the cell's style format is used. + *

+ *

+ * The two evaluators should be from the same context, to avoid inconsistencies in cached values. + *

+ * + * @param cell + * The cell (can be null) + * @param evaluator + * The FormulaEvaluator (can be null) + * @param cfEvaluator + * ConditionalFormattingEvaluator (can be null) + * @return a string value of the cell + */ + public String formatCellValue(Cell cell, FormulaEvaluator evaluator, ConditionalFormattingEvaluator cfEvaluator) { + localeChangedObservable.checkForLocaleChange(); + + if (cell == null) { + return ""; + } + + CellType cellType = cell.getCellTypeEnum(); + if (cellType == CellType.FORMULA) { + if (evaluator == null) { + return cell.getCellFormula(); + } + cellType = evaluator.evaluateFormulaCellEnum(cell); + } + switch (cellType) { + case NUMERIC: + +// if (DateUtil.isCellDateFormatted(cell, cfEvaluator)) { + return getFormattedDateString(cell, cfEvaluator); +// } +// return getFormattedNumberString(cell, cfEvaluator); + + case STRING: + return cell.getRichStringCellValue().getString(); + + case BOOLEAN: + return cell.getBooleanCellValue() ? "TRUE" : "FALSE"; + case BLANK: + return ""; + case ERROR: + return FormulaError.forInt(cell.getErrorCellValue()).getString(); + default: + throw new RuntimeException("Unexpected celltype (" + cellType + ")"); + } + } + + /** + *

+ * Sets a default number format to be used when the Excel format cannot be parsed successfully. Note: This is + * a fall back for when an error occurs while parsing an Excel number format pattern. This will not affect cells + * with the General format. + *

+ *

+ * The value that will be passed to the Format's format method (specified by java.text.Format#format) + * will be a double value from a numeric cell. Therefore the code in the format method should expect a + * Number value. + *

+ * + * @param format + * A Format instance to be used as a default + * @see java.text.Format#format + */ + public void setDefaultNumberFormat(Format format) { + for (Map.Entry entry : formats.entrySet()) { + if (entry.getValue() == generalNumberFormat) { + entry.setValue(format); + } + } + defaultNumFormat = format; + } + + /** + * Adds a new format to the available formats. + *

+ * The value that will be passed to the Format's format method (specified by java.text.Format#format) + * will be a double value from a numeric cell. Therefore the code in the format method should expect a + * Number value. + *

+ * + * @param excelFormatStr + * The data format string + * @param format + * A Format instance + */ + public void addFormat(String excelFormatStr, Format format) { + formats.put(excelFormatStr, format); + } + + // Some custom formats + + /** + * @return a DecimalFormat with parseIntegerOnly set true + */ + private static DecimalFormat createIntegerOnlyFormat(String fmt) { + DecimalFormatSymbols dsf = DecimalFormatSymbols.getInstance(Locale.ROOT); + DecimalFormat result = new DecimalFormat(fmt, dsf); + result.setParseIntegerOnly(true); + return result; + } + + /** + * Enables excel style rounding mode (round half up) on the Decimal Format given. + */ + public static void setExcelStyleRoundingMode(DecimalFormat format) { + setExcelStyleRoundingMode(format, RoundingMode.HALF_UP); + } + + /** + * Enables custom rounding mode on the given Decimal Format. + * + * @param format + * DecimalFormat + * @param roundingMode + * RoundingMode + */ + public static void setExcelStyleRoundingMode(DecimalFormat format, RoundingMode roundingMode) { + format.setRoundingMode(roundingMode); + } + + /** + * If the Locale has been changed via {@link LocaleUtil#setUserLocale(Locale)} the stored formats need to be + * refreshed. All formats which aren't originated from DataFormatter itself, i.e. all Formats added via + * {@link DataFormatter#addFormat(String, Format)} and {@link DataFormatter#setDefaultNumberFormat(Format)}, need to + * be added again. To notify callers, the returned {@link Observable} should be used. The Object in + * {@link Observer#update(Observable, Object)} is the new Locale. + * + * @return the listener object, where callers can register themselves + */ + public Observable getLocaleChangedObservable() { + return localeChangedObservable; + } + + /** + * Update formats when locale has been changed + * + * @param observable + * usually this is our own Observable instance + * @param localeObj + * only reacts on Locale objects + */ + public void update(Observable observable, Object localeObj) { + if (!(localeObj instanceof Locale)) + return; + Locale newLocale = (Locale)localeObj; + if (!localeIsAdapting || newLocale.equals(locale)) + return; + + locale = newLocale; + + dateSymbols = DateFormatSymbols.getInstance(locale); + decimalSymbols = DecimalFormatSymbols.getInstance(locale); + generalNumberFormat = new ExcelGeneralNumberFormat(locale); + + // taken from Date.toString() + defaultDateformat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", dateSymbols); + defaultDateformat.setTimeZone(LocaleUtil.getUserTimeZone()); + + // init built-in formats + + formats.clear(); + Format zipFormat = ZipPlusFourFormat.instance; + addFormat("00000\\-0000", zipFormat); + addFormat("00000-0000", zipFormat); + + Format phoneFormat = PhoneFormat.instance; + // allow for format string variations + addFormat("[<=9999999]###\\-####;\\(###\\)\\ ###\\-####", phoneFormat); + addFormat("[<=9999999]###-####;(###) ###-####", phoneFormat); + addFormat("###\\-####;\\(###\\)\\ ###\\-####", phoneFormat); + addFormat("###-####;(###) ###-####", phoneFormat); + + Format ssnFormat = SSNFormat.instance; + addFormat("000\\-00\\-0000", ssnFormat); + addFormat("000-00-0000", ssnFormat); + } + + /** + * Format class for Excel's SSN format. This class mimics Excel's built-in SSN formatting. + * + * @author James May + */ + @SuppressWarnings("serial") + private static final class SSNFormat extends Format { + public static final Format instance = new SSNFormat(); + private static final DecimalFormat df = createIntegerOnlyFormat("000000000"); + + private SSNFormat() { + // enforce singleton + } + + /** Format a number as an SSN */ + public static String format(Number num) { + String result = df.format(num); + return result.substring(0, 3) + '-' + result.substring(3, 5) + '-' + result.substring(5, 9); + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(format((Number)obj)); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return df.parseObject(source, pos); + } + } + + /** + * Format class for Excel Zip + 4 format. This class mimics Excel's built-in formatting for Zip + 4. + * + * @author James May + */ + @SuppressWarnings("serial") + private static final class ZipPlusFourFormat extends Format { + public static final Format instance = new ZipPlusFourFormat(); + private static final DecimalFormat df = createIntegerOnlyFormat("000000000"); + + private ZipPlusFourFormat() { + // enforce singleton + } + + /** Format a number as Zip + 4 */ + public static String format(Number num) { + String result = df.format(num); + return result.substring(0, 5) + '-' + result.substring(5, 9); + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(format((Number)obj)); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return df.parseObject(source, pos); + } + } + + /** + * Format class for Excel phone number format. This class mimics Excel's built-in phone number formatting. + * + * @author James May + */ + @SuppressWarnings("serial") + private static final class PhoneFormat extends Format { + public static final Format instance = new PhoneFormat(); + private static final DecimalFormat df = createIntegerOnlyFormat("##########"); + + private PhoneFormat() { + // enforce singleton + } + + /** Format a number as a phone number */ + public static String format(Number num) { + String result = df.format(num); + StringBuilder sb = new StringBuilder(); + String seg1, seg2, seg3; + int len = result.length(); + if (len <= 4) { + return result; + } + + seg3 = result.substring(len - 4, len); + seg2 = result.substring(Math.max(0, len - 7), len - 4); + seg1 = result.substring(Math.max(0, len - 10), Math.max(0, len - 7)); + + if (seg1.trim().length() > 0) { + sb.append('(').append(seg1).append(") "); + } + if (seg2.trim().length() > 0) { + sb.append(seg2).append('-'); + } + sb.append(seg3); + return sb.toString(); + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(format((Number)obj)); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return df.parseObject(source, pos); + } + } + + /** + * Format class that does nothing and always returns a constant string. + * + * This format is used to simulate Excel's handling of a format string of all # when the value is 0. Excel will + * output "", Java will output "0". + * + */ + @SuppressWarnings("serial") + private static final class ConstantStringFormat extends Format { + private static final DecimalFormat df = createIntegerOnlyFormat("##########"); + private final String str; + + public ConstantStringFormat(String s) { + str = s; + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(str); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return df.parseObject(source, pos); + } + } + + /** + * Workaround until we merge {@link DataFormatter} with {@link CellFormat}. Constant, non-cachable wrapper around a + * {@link CellFormatResult} + */ + @SuppressWarnings("serial") + private final class CellFormatResultWrapper extends Format { + private final CellFormatResult result; + + private CellFormatResultWrapper(CellFormatResult result) { + this.result = result; + } + + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + if (emulateCSV) { + return toAppendTo.append(result.text); + } else { + return toAppendTo.append(result.text.trim()); + } + } + + public Object parseObject(String source, ParsePosition pos) { + return null; // Not supported + } + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java index b19ac81..44bc943 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java @@ -64,7 +64,7 @@ public class Wirte { List list = new ArrayList(); for (int i = 0; i < 10; i++) { DemoData data = new DemoData(); - data.setString("字符串" + i); + data.setString("640121807369666560" + i); data.setDate(new Date()); data.setDoubleData(null); list.add(data); From 569f42e0da55c99b3e4c0079cac46df0a748dc02 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Wed, 4 Dec 2019 19:12:25 +0800 Subject: [PATCH 04/38] =?UTF-8?q?=E6=96=B0=E5=A2=9E`useDefaultListener`=20?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E5=BF=BD=E7=95=A5=E9=BB=98=E8=AE=A4=E7=9B=91?= =?UTF-8?q?=E5=90=AC=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/read/builder/ExcelReaderBuilder.java | 14 ++++++++++++++ .../alibaba/excel/read/metadata/ReadWorkbook.java | 15 +++++++++++++++ .../read/metadata/holder/AbstractReadHolder.java | 6 +++++- .../alibaba/easyexcel/test/temp/Lock2Test.java | 9 +-------- .../easyexcel/test/temp/LockDataListener.java | 8 +++++--- 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java index 340548b..a458acf 100644 --- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java +++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java @@ -11,6 +11,7 @@ import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.read.listener.ModelBuildEventListener; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.support.ExcelTypeEnum; @@ -233,6 +234,19 @@ public class ExcelReaderBuilder { return this; } + /** + * Whether to use the default listener, which is used by default. + *

+ * The {@link ModelBuildEventListener} is loaded by default to convert the object. + * + * @param useDefaultListener + * @return + */ + public ExcelReaderBuilder useDefaultListener(Boolean useDefaultListener) { + readWorkbook.setUseDefaultListener(useDefaultListener); + return this; + } + public ExcelReader build() { return new ExcelReader(readWorkbook); } diff --git a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java index 3a873da..6392ca0 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java +++ b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java @@ -7,6 +7,7 @@ import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.read.listener.ModelBuildEventListener; import com.alibaba.excel.support.ExcelTypeEnum; /** @@ -63,6 +64,12 @@ public class ReadWorkbook extends ReadBasicParameter { * Whether the encryption */ private String password; + /** + * Whether to use the default listener, which is used by default. + *

+ * The {@link ModelBuildEventListener} is loaded by default to convert the object. + */ + private Boolean useDefaultListener; /** * The default is all excel objects.Default is true. *

@@ -176,4 +183,12 @@ public class ReadWorkbook extends ReadBasicParameter { public void setPassword(String password) { this.password = password; } + + public Boolean getUseDefaultListener() { + return useDefaultListener; + } + + public void setUseDefaultListener(Boolean useDefaultListener) { + this.useDefaultListener = useDefaultListener; + } } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java index 02b2ef5..7133f99 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java @@ -26,6 +26,7 @@ import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.listener.ReadListenerRegistryCenter; import com.alibaba.excel.read.listener.event.AnalysisFinishEvent; import com.alibaba.excel.read.metadata.ReadBasicParameter; +import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.ConverterUtils; @@ -91,7 +92,10 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH this.readListenerList = new ArrayList(parentAbstractReadHolder.getReadListenerList()); } if (HolderEnum.WORKBOOK.equals(holderType())) { - readListenerList.add(new ModelBuildEventListener()); + Boolean useDefaultListener = ((ReadWorkbook)readBasicParameter).getUseDefaultListener(); + if (useDefaultListener == null || useDefaultListener) { + readListenerList.add(new ModelBuildEventListener()); + } } if (readBasicParameter.getCustomReadListenerList() != null && !readBasicParameter.getCustomReadListenerList().isEmpty()) { diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java index 052b60b..f72e94d 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java @@ -1,7 +1,6 @@ package com.alibaba.easyexcel.test.temp; import java.io.File; -import java.io.FileInputStream; import java.util.List; import org.junit.Ignore; @@ -9,13 +8,7 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.easyexcel.test.demo.read.DemoData; -import com.alibaba.easyexcel.test.demo.read.DemoDataListener; -import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; -import com.alibaba.excel.ExcelReader; -import com.alibaba.excel.read.metadata.ReadSheet; -import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.fastjson.JSON; /** @@ -43,7 +36,7 @@ public class Lock2Test { // 写法1: String fileName = "D:\\test\\珠海 (1).xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭 - EasyExcel.read(fileName, LockData.class, new LockDataListener()).sheet().doRead(); + EasyExcel.read(fileName, LockData.class, new LockDataListener()).useDefaultListener(false).sheet().doRead(); } @Test diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/LockDataListener.java b/src/test/java/com/alibaba/easyexcel/test/temp/LockDataListener.java index bda277c..d589111 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/LockDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/LockDataListener.java @@ -2,6 +2,7 @@ package com.alibaba.easyexcel.test.temp; import java.util.ArrayList; import java.util.List; +import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -9,6 +10,7 @@ import org.slf4j.LoggerFactory; import com.alibaba.easyexcel.test.demo.read.DemoDataListener; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.CellData; import com.alibaba.fastjson.JSON; /** @@ -16,16 +18,16 @@ import com.alibaba.fastjson.JSON; * * @author Jiaju Zhuang */ -public class LockDataListener extends AnalysisEventListener { +public class LockDataListener extends AnalysisEventListener> { private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); /** * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 5; - List list = new ArrayList(); + List> list = new ArrayList>(); @Override - public void invoke(LockData data, AnalysisContext context) { + public void invoke(Map data, AnalysisContext context) { LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); list.add(data); if (list.size() >= BATCH_COUNT) { From 46266abccb54666af614a6f69ffd3511eaaf3e8b Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Wed, 4 Dec 2019 19:19:31 +0800 Subject: [PATCH 05/38] =?UTF-8?q?=E6=96=B0=E5=A2=9E`useDefaultListener`=20?= =?UTF-8?q?=E5=8F=AF=E4=BB=A5=E5=BF=BD=E7=95=A5=E9=BB=98=E8=AE=A4=E7=9B=91?= =?UTF-8?q?=E5=90=AC=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- update.md | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e85d044..415b45a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.1.3 + 2.1.4 jar easyexcel diff --git a/update.md b/update.md index 757de15..830a7d1 100644 --- a/update.md +++ b/update.md @@ -1,3 +1,6 @@ +# 2.1.4 +* 新增参数`useDefaultListener` 可以排除默认对象转换 + # 2.1.3 * 每个java进程单独创建一个缓存目录 [Issue #813](https://github.com/alibaba/easyexcel/issues/813) * 统一修改合并为unsafe,提高大量数据导出的合并的效率 From 9c7e06022b0e32d155e2a0fa8808b94791c15188 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Mon, 23 Dec 2019 19:10:58 +0800 Subject: [PATCH 06/38] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=97=A5=E6=9C=9F?= =?UTF-8?q?=E8=BD=AC=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 + .../v03/handlers/NumberRecordHandler.java | 10 +- .../v07/handlers/DefaultCellHandler.java | 7 +- .../excel/constant/BuiltinFormats.java | 62 +- .../string/StringNumberConverter.java | 12 +- .../excel/metadata/BasicParameter.java | 13 + .../alibaba/excel/metadata/DataFormatter.java | 786 ++++++++++++++++++ .../excel/metadata/GlobalConfiguration.java | 15 + .../com/alibaba/excel/util/DateUtils.java | 408 ++++----- .../excel/util/NumberDataFormatterUtils.java | 201 ++--- .../excel/util/ThreadLocalCachedUtils.java | 14 + .../test/core/dataformat/DateFormatData.java | 14 + .../test/core/dataformat/DateFormatTest.java | 50 ++ .../test/temp/dataformat/DataFormatTest.java | 63 ++ .../easyexcel/test/temp/poi/PoiWriteTest.java | 61 -- src/test/resources/dataformat/dataformat.xlsx | Bin 0 -> 11489 bytes 16 files changed, 1263 insertions(+), 458 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/metadata/DataFormatter.java create mode 100644 src/main/java/com/alibaba/excel/util/ThreadLocalCachedUtils.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatData.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java create mode 100644 src/test/resources/dataformat/dataformat.xlsx diff --git a/pom.xml b/pom.xml index e85d044..7e2235c 100644 --- a/pom.xml +++ b/pom.xml @@ -66,6 +66,11 @@ poi-ooxml 3.17 + + org.apache.poi + poi-ooxml-schemas + 3.17 + cglib cglib diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java index 75c3128..d8f3524 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -7,6 +7,7 @@ import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.metadata.CellData; /** @@ -32,8 +33,13 @@ public class NumberRecordHandler extends AbstractXlsRecordHandler { this.row = numrec.getRow(); this.column = numrec.getColumn(); this.cellData = new CellData(BigDecimal.valueOf(numrec.getValue())); - this.cellData.setDataFormat(formatListener.getFormatIndex(numrec)); - this.cellData.setDataFormatString(formatListener.getFormatString(numrec)); + int dataFormat = formatListener.getFormatIndex(numrec); + this.cellData.setDataFormat(dataFormat); + if (dataFormat <= BuiltinFormats.builtinFormats.length) { + this.cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat)); + } else { + this.cellData.setDataFormatString(formatListener.getFormatString(numrec)); + } } @Override diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java index e0b9c41..7312b2c 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -13,7 +13,6 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; -import org.apache.poi.ss.usermodel.BuiltinFormats; import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.apache.poi.xssf.usermodel.XSSFRichTextString; @@ -21,6 +20,7 @@ import org.xml.sax.Attributes; import com.alibaba.excel.analysis.v07.XlsxCellHandler; import com.alibaba.excel.analysis.v07.XlsxRowResultHolder; +import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.enums.CellDataTypeEnum; @@ -87,12 +87,11 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder int dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(dateFormatIndexInteger); int dataFormat = xssfCellStyle.getDataFormat(); - String dataFormatString = xssfCellStyle.getDataFormatString(); currentCellData.setDataFormat(dataFormat); - if (dataFormatString == null) { + if (dataFormat <= BuiltinFormats.builtinFormats.length) { currentCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat)); } else { - currentCellData.setDataFormatString(dataFormatString); + currentCellData.setDataFormatString(xssfCellStyle.getDataFormatString()); } } } diff --git a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java index 7b3c5bb..5663054 100644 --- a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java +++ b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java @@ -47,7 +47,8 @@ public class BuiltinFormats { // 13 "# ??/??", // 14 - "m/d/yy", + // The official documentation shows "m/d/yy", but the actual test is "yyyy/m/d". + "yyyy/m/d", // 15 "d-mmm-yy", // 16 @@ -63,7 +64,8 @@ public class BuiltinFormats { // 21 "h:mm:ss", // 22 - "m/d/yy h:mm", + // The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy/m/d h:mm". + "yyyy/m/d h:mm", // 23-26 No specific correspondence found in the official documentation. // 23 null, @@ -74,25 +76,25 @@ public class BuiltinFormats { // 26 null, // 27 - "yyyy\"5E74\"m\"6708\"", + "yyyy\"年\"m\"月\"", // 28 - "m\"6708\"d\"65E5\"", + "m\"月\"d\"日\"", // 29 - "m\"6708\"d\"65E5\"", + "m\"月\"d\"日\"", // 30 "m-d-yy", // 31 - "yyyy\"5E74\"m\"6708\"d\"65E5\"", + "yyyy\"年\"m\"月\"d\"日\"", // 32 - "h\"65F6\"mm\"5206\"", + "h\"时\"mm\"分\"", // 33 - "h\"65F6\"mm\"5206\"ss\"79D2\"", + "h\"时\"mm\"分\"ss\"秒\"", // 34 - "4E0A5348/4E0B5348h\"65F6\"mm\"5206\"", + "上午/下午h\"时\"mm\"分\"", // 35 - "4E0A5348/4E0B5348h\"65F6\"mm\"5206\"ss\"79D2\"", + "上午/下午h\"时\"mm\"分\"ss\"秒\"", // 36 - "yyyy\"5E74\"m\"6708\"", + "yyyy\"年\"m\"月\"", // 37 "#,##0_);(#,##0)", // 38 @@ -120,23 +122,23 @@ public class BuiltinFormats { // 49 "@", // 50 - "yyyy\"5E74\"m\"6708\"", + "yyyy\"年\"m\"月\"", // 51 - "m\"6708\"d\"65E5\"", + "m\"月\"d\"日\"", // 52 - "yyyy\"5E74\"m\"6708\"", + "yyyy\"年\"m\"月\"", // 53 - "m\"6708\"d\"65E5\"", + "m\"月\"d\"日\"", // 54 - "m\"6708\"d\"65E5\"", + "m\"月\"d\"日\"", // 55 - "4E0A5348/4E0B5348h\"65F6\"mm\"5206\"", + "上午/下午h\"时\"mm\"分\"", // 56 - "4E0A5348/4E0B5348h\"65F6\"mm\"5206\"ss\"79D2\"", + "上午/下午h\"时\"mm\"分\"ss\"秒\"", // 57 - "yyyy\"5E74\"m\"6708\"", + "yyyy\"年\"m\"月\"", // 58 - "m\"6708\"d\"65E5\"", + "m\"月\"d\"日\"", // 59 "t0", // 60 @@ -163,25 +165,25 @@ public class BuiltinFormats { // 70 "t# ??/??", // 71 - "0E27/0E14/0E1B0E1B0E1B0E1B", + "ว/ด/ปปปป", // 72 - "0E27-0E140E140E14-0E1B0E1B", + "ว-ดดด-ปป", // 73 - "0E27-0E140E140E14", + "ว-ดดด", // 74 - "0E140E140E14-0E1B0E1B", + "ดดด-ปป", // 75 - "0E0A:0E190E19", + "ช:นน", // 76 - "0E0A:0E190E19:0E170E17", + "ช:นน:ทท", // 77 - "0E27/0E14/0E1B0E1B0E1B0E1B 0E0A:0E190E19", + "ว/ด/ปปปป ช:นน", // 78 - "0E190E19:0E170E17", + "นน:ทท", // 79 - "[0E0A]:0E190E19:0E170E17", + "[ช]:นน:ทท", // 80 - "0E190E19:0E170E17.0", + "นน:ทท.0", // 81 "d/m/bb", // end diff --git a/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java b/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java index f536a08..b31bc70 100644 --- a/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/string/StringNumberConverter.java @@ -10,7 +10,9 @@ import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.util.DateUtils; +import com.alibaba.excel.util.NumberDataFormatterUtils; import com.alibaba.excel.util.NumberUtils; +import com.alibaba.excel.util.StringUtils; /** * String and number converter @@ -44,13 +46,9 @@ public class StringNumberConverter implements Converter { return NumberUtils.format(cellData.getNumberValue(), contentProperty); } // Excel defines formatting - if (cellData.getDataFormat() != null) { - if (DateUtil.isADateFormat(cellData.getDataFormat(), cellData.getDataFormatString())) { - return DateUtils.format(DateUtil.getJavaDate(cellData.getNumberValue().doubleValue(), - globalConfiguration.getUse1904windowing(), null)); - } else { - return NumberUtils.format(cellData.getNumberValue(), contentProperty); - } + if (cellData.getDataFormat() != null && !StringUtils.isEmpty(cellData.getDataFormatString())) { + return NumberDataFormatterUtils.format(cellData.getNumberValue().doubleValue(), cellData.getDataFormat(), + cellData.getDataFormatString(), globalConfiguration); } // Default conversion number return NumberUtils.format(cellData.getNumberValue(), contentProperty); diff --git a/src/main/java/com/alibaba/excel/metadata/BasicParameter.java b/src/main/java/com/alibaba/excel/metadata/BasicParameter.java index 40bffe6..d00c93a 100644 --- a/src/main/java/com/alibaba/excel/metadata/BasicParameter.java +++ b/src/main/java/com/alibaba/excel/metadata/BasicParameter.java @@ -1,6 +1,7 @@ package com.alibaba.excel.metadata; import java.util.List; +import java.util.Locale; import com.alibaba.excel.converters.Converter; @@ -34,6 +35,11 @@ public class BasicParameter { * @return */ private Boolean use1904windowing; + /** + * A Locale object represents a specific geographical, political, or cultural region. This parameter is + * used when formatting dates and numbers. + */ + private Locale locale; public List> getHead() { return head; @@ -75,4 +81,11 @@ public class BasicParameter { this.use1904windowing = use1904windowing; } + public Locale getLocale() { + return locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } } diff --git a/src/main/java/com/alibaba/excel/metadata/DataFormatter.java b/src/main/java/com/alibaba/excel/metadata/DataFormatter.java new file mode 100644 index 0000000..13bd162 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/DataFormatter.java @@ -0,0 +1,786 @@ +/* + * ==================================================================== Licensed to the Apache Software Foundation (ASF) + * under one or more contributor license agreements. See the NOTICE file distributed with this work for additional + * information regarding copyright ownership. The ASF licenses this file to You 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. + * + * 2012 - Alfresco Software, Ltd. Alfresco Software has modified source of this file The details of changes as svn diff + * can be found in svn at location root/projects/3rd-party/src + * ==================================================================== + */ +package com.alibaba.excel.metadata; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.DateFormatSymbols; +import java.text.DecimalFormat; +import java.text.DecimalFormatSymbols; +import java.text.FieldPosition; +import java.text.Format; +import java.text.ParsePosition; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.ExcelGeneralNumberFormat; +import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; +import org.apache.poi.ss.usermodel.FractionFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.util.DateUtils; + +/** + * Written with reference to {@link org.apache.poi.ss.usermodel.DataFormatter}.Made some optimizations for date + * conversion. + *

+ * This is a non-thread-safe class. + * + * @author Jiaju Zhuang + */ +public class DataFormatter { + /** For logging any problems we find */ + private static final Logger LOGGER = LoggerFactory.getLogger(DataFormatter.class); + private static final String defaultFractionWholePartFormat = "#"; + private static final String defaultFractionFractionPartFormat = "#/##"; + /** Pattern to find a number format: "0" or "#" */ + private static final Pattern numPattern = Pattern.compile("[0#]+"); + + /** Pattern to find days of week as text "ddd...." */ + private static final Pattern daysAsText = Pattern.compile("([d]{3,})", Pattern.CASE_INSENSITIVE); + + /** Pattern to find "AM/PM" marker */ + private static final Pattern amPmPattern = Pattern.compile("(([AP])[M/P]*)|(([上下])[午/下]*)", Pattern.CASE_INSENSITIVE); + + /** Pattern to find formats with condition ranges e.g. [>=100] */ + private static final Pattern rangeConditionalPattern = + Pattern.compile(".*\\[\\s*(>|>=|<|<=|=)\\s*[0-9]*\\.*[0-9].*"); + + /** + * A regex to find locale patterns like [$$-1009] and [$?-452]. Note that we don't currently process these into + * locales + */ + private static final Pattern localePatternGroup = Pattern.compile("(\\[\\$[^-\\]]*-[0-9A-Z]+])"); + + /** + * A regex to match the colour formattings rules. Allowed colours are: Black, Blue, Cyan, Green, Magenta, Red, + * White, Yellow, "Color n" (1<=n<=56) + */ + private static final Pattern colorPattern = Pattern.compile( + "(\\[BLACK])|(\\[BLUE])|(\\[CYAN])|(\\[GREEN])|" + "(\\[MAGENTA])|(\\[RED])|(\\[WHITE])|(\\[YELLOW])|" + + "(\\[COLOR\\s*\\d])|(\\[COLOR\\s*[0-5]\\d])|(\\[DBNum(1|2|3)])|(\\[\\$-\\d{0,3}])", + Pattern.CASE_INSENSITIVE); + + /** + * A regex to identify a fraction pattern. This requires that replaceAll("\\?", "#") has already been called + */ + private static final Pattern fractionPattern = Pattern.compile("(?:([#\\d]+)\\s+)?(#+)\\s*/\\s*([#\\d]+)"); + + /** + * A regex to strip junk out of fraction formats + */ + private static final Pattern fractionStripper = Pattern.compile("(\"[^\"]*\")|([^ ?#\\d/]+)"); + + /** + * A regex to detect if an alternate grouping character is used in a numeric format + */ + private static final Pattern alternateGrouping = Pattern.compile("([#0]([^.#0])[#0]{3})"); + + /** + * Cells formatted with a date or time format and which contain invalid date or time values show 255 pound signs + * ("#"). + */ + private static final String invalidDateTimeString; + static { + StringBuilder buf = new StringBuilder(); + for (int i = 0; i < 255; i++) + buf.append('#'); + invalidDateTimeString = buf.toString(); + } + + /** + * The decimal symbols of the locale used for formatting values. + */ + private DecimalFormatSymbols decimalSymbols; + + /** + * The date symbols of the locale used for formatting values. + */ + private DateFormatSymbols dateSymbols; + /** A default format to use when a number pattern cannot be parsed. */ + private Format defaultNumFormat; + /** + * A map to cache formats. Map formats + */ + private final Map formats = new HashMap(); + + /** stores the locale valid it the last formatting call */ + private Locale locale; + /** + * true if date uses 1904 windowing, or false if using 1900 date windowing. + * + * default is false + * + * @return + */ + private Boolean use1904windowing; + + /** + * Creates a formatter using the {@link Locale#getDefault() default locale}. + */ + public DataFormatter() { + this(null, null); + } + + /** + * Creates a formatter using the given locale. + * + */ + public DataFormatter(Locale locale, Boolean use1904windowing) { + this.use1904windowing = use1904windowing != null ? use1904windowing : Boolean.FALSE; + this.locale = locale != null ? locale : Locale.getDefault(); + this.locale = Locale.US; + this.dateSymbols = DateFormatSymbols.getInstance(this.locale); + this.decimalSymbols = DecimalFormatSymbols.getInstance(this.locale); + } + + private Format getFormat(Integer dataFormat, String dataFormatString) { + // See if we already have it cached + Format format = formats.get(dataFormatString); + if (format != null) { + return format; + } + // Is it one of the special built in types, General or @? + if ("General".equalsIgnoreCase(dataFormatString) || "@".equals(dataFormatString)) { + format = getDefaultFormat(); + addFormat(dataFormatString, format); + return format; + } + + // Build a formatter, and cache it + format = createFormat(dataFormat, dataFormatString); + addFormat(dataFormatString, format); + return format; + } + + private Format createFormat(Integer dataFormat, String dataFormatString) { + String formatStr = dataFormatString; + + Format format = checkSpecialConverter(formatStr); + if (format != null) { + return format; + } + + // Remove colour formatting if present + Matcher colourM = colorPattern.matcher(formatStr); + while (colourM.find()) { + String colour = colourM.group(); + + // Paranoid replacement... + int at = formatStr.indexOf(colour); + if (at == -1) + break; + String nFormatStr = formatStr.substring(0, at) + formatStr.substring(at + colour.length()); + if (nFormatStr.equals(formatStr)) + break; + + // Try again in case there's multiple + formatStr = nFormatStr; + colourM = colorPattern.matcher(formatStr); + } + + // Strip off the locale information, we use an instance-wide locale for everything + Matcher m = localePatternGroup.matcher(formatStr); + while (m.find()) { + String match = m.group(); + String symbol = match.substring(match.indexOf('$') + 1, match.indexOf('-')); + if (symbol.indexOf('$') > -1) { + symbol = symbol.substring(0, symbol.indexOf('$')) + '\\' + symbol.substring(symbol.indexOf('$')); + } + formatStr = m.replaceAll(symbol); + m = localePatternGroup.matcher(formatStr); + } + + // Check for special cases + if (formatStr == null || formatStr.trim().length() == 0) { + return getDefaultFormat(); + } + + if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) { + return getDefaultFormat(); + } + + if (DateUtils.isADateFormat(dataFormat, formatStr)) { + return createDateFormat(formatStr); + } + // Excel supports fractions in format strings, which Java doesn't + if (formatStr.contains("#/") || formatStr.contains("?/")) { + String[] chunks = formatStr.split(";"); + for (String chunk1 : chunks) { + String chunk = chunk1.replaceAll("\\?", "#"); + Matcher matcher = fractionStripper.matcher(chunk); + chunk = matcher.replaceAll(" "); + chunk = chunk.replaceAll(" +", " "); + Matcher fractionMatcher = fractionPattern.matcher(chunk); + // take the first match + if (fractionMatcher.find()) { + String wholePart = (fractionMatcher.group(1) == null) ? "" : defaultFractionWholePartFormat; + return new FractionFormat(wholePart, fractionMatcher.group(3)); + } + } + + // Strip custom text in quotes and escaped characters for now as it can cause performance problems in + // fractions. + // String strippedFormatStr = formatStr.replaceAll("\\\\ ", " ").replaceAll("\\\\.", + // "").replaceAll("\"[^\"]*\"", " ").replaceAll("\\?", "#"); + return new FractionFormat(defaultFractionWholePartFormat, defaultFractionFractionPartFormat); + } + + if (numPattern.matcher(formatStr).find()) { + return createNumberFormat(formatStr); + } + return getDefaultFormat(); + } + + private Format checkSpecialConverter(String dataFormatString) { + if ("00000\\-0000".equals(dataFormatString) || "00000-0000".equals(dataFormatString)) { + return new ZipPlusFourFormat(); + } + if ("[<=9999999]###\\-####;\\(###\\)\\ ###\\-####".equals(dataFormatString) + || "[<=9999999]###-####;(###) ###-####".equals(dataFormatString) + || "###\\-####;\\(###\\)\\ ###\\-####".equals(dataFormatString) + || "###-####;(###) ###-####".equals(dataFormatString)) { + return new PhoneFormat(); + } + if ("000\\-00\\-0000".equals(dataFormatString) || "000-00-0000".equals(dataFormatString)) { + return new SSNFormat(); + } + return null; + } + + private Format createDateFormat(String pFormatStr) { + String formatStr = pFormatStr; + formatStr = formatStr.replaceAll("\\\\-", "-"); + formatStr = formatStr.replaceAll("\\\\,", ","); + formatStr = formatStr.replaceAll("\\\\\\.", "."); // . is a special regexp char + formatStr = formatStr.replaceAll("\\\\ ", " "); + formatStr = formatStr.replaceAll("\\\\/", "/"); // weird: m\\/d\\/yyyy + formatStr = formatStr.replaceAll(";@", ""); + formatStr = formatStr.replaceAll("\"/\"", "/"); // "/" is escaped for no reason in: mm"/"dd"/"yyyy + formatStr = formatStr.replace("\"\"", "'"); // replace Excel quoting with Java style quoting + formatStr = formatStr.replaceAll("\\\\T", "'T'"); // Quote the T is iso8601 style dates + formatStr = formatStr.replace("\"", ""); + + boolean hasAmPm = false; + Matcher amPmMatcher = amPmPattern.matcher(formatStr); + while (amPmMatcher.find()) { + formatStr = amPmMatcher.replaceAll("@"); + hasAmPm = true; + amPmMatcher = amPmPattern.matcher(formatStr); + } + formatStr = formatStr.replaceAll("@", "a"); + + Matcher dateMatcher = daysAsText.matcher(formatStr); + if (dateMatcher.find()) { + String match = dateMatcher.group(0).toUpperCase(Locale.ROOT).replaceAll("D", "E"); + formatStr = dateMatcher.replaceAll(match); + } + + // Convert excel date format to SimpleDateFormat. + // Excel uses lower and upper case 'm' for both minutes and months. + // From Excel help: + /* + The "m" or "mm" code must appear immediately after the "h" or"hh" + code or immediately before the "ss" code; otherwise, Microsoft + Excel displays the month instead of minutes." + */ + StringBuilder sb = new StringBuilder(); + char[] chars = formatStr.toCharArray(); + boolean mIsMonth = true; + List ms = new ArrayList(); + boolean isElapsed = false; + for (int j = 0; j < chars.length; j++) { + char c = chars[j]; + if (c == '\'') { + sb.append(c); + j++; + + // skip until the next quote + while (j < chars.length) { + c = chars[j]; + sb.append(c); + if (c == '\'') { + break; + } + j++; + } + } else if (c == '[' && !isElapsed) { + isElapsed = true; + mIsMonth = false; + sb.append(c); + } else if (c == ']' && isElapsed) { + isElapsed = false; + sb.append(c); + } else if (isElapsed) { + if (c == 'h' || c == 'H') { + sb.append('H'); + } else if (c == 'm' || c == 'M') { + sb.append('m'); + } else if (c == 's' || c == 'S') { + sb.append('s'); + } else { + sb.append(c); + } + } else if (c == 'h' || c == 'H') { + mIsMonth = false; + if (hasAmPm) { + sb.append('h'); + } else { + sb.append('H'); + } + } else if (c == 'm' || c == 'M') { + if (mIsMonth) { + sb.append('M'); + ms.add(Integer.valueOf(sb.length() - 1)); + } else { + sb.append('m'); + } + } else if (c == 's' || c == 'S') { + sb.append('s'); + // if 'M' precedes 's' it should be minutes ('m') + for (int index : ms) { + if (sb.charAt(index) == 'M') { + sb.replace(index, index + 1, "m"); + } + } + mIsMonth = true; + ms.clear(); + } else if (Character.isLetter(c)) { + mIsMonth = true; + ms.clear(); + if (c == 'y' || c == 'Y') { + sb.append('y'); + } else if (c == 'd' || c == 'D') { + sb.append('d'); + } else { + sb.append(c); + } + } else { + if (Character.isWhitespace(c)) { + ms.clear(); + } + sb.append(c); + } + } + formatStr = sb.toString(); + + try { + return new ExcelStyleDateFormatter(formatStr, dateSymbols); + } catch (IllegalArgumentException iae) { + LOGGER.debug("Formatting failed for format {}, falling back", formatStr, iae); + // the pattern could not be parsed correctly, + // so fall back to the default number format + return getDefaultFormat(); + } + + } + + private String cleanFormatForNumber(String formatStr) { + StringBuilder sb = new StringBuilder(formatStr); + // If they requested spacers, with "_", + // remove those as we don't do spacing + // If they requested full-column-width + // padding, with "*", remove those too + for (int i = 0; i < sb.length(); i++) { + char c = sb.charAt(i); + if (c == '_' || c == '*') { + if (i > 0 && sb.charAt((i - 1)) == '\\') { + // It's escaped, don't worry + continue; + } + if (i < sb.length() - 1) { + // Remove the character we're supposed + // to match the space of / pad to the + // column width with + sb.deleteCharAt(i + 1); + } + // Remove the _ too + sb.deleteCharAt(i); + i--; + } + } + + // Now, handle the other aspects like + // quoting and scientific notation + for (int i = 0; i < sb.length(); i++) { + char c = sb.charAt(i); + // remove quotes and back slashes + if (c == '\\' || c == '"') { + sb.deleteCharAt(i); + i--; + + // for scientific/engineering notation + } else if (c == '+' && i > 0 && sb.charAt(i - 1) == 'E') { + sb.deleteCharAt(i); + i--; + } + } + + return sb.toString(); + } + + private static class InternalDecimalFormatWithScale extends Format { + + private static final Pattern endsWithCommas = Pattern.compile("(,+)$"); + private BigDecimal divider; + private static final BigDecimal ONE_THOUSAND = new BigDecimal(1000); + private final DecimalFormat df; + + private static String trimTrailingCommas(String s) { + return s.replaceAll(",+$", ""); + } + + public InternalDecimalFormatWithScale(String pattern, DecimalFormatSymbols symbols) { + df = new DecimalFormat(trimTrailingCommas(pattern), symbols); + setExcelStyleRoundingMode(df); + Matcher endsWithCommasMatcher = endsWithCommas.matcher(pattern); + if (endsWithCommasMatcher.find()) { + String commas = (endsWithCommasMatcher.group(1)); + BigDecimal temp = BigDecimal.ONE; + for (int i = 0; i < commas.length(); ++i) { + temp = temp.multiply(ONE_THOUSAND); + } + divider = temp; + } else { + divider = null; + } + } + + private Object scaleInput(Object obj) { + if (divider != null) { + if (obj instanceof BigDecimal) { + obj = ((BigDecimal)obj).divide(divider, RoundingMode.HALF_UP); + } else if (obj instanceof Double) { + obj = (Double)obj / divider.doubleValue(); + } else { + throw new UnsupportedOperationException(); + } + } + return obj; + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + obj = scaleInput(obj); + return df.format(obj, toAppendTo, pos); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + throw new UnsupportedOperationException(); + } + } + + private Format createNumberFormat(String formatStr) { + String format = cleanFormatForNumber(formatStr); + DecimalFormatSymbols symbols = decimalSymbols; + + // Do we need to change the grouping character? + // eg for a format like #'##0 which wants 12'345 not 12,345 + Matcher agm = alternateGrouping.matcher(format); + if (agm.find()) { + char grouping = agm.group(2).charAt(0); + // Only replace the grouping character if it is not the default + // grouping character for the US locale (',') in order to enable + // correct grouping for non-US locales. + if (grouping != ',') { + symbols = DecimalFormatSymbols.getInstance(locale); + + symbols.setGroupingSeparator(grouping); + String oldPart = agm.group(1); + String newPart = oldPart.replace(grouping, ','); + format = format.replace(oldPart, newPart); + } + } + + try { + return new InternalDecimalFormatWithScale(format, symbols); + } catch (IllegalArgumentException iae) { + LOGGER.debug("Formatting failed for format {}, falling back", formatStr, iae); + // the pattern could not be parsed correctly, + // so fall back to the default number format + return getDefaultFormat(); + } + } + + private Format getDefaultFormat() { + // for numeric cells try user supplied default + if (defaultNumFormat != null) { + return defaultNumFormat; + // otherwise use general format + } + defaultNumFormat = new ExcelGeneralNumberFormat(locale); + return defaultNumFormat; + } + + /** + * Performs Excel-style date formatting, using the supplied Date and format + */ + private String performDateFormatting(Date d, Format dateFormat) { + Format df = dateFormat != null ? dateFormat : getDefaultFormat(); + return df.format(d); + } + + /** + * Returns the formatted value of an Excel date as a String based on the cell's DataFormat. + * i.e. "Thursday, January 02, 2003" , "01/02/2003" , "02-Jan" , etc. + *

+ * If any conditional format rules apply, the highest priority with a number format is used. If no rules contain a + * number format, or no rules apply, the cell's style format is used. If the style does not have a format, the + * default date format is applied. + * + * @param data + * to format + * @param dataFormat + * @param dataFormatString + * @return Formatted value + */ + private String getFormattedDateString(Double data, Integer dataFormat, String dataFormatString) { + Format dateFormat = getFormat(dataFormat, dataFormatString); + if (dateFormat instanceof ExcelStyleDateFormatter) { + // Hint about the raw excel value + ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(data); + } + return performDateFormatting(DateUtil.getJavaDate(data, use1904windowing), dateFormat); + } + + /** + * Returns the formatted value of an Excel number as a String based on the cell's DataFormat. + * Supported formats include currency, percents, decimals, phone number, SSN, etc.: "61.54%", "$100.00", "(800) + * 555-1234". + *

+ * Format comes from either the highest priority conditional format rule with a specified format, or from the cell + * style. + * + * @param data + * to format + * @param dataFormat + * @param dataFormatString + * @return a formatted number string + */ + private String getFormattedNumberString(Double data, Integer dataFormat, String dataFormatString) { + Format numberFormat = getFormat(dataFormat, dataFormatString); + String formatted = numberFormat.format(data); + return formatted.replaceFirst("E(\\d)", "E+$1"); // to match Excel's E-notation + } + + /** + * Format data. + * + * @param data + * @param dataFormat + * @param dataFormatString + * @return + */ + public String format(Double data, Integer dataFormat, String dataFormatString) { + if (DateUtils.isADateFormat(dataFormat, dataFormatString)) { + return getFormattedDateString(data, dataFormat, dataFormatString); + } + return getFormattedNumberString(data, dataFormat, dataFormatString); + } + + /** + *

+ * Sets a default number format to be used when the Excel format cannot be parsed successfully. Note: This is + * a fall back for when an error occurs while parsing an Excel number format pattern. This will not affect cells + * with the General format. + *

+ *

+ * The value that will be passed to the Format's format method (specified by java.text.Format#format) + * will be a double value from a numeric cell. Therefore the code in the format method should expect a + * Number value. + *

+ * + * @param format + * A Format instance to be used as a default + * @see Format#format + */ + public void setDefaultNumberFormat(Format format) { + for (Map.Entry entry : formats.entrySet()) { + if (entry.getValue() == defaultNumFormat) { + entry.setValue(format); + } + } + defaultNumFormat = format; + } + + /** + * Adds a new format to the available formats. + *

+ * The value that will be passed to the Format's format method (specified by java.text.Format#format) + * will be a double value from a numeric cell. Therefore the code in the format method should expect a + * Number value. + *

+ * + * @param excelFormatStr + * The data format string + * @param format + * A Format instance + */ + public void addFormat(String excelFormatStr, Format format) { + formats.put(excelFormatStr, format); + } + + // Some custom formats + + /** + * @return a DecimalFormat with parseIntegerOnly set true + */ + private static DecimalFormat createIntegerOnlyFormat(String fmt) { + DecimalFormatSymbols dsf = DecimalFormatSymbols.getInstance(Locale.ROOT); + DecimalFormat result = new DecimalFormat(fmt, dsf); + result.setParseIntegerOnly(true); + return result; + } + + /** + * Enables excel style rounding mode (round half up) on the Decimal Format given. + */ + public static void setExcelStyleRoundingMode(DecimalFormat format) { + setExcelStyleRoundingMode(format, RoundingMode.HALF_UP); + } + + /** + * Enables custom rounding mode on the given Decimal Format. + * + * @param format + * DecimalFormat + * @param roundingMode + * RoundingMode + */ + public static void setExcelStyleRoundingMode(DecimalFormat format, RoundingMode roundingMode) { + format.setRoundingMode(roundingMode); + } + + /** + * Format class for Excel's SSN format. This class mimics Excel's built-in SSN formatting. + * + * @author James May + */ + @SuppressWarnings("serial") + private static final class SSNFormat extends Format { + private static final DecimalFormat df = createIntegerOnlyFormat("000000000"); + + private SSNFormat() { + // enforce singleton + } + + /** Format a number as an SSN */ + public static String format(Number num) { + String result = df.format(num); + return result.substring(0, 3) + '-' + result.substring(3, 5) + '-' + result.substring(5, 9); + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(format((Number)obj)); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return df.parseObject(source, pos); + } + } + + /** + * Format class for Excel Zip + 4 format. This class mimics Excel's built-in formatting for Zip + 4. + * + * @author James May + */ + @SuppressWarnings("serial") + private static final class ZipPlusFourFormat extends Format { + private static final DecimalFormat df = createIntegerOnlyFormat("000000000"); + + private ZipPlusFourFormat() { + // enforce singleton + } + + /** Format a number as Zip + 4 */ + public static String format(Number num) { + String result = df.format(num); + return result.substring(0, 5) + '-' + result.substring(5, 9); + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(format((Number)obj)); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return df.parseObject(source, pos); + } + } + + /** + * Format class for Excel phone number format. This class mimics Excel's built-in phone number formatting. + * + * @author James May + */ + @SuppressWarnings("serial") + private static final class PhoneFormat extends Format { + private static final DecimalFormat df = createIntegerOnlyFormat("##########"); + + private PhoneFormat() { + // enforce singleton + } + + /** Format a number as a phone number */ + public static String format(Number num) { + String result = df.format(num); + StringBuilder sb = new StringBuilder(); + String seg1, seg2, seg3; + int len = result.length(); + if (len <= 4) { + return result; + } + + seg3 = result.substring(len - 4, len); + seg2 = result.substring(Math.max(0, len - 7), len - 4); + seg1 = result.substring(Math.max(0, len - 10), Math.max(0, len - 7)); + + if (seg1.trim().length() > 0) { + sb.append('(').append(seg1).append(") "); + } + if (seg2.trim().length() > 0) { + sb.append(seg2).append('-'); + } + sb.append(seg3); + return sb.toString(); + } + + @Override + public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) { + return toAppendTo.append(format((Number)obj)); + } + + @Override + public Object parseObject(String source, ParsePosition pos) { + return df.parseObject(source, pos); + } + } + +} diff --git a/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java b/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java index 921d70a..12cc8d3 100644 --- a/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java +++ b/src/main/java/com/alibaba/excel/metadata/GlobalConfiguration.java @@ -1,5 +1,7 @@ package com.alibaba.excel.metadata; +import java.util.Locale; + /** * Global configuration * @@ -18,6 +20,11 @@ public class GlobalConfiguration { * @return */ private Boolean use1904windowing; + /** + * A Locale object represents a specific geographical, political, or cultural region. This parameter is + * used when formatting dates and numbers. + */ + private Locale locale; public Boolean getUse1904windowing() { return use1904windowing; @@ -34,4 +41,12 @@ public class GlobalConfiguration { public void setAutoTrim(Boolean autoTrim) { this.autoTrim = autoTrim; } + + public Locale getLocale() { + return locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } } diff --git a/src/main/java/com/alibaba/excel/util/DateUtils.java b/src/main/java/com/alibaba/excel/util/DateUtils.java index dfc8d20..b375733 100644 --- a/src/main/java/com/alibaba/excel/util/DateUtils.java +++ b/src/main/java/com/alibaba/excel/util/DateUtils.java @@ -1,24 +1,45 @@ package com.alibaba.excel.util; -import java.text.Format; +import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; - -import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.DateUtil; -import org.apache.poi.ss.usermodel.ExcelNumberFormat; -import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Pattern; /** * Date utils * * @author Jiaju Zhuang **/ -public class DateUtils { - +public class DateUtils implements ThreadLocalCachedUtils { + /** + * Is a cache of dates + */ + private static final ThreadLocal> DATE_THREAD_LOCAL = + new ThreadLocal>(); + /** + * Is a cache of dates + */ + private static final ThreadLocal> DATE_FORMAT_THREAD_LOCAL = + new ThreadLocal>(); + /** + * The following patterns are used in {@link #isADateFormat(Integer, String)} + */ + private static final Pattern date_ptrn1 = Pattern.compile("^\\[\\$\\-.*?\\]"); + private static final Pattern date_ptrn2 = Pattern.compile("^\\[[a-zA-Z]+\\]"); + private static final Pattern date_ptrn3a = Pattern.compile("[yYmMdDhHsS]"); + // add "\u5e74 \u6708 \u65e5" for Chinese/Japanese date format:2017 \u5e74 2 \u6708 7 \u65e5 + private static final Pattern date_ptrn3b = + Pattern.compile("^[\\[\\]yYmMdDhHsS\\-T/\u5e74\u6708\u65e5,. :\"\\\\]+0*[ampAMP/]*$"); + // elapsed time patterns: [h],[m] and [s] + private static final Pattern date_ptrn4 = Pattern.compile("^\\[([hH]+|[mM]+|[sS]+)\\]"); + // for format which start with "[DBNum1]" or "[DBNum2]" or "[DBNum3]" could be a Chinese date + private static final Pattern date_ptrn5 = Pattern.compile("^\\[DBNum(1|2|3)\\]"); + // for format which start with "年" or "月" or "日" or "时" or "分" or "秒" could be a Chinese date + private static final Pattern date_ptrn6 = Pattern.compile("(年|月|日|时|分|秒)+"); public static final String DATE_FORMAT_10 = "yyyy-MM-dd"; public static final String DATE_FORMAT_14 = "yyyyMMddHHmmss"; @@ -41,7 +62,7 @@ public class DateUtils { if (StringUtils.isEmpty(dateFormat)) { dateFormat = switchDateFormat(dateString); } - return new SimpleDateFormat(dateFormat).parse(dateString); + return getCacheDateFormat(dateFormat).parse(dateString); } /** @@ -107,196 +128,183 @@ public class DateUtils { if (StringUtils.isEmpty(dateFormat)) { dateFormat = DATE_FORMAT_19; } - return new SimpleDateFormat(dateFormat).format(date); + return getCacheDateFormat(dateFormat).format(date); + } + + private static DateFormat getCacheDateFormat(String dateFormat) { + Map dateFormatMap = DATE_FORMAT_THREAD_LOCAL.get(); + if (dateFormatMap == null) { + dateFormatMap = new HashMap(); + DATE_FORMAT_THREAD_LOCAL.set(dateFormatMap); + } else { + SimpleDateFormat dateFormatCached = dateFormatMap.get(dateFormat); + if (dateFormatCached != null) { + return dateFormatCached; + } + } + SimpleDateFormat simpleDateFormat = new SimpleDateFormat(dateFormat); + dateFormatMap.put(dateFormat, simpleDateFormat); + return simpleDateFormat; } -// -// /** -// * Determine if it is a date format. -// * -// * @param dataFormat -// * @param dataFormatString -// * @return -// */ -// public static boolean isDateFormatted(Integer dataFormat, String dataFormatString) { -// if (cell == null) { -// return false; -// } -// boolean isDate = false; -// -// double d = cell.getNumericCellValue(); -// if (DateUtil.isValidExcelDate(d)) { -// ExcelNumberFormat nf = ExcelNumberFormat.from(cell, cfEvaluator); -// if (nf == null) { -// return false; -// } -// bDate = isADateFormat(nf); -// } -// return bDate; -// } -// -// private String getFormattedDateString(Cell cell, ConditionalFormattingEvaluator cfEvaluator) { -// if (cell == null) { -// return null; -// } -// Format dateFormat = getFormat(cell, cfEvaluator); -// synchronized (dateFormat) { -// if(dateFormat instanceof ExcelStyleDateFormatter) { -// // Hint about the raw excel value -// ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted( -// cell.getNumericCellValue() -// ); -// } -// Date d = cell.getDateCellValue(); -// return performDateFormatting(d, dateFormat); -// } -// } -// -// -// public static boolean isADateFormat(int formatIndex, String formatString) { -// // First up, is this an internal date format? -// if (isInternalDateFormat(formatIndex)) { -// return true; -// } -// if (StringUtils.isEmpty(formatString)) { -// return false; -// } -// -// // check the cache first -// if (isCached(formatString, formatIndex)) { -// return lastCachedResult.get(); -// } -// -// String fs = formatString; -// /*if (false) { -// // Normalize the format string. The code below is equivalent -// // to the following consecutive regexp replacements: -// -// // Translate \- into just -, before matching -// fs = fs.replaceAll("\\\\-","-"); -// // And \, into , -// fs = fs.replaceAll("\\\\,",","); -// // And \. into . -// fs = fs.replaceAll("\\\\\\.","."); -// // And '\ ' into ' ' -// fs = fs.replaceAll("\\\\ "," "); -// -// // If it end in ;@, that's some crazy dd/mm vs mm/dd -// // switching stuff, which we can ignore -// fs = fs.replaceAll(";@", ""); -// -// // The code above was reworked as suggested in bug 48425: -// // simple loop is more efficient than consecutive regexp replacements. -// }*/ -// final int length = fs.length(); -// StringBuilder sb = new StringBuilder(length); -// for (int i = 0; i < length; i++) { -// char c = fs.charAt(i); -// if (i < length - 1) { -// char nc = fs.charAt(i + 1); -// if (c == '\\') { -// switch (nc) { -// case '-': -// case ',': -// case '.': -// case ' ': -// case '\\': -// // skip current '\' and continue to the next char -// continue; -// } -// } else if (c == ';' && nc == '@') { -// i++; -// // skip ";@" duplets -// continue; -// } -// } -// sb.append(c); -// } -// fs = sb.toString(); -// -// // short-circuit if it indicates elapsed time: [h], [m] or [s] -// if (date_ptrn4.matcher(fs).matches()) { -// cache(formatString, formatIndex, true); -// return true; -// } -// // If it starts with [DBNum1] or [DBNum2] or [DBNum3] -// // then it could be a Chinese date -// fs = date_ptrn5.matcher(fs).replaceAll(""); -// // If it starts with [$-...], then could be a date, but -// // who knows what that starting bit is all about -// fs = date_ptrn1.matcher(fs).replaceAll(""); -// // If it starts with something like [Black] or [Yellow], -// // then it could be a date -// fs = date_ptrn2.matcher(fs).replaceAll(""); -// // You're allowed something like dd/mm/yy;[red]dd/mm/yy -// // which would place dates before 1900/1904 in red -// // For now, only consider the first one -// final int separatorIndex = fs.indexOf(';'); -// if (0 < separatorIndex && separatorIndex < fs.length() - 1) { -// fs = fs.substring(0, separatorIndex); -// } -// -// // Ensure it has some date letters in it -// // (Avoids false positives on the rest of pattern 3) -// if (!date_ptrn3a.matcher(fs).find()) { -// return false; -// } -// -// // If we get here, check it's only made up, in any case, of: -// // y m d h s - \ / , . : [ ] T -// // optionally followed by AM/PM -// -// boolean result = date_ptrn3b.matcher(fs).matches(); -// cache(formatString, formatIndex, result); -// return result; -// } -// -// /** -// * Given a format ID this will check whether the format represents an internal excel date format or not. -// * -// * @see #isADateFormat(int, java.lang.String) -// */ -// public static boolean isInternalDateFormat(int format) { -// switch (format) { -// // Internal Date Formats as described on page 427 in -// // Microsoft Excel Dev's Kit... -// // 14-22 -// case 0x0e: -// case 0x0f: -// case 0x10: -// case 0x11: -// case 0x12: -// case 0x13: -// case 0x14: -// case 0x15: -// case 0x16: -// // 27-36 -// case 0x1b: -// case 0x1c: -// case 0x1d: -// case 0x1e: -// case 0x1f: -// case 0x20: -// case 0x21: -// case 0x22: -// case 0x23: -// case 0x24: -// // 45-47 -// case 0x2d: -// case 0x2e: -// case 0x2f: -// // 50-58 -// case 0x32: -// case 0x33: -// case 0x34: -// case 0x35: -// case 0x36: -// case 0x37: -// case 0x38: -// case 0x39: -// case 0x3a: -// return true; -// } -// return false; -// } + /** + * Determine if it is a date format. + * + * @param formatIndex + * @param formatString + * @return + */ + public static boolean isADateFormat(Integer formatIndex, String formatString) { + if (formatIndex == null) { + return false; + } + Map isDateCache = DATE_THREAD_LOCAL.get(); + if (isDateCache == null) { + isDateCache = new HashMap(); + DATE_THREAD_LOCAL.set(isDateCache); + } else { + Boolean isDateCachedData = isDateCache.get(formatIndex); + if (isDateCachedData != null) { + return isDateCachedData; + } + } + boolean isDate = isADateFormatUncached(formatIndex, formatString); + isDateCache.put(formatIndex, isDate); + return isDate; + } + + /** + * Determine if it is a date format. + * + * @param formatIndex + * @param formatString + * @return + */ + public static boolean isADateFormatUncached(Integer formatIndex, String formatString) { + // First up, is this an internal date format? + if (isInternalDateFormat(formatIndex)) { + return true; + } + if (StringUtils.isEmpty(formatString)) { + return false; + } + String fs = formatString; + final int length = fs.length(); + StringBuilder sb = new StringBuilder(length); + for (int i = 0; i < length; i++) { + char c = fs.charAt(i); + if (i < length - 1) { + char nc = fs.charAt(i + 1); + if (c == '\\') { + switch (nc) { + case '-': + case ',': + case '.': + case ' ': + case '\\': + // skip current '\' and continue to the next char + continue; + } + } else if (c == ';' && nc == '@') { + i++; + // skip ";@" duplets + continue; + } + } + sb.append(c); + } + fs = sb.toString(); + + // short-circuit if it indicates elapsed time: [h], [m] or [s] + if (date_ptrn4.matcher(fs).matches()) { + return true; + } + // If it starts with [DBNum1] or [DBNum2] or [DBNum3] + // then it could be a Chinese date + fs = date_ptrn5.matcher(fs).replaceAll(""); + // If it starts with [$-...], then could be a date, but + // who knows what that starting bit is all about + fs = date_ptrn1.matcher(fs).replaceAll(""); + // If it starts with something like [Black] or [Yellow], + // then it could be a date + fs = date_ptrn2.matcher(fs).replaceAll(""); + // You're allowed something like dd/mm/yy;[red]dd/mm/yy + // which would place dates before 1900/1904 in red + // For now, only consider the first one + final int separatorIndex = fs.indexOf(';'); + if (0 < separatorIndex && separatorIndex < fs.length() - 1) { + fs = fs.substring(0, separatorIndex); + } + + // Ensure it has some date letters in it + // (Avoids false positives on the rest of pattern 3) + if (!date_ptrn3a.matcher(fs).find()) { + return false; + } + + // If we get here, check it's only made up, in any case, of: + // y m d h s - \ / , . : [ ] T + // optionally followed by AM/PM + boolean result = date_ptrn3b.matcher(fs).matches(); + if (result) { + return true; + } + result = date_ptrn6.matcher(fs).find(); + return result; + } + + /** + * Given a format ID this will check whether the format represents an internal excel date format or not. + * + * @see #isADateFormat(Integer, String) + */ + public static boolean isInternalDateFormat(int format) { + switch (format) { + // Internal Date Formats as described on page 427 in + // Microsoft Excel Dev's Kit... + // 14-22 + case 0x0e: + case 0x0f: + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + // 27-36 + case 0x1b: + case 0x1c: + case 0x1d: + case 0x1e: + case 0x1f: + case 0x20: + case 0x21: + case 0x22: + case 0x23: + case 0x24: + // 45-47 + case 0x2d: + case 0x2e: + case 0x2f: + // 50-58 + case 0x32: + case 0x33: + case 0x34: + case 0x35: + case 0x36: + case 0x37: + case 0x38: + case 0x39: + case 0x3a: + return true; + } + return false; + } + + @Override + public void removeThreadLocalCache() { + DATE_THREAD_LOCAL.remove(); + DATE_FORMAT_THREAD_LOCAL.remove(); + } } diff --git a/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java b/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java index 6a4b9c5..52ced2a 100644 --- a/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java +++ b/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java @@ -1,154 +1,47 @@ -//package com.alibaba.excel.util; -// -//import java.text.Format; -// -//import org.apache.poi.ss.format.CellFormat; -//import org.apache.poi.ss.formula.ConditionalFormattingEvaluator; -//import org.apache.poi.ss.usermodel.Cell; -//import org.apache.poi.ss.usermodel.DataFormatter; -//import org.apache.poi.ss.usermodel.DateUtil; -//import org.apache.poi.ss.usermodel.ExcelNumberFormat; -//import org.apache.poi.ss.usermodel.ExcelStyleDateFormatter; -//import org.apache.poi.util.POILogger; -// -///** -// * Convert number data, including date. -// * -// * @author Jiaju Zhuang -// **/ -//public class NumberDataFormatterUtils { -// -// /** -// * -// * @param data -// * Not null. -// * @param dataFormatString -// * Not null. -// * @return -// */ -// public String format(Double data, Integer dataFormat, String dataFormatString) { -// -// if (DateUtil.isCellDateFormatted(cell, cfEvaluator)) { -// return getFormattedDateString(cell, cfEvaluator); -// } -// return getFormattedNumberString(cell, cfEvaluator); -// -// } -// -// private String getFormattedDateString(Double data,String dataFormatString) { -// -// -// if (cell == null) { -// return null; -// } -// Format dateFormat = getFormat(cell, cfEvaluator); -// synchronized (dateFormat) { -// if (dateFormat instanceof ExcelStyleDateFormatter) { -// // Hint about the raw excel value -// ((ExcelStyleDateFormatter)dateFormat).setDateToBeFormatted(cell.getNumericCellValue()); -// } -// Date d = cell.getDateCellValue(); -// return performDateFormatting(d, dateFormat); -// } -// } -// -// -// /** -// * Return a Format for the given cell if one exists, otherwise try to -// * create one. This method will return null if the any of the -// * following is true: -// *
    -// *
  • the cell's style is null
  • -// *
  • the style's data format string is null or empty
  • -// *
  • the format string cannot be recognized as either a number or date
  • -// *
-// * -// * @param cell The cell to retrieve a Format for -// * @return A Format for the format String -// */ -// private Format getFormat(Cell cell, ConditionalFormattingEvaluator cfEvaluator) { -// if (cell == null) return null; -// -// ExcelNumberFormat numFmt = ExcelNumberFormat.from(cell, cfEvaluator); -// -// if ( numFmt == null) { -// return null; -// } -// -// int formatIndex = numFmt.getIdx(); -// String formatStr = numFmt.getFormat(); -// if(formatStr == null || formatStr.trim().length() == 0) { -// return null; -// } -// return getFormat(cell.getNumericCellValue(), formatIndex, formatStr, isDate1904(cell)); -// } -// -// private boolean isDate1904(Cell cell) { -// if ( cell != null && cell.getSheet().getWorkbook() instanceof Date1904Support) { -// return ((Date1904Support)cell.getSheet().getWorkbook()).isDate1904(); -// -// } -// return false; -// } -// -// private Format getFormat(double cellValue, int formatIndex, String formatStrIn, boolean use1904Windowing) { -// localeChangedObservable.checkForLocaleChange(); -// -// // Might be better to separate out the n p and z formats, falling back to p when n and z are not set. -// // That however would require other code to be re factored. -// // String[] formatBits = formatStrIn.split(";"); -// // int i = cellValue > 0.0 ? 0 : cellValue < 0.0 ? 1 : 2; -// // String formatStr = (i < formatBits.length) ? formatBits[i] : formatBits[0]; -// -// String formatStr = formatStrIn; -// -// // Excel supports 2+ part conditional data formats, eg positive/negative/zero, -// // or (>1000),(>0),(0),(negative). As Java doesn't handle these kinds -// // of different formats for different ranges, just +ve/-ve, we need to -// // handle these ourselves in a special way. -// // For now, if we detect 2+ parts, we call out to CellFormat to handle it -// // TODO Going forward, we should really merge the logic between the two classes -// if (formatStr.contains(";") && -// (formatStr.indexOf(';') != formatStr.lastIndexOf(';') -// || rangeConditionalPattern.matcher(formatStr).matches() -// ) ) { -// try { -// // Ask CellFormat to get a formatter for it -// CellFormat cfmt = CellFormat.getInstance(locale, formatStr); -// // CellFormat requires callers to identify date vs not, so do so -// Object cellValueO = Double.valueOf(cellValue); -// if (DateUtil.isADateFormat(formatIndex, formatStr) && -// // don't try to handle Date value 0, let a 3 or 4-part format take care of it -// ((Double)cellValueO).doubleValue() != 0.0) { -// cellValueO = DateUtil.getJavaDate(cellValue, use1904Windowing); -// } -// // Wrap and return (non-cachable - CellFormat does that) -// return new DataFormatter.CellFormatResultWrapper( cfmt.apply(cellValueO) ); -// } catch (Exception e) { -// logger.log(POILogger.WARN, "Formatting failed for format " + formatStr + ", falling back", e); -// } -// } -// -// // Excel's # with value 0 will output empty where Java will output 0. This hack removes the # from the format. -// if (emulateCSV && cellValue == 0.0 && formatStr.contains("#") && !formatStr.contains("0")) { -// formatStr = formatStr.replaceAll("#", ""); -// } -// -// // See if we already have it cached -// Format format = formats.get(formatStr); -// if (format != null) { -// return format; -// } -// -// // Is it one of the special built in types, General or @? -// if ("General".equalsIgnoreCase(formatStr) || "@".equals(formatStr)) { -// return generalNumberFormat; -// } -// -// // Build a formatter, and cache it -// format = createFormat(cellValue, formatIndex, formatStr); -// formats.put(formatStr, format); -// return format; -// } -// -//} +package com.alibaba.excel.util; + +import com.alibaba.excel.metadata.DataFormatter; +import com.alibaba.excel.metadata.GlobalConfiguration; + +/** + * Convert number data, including date. + * + * @author Jiaju Zhuang + **/ +public class NumberDataFormatterUtils implements ThreadLocalCachedUtils { + /** + * Cache DataFormatter. + */ + private static final ThreadLocal DATA_FORMATTER_THREAD_LOCAL = new ThreadLocal(); + + /** + * Format number data. + * + * @param data + * @param dataFormat + * Not null. + * @param dataFormatString + * @param globalConfiguration + * @return + */ + public static String format(Double data, Integer dataFormat, String dataFormatString, + GlobalConfiguration globalConfiguration) { + DataFormatter dataFormatter = DATA_FORMATTER_THREAD_LOCAL.get(); + if (dataFormatter == null) { + if (globalConfiguration != null) { + dataFormatter = + new DataFormatter(globalConfiguration.getLocale(), globalConfiguration.getUse1904windowing()); + } else { + dataFormatter = new DataFormatter(); + } + DATA_FORMATTER_THREAD_LOCAL.set(dataFormatter); + } + return dataFormatter.format(data, dataFormat, dataFormatString); + + } + + @Override + public void removeThreadLocalCache() { + DATA_FORMATTER_THREAD_LOCAL.remove(); + } +} diff --git a/src/main/java/com/alibaba/excel/util/ThreadLocalCachedUtils.java b/src/main/java/com/alibaba/excel/util/ThreadLocalCachedUtils.java new file mode 100644 index 0000000..d136703 --- /dev/null +++ b/src/main/java/com/alibaba/excel/util/ThreadLocalCachedUtils.java @@ -0,0 +1,14 @@ +package com.alibaba.excel.util; + +/** + * Thread local cache in the current tool class. + * + * @author Jiaju Zhuang + **/ +public interface ThreadLocalCachedUtils { + + /** + * Remove remove thread local cached. + */ + void removeThreadLocalCache(); +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatData.java b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatData.java new file mode 100644 index 0000000..d627e46 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.dataformat; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class DateFormatData { + private String date; + private String dateString; + private String number; + private String numberString; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java new file mode 100644 index 0000000..69b6709 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java @@ -0,0 +1,50 @@ +package com.alibaba.easyexcel.test.core.dataformat; + +import java.io.File; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; + +/** + * + * @author Jiaju Zhuang + */ +public class DateFormatTest { + private static final Logger LOGGER = LoggerFactory.getLogger(DateFormatTest.class); + + private static File file07; + private static File file03; + + @BeforeClass + public static void init() { + file07 = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xlsx"); + file03 = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xls"); + } + + @Test + public void t01Read07() { + read(file07); + } + + @Test + public void t02Read03() { + read(file03); + } + + private void read(File file) { + List list = EasyExcel.read(file, DateFormatData.class, null).sheet().doReadSync(); + for (DateFormatData data : list) { + if (!data.getDate().equals(data.getDateString())) { + LOGGER.info("返回:{}", JSON.toJSONString(data)); + } + } + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java index d9c7bb2..d3db5e0 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java @@ -6,10 +6,14 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; +import java.util.Locale; +import java.util.regex.Pattern; +import org.apache.poi.openxml4j.exceptions.InvalidFormatException; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.DataFormatter; import org.apache.poi.ss.usermodel.DateUtil; +import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.junit.Ignore; @@ -17,7 +21,9 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.alibaba.easyexcel.test.core.dataformat.DateFormatData; import com.alibaba.easyexcel.test.temp.Lock2Test; +import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.fastjson.JSON; @@ -124,4 +130,61 @@ public class DataFormatTest { System.out.println("end:" + (System.currentTimeMillis() - start)); } + @Test + public void test355() throws IOException, InvalidFormatException { + File file = TestFileUtil.readFile("dataformat" + File.separator + "dataformat.xlsx"); + XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file); + Sheet xssfSheet = xssfWorkbook.getSheetAt(0); + DataFormatter d = new DataFormatter(Locale.CHINA); + + for (int i = 0; i < xssfSheet.getLastRowNum(); i++) { + Row row = xssfSheet.getRow(i); + System.out.println(d.formatCellValue(row.getCell(0))); + } + + } + + @Test + public void test3556() throws IOException, InvalidFormatException { + String file = "D://test/dataformat.xlsx"; + XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file); + Sheet xssfSheet = xssfWorkbook.getSheetAt(0); + DataFormatter d = new DataFormatter(Locale.CHINA); + + for (int i = 0; i < xssfSheet.getLastRowNum(); i++) { + Row row = xssfSheet.getRow(i); + System.out.println(d.formatCellValue(row.getCell(0))); + } + + } + + @Test + public void tests() throws IOException, InvalidFormatException { + SimpleDateFormat s1 = new SimpleDateFormat("yyyy\"5E74\"m\"6708\"d\"65E5\""); + System.out.println(s1.format(new Date())); + s1 = new SimpleDateFormat("yyyy年m月d日"); + System.out.println(s1.format(new Date())); + } + + @Test + public void tests1() throws IOException, InvalidFormatException { + String file = "D://test/dataformat1.xlsx"; + List list = EasyExcel.read(file, DateFormatData.class, null).sheet().doReadSync(); + for (DateFormatData data : list) { + LOGGER.info("返回:{}", JSON.toJSONString(data)); + } + } + + @Test + public void tests3() throws IOException, InvalidFormatException { + SimpleDateFormat s1 = new SimpleDateFormat("ah\"时\"mm\"分\""); + System.out.println(s1.format(new Date())); + } + + private static final Pattern date_ptrn6 = Pattern.compile("^.*(年|月|日|时|分|秒)+.*$"); + + @Test + public void tests34() throws IOException, InvalidFormatException { + System.out.println(date_ptrn6.matcher("2017但是").matches()); + } } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java index 3a70d0d..68fff70 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java @@ -2,12 +2,8 @@ package com.alibaba.easyexcel.test.temp.poi; import java.io.FileOutputStream; import java.io.IOException; -import java.lang.reflect.Field; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; import java.util.regex.Pattern; -import org.apache.poi.ss.formula.functions.T; import org.apache.poi.xssf.streaming.SXSSFCell; import org.apache.poi.xssf.streaming.SXSSFRow; import org.apache.poi.xssf.streaming.SXSSFSheet; @@ -17,11 +13,8 @@ import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.excel.metadata.CellData; import com.alibaba.fastjson.JSON; -import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; - /** * 测试poi * @@ -99,58 +92,4 @@ public class PoiWriteTest { } - @Test - public void test() throws Exception { - Class clazz = TestCell.class; - - Field field = clazz.getDeclaredField("c2"); - // 通过getDeclaredField可以获得成员变量,但是对于Map来说,仅仅可以知道它是个Map,无法知道键值对各自的数据类型 - - Type gType = field.getGenericType(); - // 获得field的泛型类型 - - // 如果gType是ParameterizedType对象(参数化) - if (gType instanceof ParameterizedType) { - - ParameterizedType pType = (ParameterizedType)gType; - // 就把它转换成ParameterizedType对象 - - Type[] tArgs = pType.getActualTypeArguments(); - // 获得泛型类型的泛型参数(实际类型参数) - ParameterizedTypeImpl c = (ParameterizedTypeImpl)pType.getActualTypeArguments()[0]; - Class ttt = c.getRawType(); - System.out.println(ttt); - } else { - System.out.println("出错!!!"); - } - - } - - @Test - public void test2() throws Exception { - Class clazz = TestCell.class; - - Field field = clazz.getDeclaredField("c2"); - // 通过getDeclaredField可以获得成员变量,但是对于Map来说,仅仅可以知道它是个Map,无法知道键值对各自的数据类型 - - Type gType = field.getGenericType(); - // 获得field的泛型类型 - - // 如果gType是ParameterizedType对象(参数化) - if (gType instanceof ParameterizedType) { - - ParameterizedType pType = (ParameterizedType)gType; - // 就把它转换成ParameterizedType对象 - - Type[] tArgs = pType.getActualTypeArguments(); - // 获得泛型类型的泛型参数(实际类型参数) - ParameterizedTypeImpl c = (ParameterizedTypeImpl)pType.getActualTypeArguments()[0]; - Class ttt = c.getRawType(); - System.out.println(ttt); - } else { - System.out.println("出错!!!"); - } - - } - } diff --git a/src/test/resources/dataformat/dataformat.xlsx b/src/test/resources/dataformat/dataformat.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..370d983a931862faf90274a954ed71e38cb92ac5 GIT binary patch literal 11489 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 literal 0 HcmV?d00001 From 35558838718454cf4784f70288fc90960c07e403 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 24 Dec 2019 20:44:03 +0800 Subject: [PATCH 07/38] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=94=A8String?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E6=97=A5=E6=9C=9F=E3=80=81=E6=95=B0=E5=AD=97?= =?UTF-8?q?=E5=92=8Cexcel=E6=98=BE=E7=A4=BA=E4=B8=8D=E4=B8=80=E8=87=B4?= =?UTF-8?q?=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 4 +- .../excel/analysis/ExcelAnalyserImpl.java | 9 + .../excel/analysis/v03/XlsSaxAnalyser.java | 6 +- .../v03/handlers/NumberRecordHandler.java | 13 +- .../v07/handlers/DefaultCellHandler.java | 8 +- .../excel/constant/BuiltinFormats.java | 193 +++++++++++++++++- .../excel/context/AnalysisContext.java | 1 - .../excel/context/WriteContextImpl.java | 9 + .../byteconverter/ByteNumberConverter.java | 2 +- .../floatconverter/FloatNumberConverter.java | 2 +- .../integer/IntegerNumberConverter.java | 2 +- .../shortconverter/ShortNumberConverter.java | 2 +- .../excel/metadata/AbstractHolder.java | 12 +- .../metadata/AbstractParameterBuilder.java | 93 +++++++++ .../alibaba/excel/metadata/DataFormatter.java | 4 +- .../AbstractExcelReaderParameterBuilder.java | 47 +++++ .../read/builder/ExcelReaderBuilder.java | 103 +--------- .../read/builder/ExcelReaderSheetBuilder.java | 101 +-------- .../com/alibaba/excel/util/DateUtils.java | 5 +- .../excel/util/NumberDataFormatterUtils.java | 5 +- .../excel/util/ThreadLocalCachedUtils.java | 14 -- .../AbstractExcelWriterParameterBuilder.java | 104 ++++++++++ .../write/builder/ExcelWriterBuilder.java | 133 +----------- .../builder/ExcelWriterSheetBuilder.java | 136 +----------- .../builder/ExcelWriterTableBuilder.java | 135 +----------- .../test/core/dataformat/DateFormatData.java | 6 +- .../test/core/dataformat/DateFormatTest.java | 27 ++- .../test/temp/dataformat/DataFormatTest.java | 2 +- .../easyexcel/test/temp/poi/PoiWriteTest.java | 12 ++ .../easyexcel/test/temp/simple/JsonData.java | 15 ++ .../easyexcel/test/temp/simple/Wirte.java | 41 +++- .../easyexcel/test/temp/simple/WriteData.java | 13 ++ src/test/resources/dataformat/dataformat.xls | Bin 0 -> 26112 bytes src/test/resources/dataformat/dataformat.xlsx | Bin 11489 -> 11754 bytes update.md | 6 + 35 files changed, 618 insertions(+), 647 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java create mode 100644 src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java delete mode 100644 src/main/java/com/alibaba/excel/util/ThreadLocalCachedUtils.java create mode 100644 src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/temp/simple/JsonData.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java create mode 100644 src/test/resources/dataformat/dataformat.xls diff --git a/pom.xml b/pom.xml index 7e2235c..5aff423 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ UTF-8 - 1.7 + 1.6 @@ -84,7 +84,7 @@ org.ehcache ehcache - 3.7.1 + 3.4.0 diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index eb4f188..feec16b 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -22,7 +22,9 @@ import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.util.CollectionUtils; +import com.alibaba.excel.util.DateUtils; import com.alibaba.excel.util.FileUtils; +import com.alibaba.excel.util.NumberDataFormatterUtils; import com.alibaba.excel.util.StringUtils; /** @@ -175,11 +177,18 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { clearEncrypt03(); + removeThreadLocalCache(); + if (throwable != null) { throw new ExcelAnalysisException("Can not close IO.", throwable); } } + private void removeThreadLocalCache() { + NumberDataFormatterUtils.removeThreadLocalCache(); + DateUtils.removeThreadLocalCache(); + } + private void clearEncrypt03() { if (StringUtils.isEmpty(analysisContext.readWorkbookHolder().getPassword()) || !ExcelTypeEnum.XLS.equals(analysisContext.readWorkbookHolder().getExcelType())) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index e0c150c..fd73e67 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -3,10 +3,10 @@ package com.alibaba.excel.analysis.v03; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.TreeMap; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; @@ -191,7 +191,7 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { analysisContext.readRowHolder( new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration())); analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext); - records.clear(); + records = new HashMap(); lastColumnNumber = -1; } @@ -208,7 +208,7 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener)); recordHandlers.add(new LabelRecordHandler()); recordHandlers.add(new NoteRecordHandler()); - recordHandlers.add(new NumberRecordHandler(formatListener)); + recordHandlers.add(new NumberRecordHandler(analysisContext, formatListener)); recordHandlers.add(new RkRecordHandler()); recordHandlers.add(new SstRecordHandler()); recordHandlers.add(new MissingCellDummyRecordHandler()); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java index d8f3524..af02488 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -8,6 +8,7 @@ import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import com.alibaba.excel.constant.BuiltinFormats; +import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.metadata.CellData; /** @@ -18,7 +19,10 @@ import com.alibaba.excel.metadata.CellData; public class NumberRecordHandler extends AbstractXlsRecordHandler { private FormatTrackingHSSFListener formatListener; - public NumberRecordHandler(FormatTrackingHSSFListener formatListener) { + private AnalysisContext context; + + public NumberRecordHandler(AnalysisContext context, FormatTrackingHSSFListener formatListener) { + this.context = context; this.formatListener = formatListener; } @@ -35,11 +39,8 @@ public class NumberRecordHandler extends AbstractXlsRecordHandler { this.cellData = new CellData(BigDecimal.valueOf(numrec.getValue())); int dataFormat = formatListener.getFormatIndex(numrec); this.cellData.setDataFormat(dataFormat); - if (dataFormat <= BuiltinFormats.builtinFormats.length) { - this.cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat)); - } else { - this.cellData.setDataFormatString(formatListener.getFormatString(numrec)); - } + this.cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, + formatListener.getFormatString(numrec), context.readSheetHolder().getGlobalConfiguration().getLocale())); } @Override diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java index 7312b2c..3d96a90 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -88,11 +88,9 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(dateFormatIndexInteger); int dataFormat = xssfCellStyle.getDataFormat(); currentCellData.setDataFormat(dataFormat); - if (dataFormat <= BuiltinFormats.builtinFormats.length) { - currentCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat)); - } else { - currentCellData.setDataFormatString(xssfCellStyle.getDataFormatString()); - } + currentCellData.setDataFormatString( + BuiltinFormats.getBuiltinFormat(dataFormat, xssfCellStyle.getDataFormatString(), + analysisContext.readSheetHolder().getGlobalConfiguration().getLocale())); } } // cell is formula diff --git a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java index 5663054..1dec2c6 100644 --- a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java +++ b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java @@ -1,6 +1,6 @@ package com.alibaba.excel.constant; -import com.alibaba.excel.util.StringUtils; +import java.util.Locale; /** * Excel's built-in format conversion.Currently only supports Chinese. @@ -17,7 +17,179 @@ import com.alibaba.excel.util.StringUtils; **/ public class BuiltinFormats { - public static String[] builtinFormats = { + private static final String[] BUILTIN_FORMATS_CN = { + // 0 + "General", + // 1 + "0", + // 2 + "0.00", + // 3 + "#,##0", + // 4 + "#,##0.00", + // 5 + "\"¥\"#,##0_);(\"¥\"#,##0)", + // 6 + "\"¥\"#,##0_);[Red](\"¥\"#,##0)", + // 7 + "\"¥\"#,##0.00_);(\"¥\"#,##0.00)", + // 8 + "\"¥\"#,##0.00_);[Red](\"¥\"#,##0.00)", + // 9 + "0%", + // 10 + "0.00%", + // 11 + "0.00E+00", + // 12 + "# ?/?", + // 13 + "# ??/??", + // 14 + // The official documentation shows "m/d/yy", but the actual test is "yyyy/m/d". + "yyyy/m/d", + // 15 + "d-mmm-yy", + // 16 + "d-mmm", + // 17 + "mmm-yy", + // 18 + "h:mm AM/PM", + // 19 + "h:mm:ss AM/PM", + // 20 + "h:mm", + // 21 + "h:mm:ss", + // 22 + // The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy/m/d h:mm". + "yyyy/m/d h:mm", + // 23-26 No specific correspondence found in the official documentation. + // 23 + null, + // 24 + null, + // 25 + null, + // 26 + null, + // 27 + "yyyy\"年\"m\"月\"", + // 28 + "m\"月\"d\"日\"", + // 29 + "m\"月\"d\"日\"", + // 30 + "m-d-yy", + // 31 + "yyyy\"年\"m\"月\"d\"日\"", + // 32 + "h\"时\"mm\"分\"", + // 33 + "h\"时\"mm\"分\"ss\"秒\"", + // 34 + "上午/下午h\"时\"mm\"分\"", + // 35 + "上午/下午h\"时\"mm\"分\"ss\"秒\"", + // 36 + "yyyy\"年\"m\"月\"", + // 37 + "#,##0_);(#,##0)", + // 38 + "#,##0_);[Red](#,##0)", + // 39 + "#,##0.00_);(#,##0.00)", + // 40 + "#,##0.00_);[Red](#,##0.00)", + // 41 + "_(* #,##0_);_(* (#,##0);_(* \"-\"_);_(@_)", + // 42 + "_(\"¥\"* #,##0_);_(\"¥\"* (#,##0);_(\"¥\"* \"-\"_);_(@_)", + // 43 + "_(* #,##0.00_);_(* (#,##0.00);_(* \"-\"??_);_(@_)", + // 44 + "_(\"¥\"* #,##0.00_);_(\"¥\"* (#,##0.00);_(\"¥\"* \"-\"??_);_(@_)", + // 45 + "mm:ss", + // 46 + "[h]:mm:ss", + // 47 + "mm:ss.0", + // 48 + "##0.0E+0", + // 49 + "@", + // 50 + "yyyy\"年\"m\"月\"", + // 51 + "m\"月\"d\"日\"", + // 52 + "yyyy\"年\"m\"月\"", + // 53 + "m\"月\"d\"日\"", + // 54 + "m\"月\"d\"日\"", + // 55 + "上午/下午h\"时\"mm\"分\"", + // 56 + "上午/下午h\"时\"mm\"分\"ss\"秒\"", + // 57 + "yyyy\"年\"m\"月\"", + // 58 + "m\"月\"d\"日\"", + // 59 + "t0", + // 60 + "t0.00", + // 61 + "t#,##0", + // 62 + "t#,##0.00", + // 63-66 No specific correspondence found in the official documentation. + // 63 + null, + // 64 + null, + // 65 + null, + // 66 + null, + // 67 + "t0%", + // 68 + "t0.00%", + // 69 + "t# ?/?", + // 70 + "t# ??/??", + // 71 + "ว/ด/ปปปป", + // 72 + "ว-ดดด-ปป", + // 73 + "ว-ดดด", + // 74 + "ดดด-ปป", + // 75 + "ช:นน", + // 76 + "ช:นน:ทท", + // 77 + "ว/ด/ปปปป ช:นน", + // 78 + "นน:ทท", + // 79 + "[ช]:นน:ทท", + // 80 + "นน:ทท.0", + // 81 + "d/m/bb", + // end + }; + + private static final String[] BUILTIN_FORMATS_US = { // 0 "General", // 1 @@ -189,18 +361,19 @@ public class BuiltinFormats { // end }; - public static String getBuiltinFormat(Integer index) { - if (index == null || index < 0 || index >= builtinFormats.length) { - return null; + public static String getBuiltinFormat(Integer index, String defaultFormat, Locale locale) { + String[] builtinFormat = switchBuiltinFormats(locale); + if (index == null || index < 0 || index >= builtinFormat.length) { + return defaultFormat; } - return builtinFormats[index]; + return builtinFormat[index]; } - public static String getFormat(Integer index, String format) { - if (!StringUtils.isEmpty(format)) { - return format; + private static String[] switchBuiltinFormats(Locale locale) { + if (locale != null && Locale.US.getCountry().equals(locale.getCountry())) { + return BUILTIN_FORMATS_US; } - return getBuiltinFormat(index); + return BUILTIN_FORMATS_CN; } } diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java index f44c2b3..66c69a5 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContext.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -2,7 +2,6 @@ package com.alibaba.excel.context; import java.io.InputStream; -import com.alibaba.excel.analysis.ExcelReadExecutor; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; import com.alibaba.excel.read.metadata.ReadSheet; diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index 0935868..7b9bb81 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -27,7 +27,9 @@ import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.support.ExcelTypeEnum; +import com.alibaba.excel.util.DateUtils; import com.alibaba.excel.util.FileUtils; +import com.alibaba.excel.util.NumberDataFormatterUtils; import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.WorkBookUtil; import com.alibaba.excel.util.WriteHandlerUtils; @@ -327,6 +329,8 @@ public class WriteContextImpl implements WriteContext { clearEncrypt03(); + removeThreadLocalCache(); + if (throwable != null) { throw new ExcelGenerateException("Can not close IO.", throwable); } @@ -336,6 +340,11 @@ public class WriteContextImpl implements WriteContext { } } + private void removeThreadLocalCache() { + NumberDataFormatterUtils.removeThreadLocalCache(); + DateUtils.removeThreadLocalCache(); + } + @Override public Sheet getCurrentSheet() { return writeSheetHolder.getSheet(); diff --git a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java index 8c16a77..f1facdf 100644 --- a/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/byteconverter/ByteNumberConverter.java @@ -34,7 +34,7 @@ public class ByteNumberConverter implements Converter { @Override public CellData convertToExcelData(Byte value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(BigDecimal.valueOf(value)); + return new CellData(new BigDecimal(Byte.toString(value))); } } diff --git a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java index a1b6471..69cc22e 100644 --- a/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/floatconverter/FloatNumberConverter.java @@ -34,7 +34,7 @@ public class FloatNumberConverter implements Converter { @Override public CellData convertToExcelData(Float value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(BigDecimal.valueOf(value)); + return new CellData(new BigDecimal(Float.toString(value))); } } diff --git a/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java b/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java index 3b0deac..117d4c1 100644 --- a/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/integer/IntegerNumberConverter.java @@ -34,7 +34,7 @@ public class IntegerNumberConverter implements Converter { @Override public CellData convertToExcelData(Integer value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(BigDecimal.valueOf(value)); + return new CellData(new BigDecimal(Integer.toString(value))); } } diff --git a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java index 7d1d7da..357c6ae 100644 --- a/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java +++ b/src/main/java/com/alibaba/excel/converters/shortconverter/ShortNumberConverter.java @@ -34,7 +34,7 @@ public class ShortNumberConverter implements Converter { @Override public CellData convertToExcelData(Short value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) { - return new CellData(BigDecimal.valueOf(value)); + return new CellData(new BigDecimal(Short.toString(value))); } } diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java b/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java index 37a1942..6bfd825 100644 --- a/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java +++ b/src/main/java/com/alibaba/excel/metadata/AbstractHolder.java @@ -1,6 +1,7 @@ package com.alibaba.excel.metadata; import java.util.List; +import java.util.Locale; import java.util.Map; import com.alibaba.excel.converters.Converter; @@ -27,7 +28,6 @@ public abstract class AbstractHolder implements ConfigurationHolder { * Some global variables */ private GlobalConfiguration globalConfiguration; - /** *

* Read key: @@ -58,6 +58,16 @@ public abstract class AbstractHolder implements ConfigurationHolder { } else { globalConfiguration.setAutoTrim(basicParameter.getAutoTrim()); } + + if (basicParameter.getLocale() == null) { + if (prentAbstractHolder == null) { + globalConfiguration.setLocale(Locale.getDefault()); + } else { + globalConfiguration.setLocale(prentAbstractHolder.getGlobalConfiguration().getLocale()); + } + } else { + globalConfiguration.setLocale(basicParameter.getLocale()); + } } public Boolean getNewInitialization() { diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java b/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java new file mode 100644 index 0000000..5840046 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java @@ -0,0 +1,93 @@ +package com.alibaba.excel.metadata; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +import com.alibaba.excel.converters.Converter; + +/** + * ExcelBuilder + * + * @author Jiaju Zhuang + */ +public abstract class AbstractParameterBuilder { + /** + * You can only choose one of the {@link #head(List)} and {@link #head(Class)} + * + * @param head + * @return + */ + public T head(List> head) { + parameter().setHead(head); + return self(); + } + + /** + * You can only choose one of the {@link #head(List)} and {@link #head(Class)} + * + * @param clazz + * @return + */ + public T head(Class clazz) { + parameter().setClazz(clazz); + return self(); + } + + /** + * Custom type conversions override the default. + * + * @param converter + * @return + */ + public T registerConverter(Converter converter) { + if (parameter().getCustomConverterList() == null) { + parameter().setCustomConverterList(new ArrayList()); + } + parameter().getCustomConverterList().add(converter); + return self(); + } + + /** + * true if date uses 1904 windowing, or false if using 1900 date windowing. + * + * default is false + * + * @param use1904windowing + * @return + */ + public T use1904windowing(Boolean use1904windowing) { + parameter().setUse1904windowing(use1904windowing); + return self(); + } + + /** + * A Locale object represents a specific geographical, political, or cultural region. This parameter is + * used when formatting dates and numbers. + * + * @param locale + * @return + */ + public T locale(Locale locale) { + parameter().setLocale(locale); + return self(); + } + + /** + * Automatic trim includes sheet name and content + * + * @param autoTrim + * @return + */ + public T autoTrim(Boolean autoTrim) { + parameter().setAutoTrim(autoTrim); + return self(); + } + + @SuppressWarnings("unchecked") + protected T self() { + return (T)this; + } + + protected abstract C parameter(); +} diff --git a/src/main/java/com/alibaba/excel/metadata/DataFormatter.java b/src/main/java/com/alibaba/excel/metadata/DataFormatter.java index 13bd162..7467cd2 100644 --- a/src/main/java/com/alibaba/excel/metadata/DataFormatter.java +++ b/src/main/java/com/alibaba/excel/metadata/DataFormatter.java @@ -63,7 +63,8 @@ public class DataFormatter { private static final Pattern daysAsText = Pattern.compile("([d]{3,})", Pattern.CASE_INSENSITIVE); /** Pattern to find "AM/PM" marker */ - private static final Pattern amPmPattern = Pattern.compile("(([AP])[M/P]*)|(([上下])[午/下]*)", Pattern.CASE_INSENSITIVE); + private static final Pattern amPmPattern = + Pattern.compile("(([AP])[M/P]*)|(([上下])[午/下]*)", Pattern.CASE_INSENSITIVE); /** Pattern to find formats with condition ranges e.g. [>=100] */ private static final Pattern rangeConditionalPattern = @@ -152,7 +153,6 @@ public class DataFormatter { public DataFormatter(Locale locale, Boolean use1904windowing) { this.use1904windowing = use1904windowing != null ? use1904windowing : Boolean.FALSE; this.locale = locale != null ? locale : Locale.getDefault(); - this.locale = Locale.US; this.dateSymbols = DateFormatSymbols.getInstance(this.locale); this.decimalSymbols = DecimalFormatSymbols.getInstance(this.locale); } diff --git a/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java b/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java new file mode 100644 index 0000000..4e5e370 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/builder/AbstractExcelReaderParameterBuilder.java @@ -0,0 +1,47 @@ +package com.alibaba.excel.read.builder; + +import java.util.ArrayList; + +import com.alibaba.excel.metadata.AbstractParameterBuilder; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.ReadBasicParameter; + +/** + * Build ExcelBuilder + * + * @author Jiaju Zhuang + */ +public abstract class AbstractExcelReaderParameterBuilder extends AbstractParameterBuilder { + /** + * Count the number of added heads when read sheet. + * + *

+ * 0 - This Sheet has no head ,since the first row are the data + *

+ * 1 - This Sheet has one row head , this is the default + *

+ * 2 - This Sheet has two row head ,since the third row is the data + * + * @param headRowNumber + * @return + */ + public T headRowNumber(Integer headRowNumber) { + parameter().setHeadRowNumber(headRowNumber); + return self(); + } + + /** + * Custom type listener run after default + * + * @param readListener + * @return + */ + public T registerReadListener(ReadListener readListener) { + if (parameter().getCustomReadListenerList() == null) { + parameter().setCustomReadListenerList(new ArrayList()); + } + parameter().getCustomReadListenerList().add(readListener); + return self(); + } +} diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java index 4f6cdda..1bdfd6d 100644 --- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java +++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java @@ -2,8 +2,6 @@ package com.alibaba.excel.read.builder; import java.io.File; import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; import javax.xml.parsers.SAXParserFactory; @@ -11,9 +9,7 @@ import com.alibaba.excel.ExcelReader; import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.converters.Converter; import com.alibaba.excel.event.AnalysisEventListener; -import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.support.ExcelTypeEnum; @@ -22,7 +18,7 @@ import com.alibaba.excel.support.ExcelTypeEnum; * * @author Jiaju Zhuang */ -public class ExcelReaderBuilder { +public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder { /** * Workbook */ @@ -132,98 +128,6 @@ public class ExcelReaderBuilder { return this; } - /** - * Count the number of added heads when read sheet. - * - *

- * 0 - This Sheet has no head ,since the first row are the data - *

- * 1 - This Sheet has one row head , this is the default - *

- * 2 - This Sheet has two row head ,since the third row is the data - * - * @param headRowNumber - * @return - */ - public ExcelReaderBuilder headRowNumber(Integer headRowNumber) { - readWorkbook.setHeadRowNumber(headRowNumber); - return this; - } - - /** - * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)} - * - * @param head - * @return - */ - public ExcelReaderBuilder head(List> head) { - readWorkbook.setHead(head); - return this; - } - - /** - * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)} - * - * @param clazz - * @return - */ - public ExcelReaderBuilder head(Class clazz) { - readWorkbook.setClazz(clazz); - return this; - } - - /** - * Custom type conversions override the default. - * - * @param converter - * @return - */ - public ExcelReaderBuilder registerConverter(Converter converter) { - if (readWorkbook.getCustomConverterList() == null) { - readWorkbook.setCustomConverterList(new ArrayList()); - } - readWorkbook.getCustomConverterList().add(converter); - return this; - } - - /** - * Custom type listener run after default - * - * @param readListener - * @return - */ - public ExcelReaderBuilder registerReadListener(ReadListener readListener) { - if (readWorkbook.getCustomReadListenerList() == null) { - readWorkbook.setCustomReadListenerList(new ArrayList()); - } - readWorkbook.getCustomReadListenerList().add(readListener); - return this; - } - - /** - * true if date uses 1904 windowing, or false if using 1900 date windowing. - * - * default is false - * - * @param use1904windowing - * @return - */ - public ExcelReaderBuilder use1904windowing(Boolean use1904windowing) { - readWorkbook.setUse1904windowing(use1904windowing); - return this; - } - - /** - * Automatic trim includes sheet name and content - * - * @param autoTrim - * @return - */ - public ExcelReaderBuilder autoTrim(Boolean autoTrim) { - readWorkbook.setAutoTrim(autoTrim); - return this; - } - /** * Whether the encryption * @@ -285,4 +189,9 @@ public class ExcelReaderBuilder { } return excelReaderSheetBuilder; } + + @Override + protected ReadWorkbook parameter() { + return readWorkbook; + } } diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java index d494e23..84ec6ba 100644 --- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java +++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderSheetBuilder.java @@ -1,14 +1,11 @@ package com.alibaba.excel.read.builder; -import java.util.ArrayList; import java.util.List; import com.alibaba.excel.ExcelReader; -import com.alibaba.excel.converters.Converter; import com.alibaba.excel.event.SyncReadListener; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelGenerateException; -import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.metadata.ReadSheet; /** @@ -16,7 +13,7 @@ import com.alibaba.excel.read.metadata.ReadSheet; * * @author Jiaju Zhuang */ -public class ExcelReaderSheetBuilder { +public class ExcelReaderSheetBuilder extends AbstractExcelReaderParameterBuilder { private ExcelReader excelReader; /** * Sheet @@ -54,98 +51,6 @@ public class ExcelReaderSheetBuilder { return this; } - /** - * Count the number of added heads when read sheet. - * - *

- * 0 - This Sheet has no head ,since the first row are the data - *

- * 1 - This Sheet has one row head , this is the default - *

- * 2 - This Sheet has two row head ,since the third row is the data - * - * @param headRowNumber - * @return - */ - public ExcelReaderSheetBuilder headRowNumber(Integer headRowNumber) { - readSheet.setHeadRowNumber(headRowNumber); - return this; - } - - /** - * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)} - * - * @param head - * @return - */ - public ExcelReaderSheetBuilder head(List> head) { - readSheet.setHead(head); - return this; - } - - /** - * You can only choose one of the {@link ExcelReaderBuilder#head(List)} and {@link ExcelReaderBuilder#head(Class)} - * - * @param clazz - * @return - */ - public ExcelReaderSheetBuilder head(Class clazz) { - readSheet.setClazz(clazz); - return this; - } - - /** - * Custom type conversions override the default. - * - * @param converter - * @return - */ - public ExcelReaderSheetBuilder registerConverter(Converter converter) { - if (readSheet.getCustomConverterList() == null) { - readSheet.setCustomConverterList(new ArrayList()); - } - readSheet.getCustomConverterList().add(converter); - return this; - } - - /** - * Custom type listener run after default - * - * @param readListener - * @return - */ - public ExcelReaderSheetBuilder registerReadListener(ReadListener readListener) { - if (readSheet.getCustomReadListenerList() == null) { - readSheet.setCustomReadListenerList(new ArrayList()); - } - readSheet.getCustomReadListenerList().add(readListener); - return this; - } - - /** - * true if date uses 1904 windowing, or false if using 1900 date windowing. - * - * default is false - * - * @param use1904windowing - * @return - */ - public ExcelReaderSheetBuilder use1904windowing(Boolean use1904windowing) { - readSheet.setUse1904windowing(use1904windowing); - return this; - } - - /** - * Automatic trim includes sheet name and content - * - * @param autoTrim - * @return - */ - public ExcelReaderSheetBuilder autoTrim(Boolean autoTrim) { - readSheet.setAutoTrim(autoTrim); - return this; - } - public ReadSheet build() { return readSheet; } @@ -177,4 +82,8 @@ public class ExcelReaderSheetBuilder { return (List)syncReadListener.getList(); } + @Override + protected ReadSheet parameter() { + return readSheet; + } } diff --git a/src/main/java/com/alibaba/excel/util/DateUtils.java b/src/main/java/com/alibaba/excel/util/DateUtils.java index b375733..815257b 100644 --- a/src/main/java/com/alibaba/excel/util/DateUtils.java +++ b/src/main/java/com/alibaba/excel/util/DateUtils.java @@ -13,7 +13,7 @@ import java.util.regex.Pattern; * * @author Jiaju Zhuang **/ -public class DateUtils implements ThreadLocalCachedUtils { +public class DateUtils { /** * Is a cache of dates */ @@ -302,8 +302,7 @@ public class DateUtils implements ThreadLocalCachedUtils { return false; } - @Override - public void removeThreadLocalCache() { + public static void removeThreadLocalCache() { DATE_THREAD_LOCAL.remove(); DATE_FORMAT_THREAD_LOCAL.remove(); } diff --git a/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java b/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java index 52ced2a..5bceb4a 100644 --- a/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java +++ b/src/main/java/com/alibaba/excel/util/NumberDataFormatterUtils.java @@ -8,7 +8,7 @@ import com.alibaba.excel.metadata.GlobalConfiguration; * * @author Jiaju Zhuang **/ -public class NumberDataFormatterUtils implements ThreadLocalCachedUtils { +public class NumberDataFormatterUtils { /** * Cache DataFormatter. */ @@ -40,8 +40,7 @@ public class NumberDataFormatterUtils implements ThreadLocalCachedUtils { } - @Override - public void removeThreadLocalCache() { + public static void removeThreadLocalCache() { DATA_FORMATTER_THREAD_LOCAL.remove(); } } diff --git a/src/main/java/com/alibaba/excel/util/ThreadLocalCachedUtils.java b/src/main/java/com/alibaba/excel/util/ThreadLocalCachedUtils.java deleted file mode 100644 index d136703..0000000 --- a/src/main/java/com/alibaba/excel/util/ThreadLocalCachedUtils.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.alibaba.excel.util; - -/** - * Thread local cache in the current tool class. - * - * @author Jiaju Zhuang - **/ -public interface ThreadLocalCachedUtils { - - /** - * Remove remove thread local cached. - */ - void removeThreadLocalCache(); -} diff --git a/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java b/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java new file mode 100644 index 0000000..d44c0ad --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/builder/AbstractExcelWriterParameterBuilder.java @@ -0,0 +1,104 @@ +package com.alibaba.excel.write.builder; + +import java.util.ArrayList; +import java.util.Collection; + +import com.alibaba.excel.metadata.AbstractParameterBuilder; +import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.metadata.WriteBasicParameter; + +/** + * Build ExcelBuilder + * + * @author Jiaju Zhuang + */ +public abstract class AbstractExcelWriterParameterBuilder extends AbstractParameterBuilder { + /** + * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. + * + * @param relativeHeadRowIndex + * @return + */ + public T relativeHeadRowIndex(Integer relativeHeadRowIndex) { + parameter().setRelativeHeadRowIndex(relativeHeadRowIndex); + return self(); + } + + /** + * Need Head + */ + public T needHead(Boolean needHead) { + parameter().setNeedHead(needHead); + return self(); + } + + /** + * Custom write handler + * + * @param writeHandler + * @return + */ + public T registerWriteHandler(WriteHandler writeHandler) { + if (parameter().getCustomWriteHandlerList() == null) { + parameter().setCustomWriteHandlerList(new ArrayList()); + } + parameter().getCustomWriteHandlerList().add(writeHandler); + return self(); + } + + /** + * Use the default style.Default is true. + * + * @param useDefaultStyle + * @return + */ + public T useDefaultStyle(Boolean useDefaultStyle) { + parameter().setUseDefaultStyle(useDefaultStyle); + return self(); + } + + /** + * Whether to automatically merge headers.Default is true. + * + * @param automaticMergeHead + * @return + */ + public T automaticMergeHead(Boolean automaticMergeHead) { + parameter().setAutomaticMergeHead(automaticMergeHead); + return self(); + } + + /** + * Ignore the custom columns. + */ + public T excludeColumnIndexes(Collection excludeColumnIndexes) { + parameter().setExcludeColumnIndexes(excludeColumnIndexes); + return self(); + } + + /** + * Ignore the custom columns. + */ + public T excludeColumnFiledNames(Collection excludeColumnFiledNames) { + parameter().setExcludeColumnFiledNames(excludeColumnFiledNames); + return self(); + } + + /** + * Only output the custom columns. + */ + public T includeColumnIndexes(Collection includeColumnIndexes) { + parameter().setIncludeColumnIndexes(includeColumnIndexes); + return self(); + } + + /** + * Only output the custom columns. + */ + public T includeColumnFiledNames(Collection includeColumnFiledNames) { + parameter().setIncludeColumnFiledNames(includeColumnFiledNames); + return self(); + } + +} diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java index c1f2d94..12c2f22 100644 --- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterBuilder.java @@ -3,12 +3,8 @@ package com.alibaba.excel.write.builder; import java.io.File; import java.io.InputStream; import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.converters.Converter; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.write.handler.WriteHandler; import com.alibaba.excel.write.metadata.WriteWorkbook; @@ -18,7 +14,7 @@ import com.alibaba.excel.write.metadata.WriteWorkbook; * * @author Jiaju Zhuang */ -public class ExcelWriterBuilder { +public class ExcelWriterBuilder extends AbstractExcelWriterParameterBuilder { /** * Workbook */ @@ -28,47 +24,6 @@ public class ExcelWriterBuilder { this.writeWorkbook = new WriteWorkbook(); } - /** - * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. - * - * @param relativeHeadRowIndex - * @return - */ - public ExcelWriterBuilder relativeHeadRowIndex(Integer relativeHeadRowIndex) { - writeWorkbook.setRelativeHeadRowIndex(relativeHeadRowIndex); - return this; - } - - /** - * You can only choose one of the {@link ExcelWriterBuilder#head(List)} and {@link ExcelWriterBuilder#head(Class)} - * - * @param head - * @return - */ - public ExcelWriterBuilder head(List> head) { - writeWorkbook.setHead(head); - return this; - } - - /** - * You can only choose one of the {@link ExcelWriterBuilder#head(List)} and {@link ExcelWriterBuilder#head(Class)} - * - * @param clazz - * @return - */ - public ExcelWriterBuilder head(Class clazz) { - writeWorkbook.setClazz(clazz); - return this; - } - - /** - * Need Head - */ - public ExcelWriterBuilder needHead(Boolean needHead) { - writeWorkbook.setNeedHead(needHead); - return this; - } - /** * Default true * @@ -80,28 +35,6 @@ public class ExcelWriterBuilder { return this; } - /** - * Use the default style.Default is true. - * - * @param useDefaultStyle - * @return - */ - public ExcelWriterBuilder useDefaultStyle(Boolean useDefaultStyle) { - writeWorkbook.setUseDefaultStyle(useDefaultStyle); - return this; - } - - /** - * Whether to automatically merge headers.Default is true. - * - * @param automaticMergeHead - * @return - */ - public ExcelWriterBuilder automaticMergeHead(Boolean automaticMergeHead) { - writeWorkbook.setAutomaticMergeHead(automaticMergeHead); - return this; - } - /** * Whether the encryption. *

@@ -125,38 +58,6 @@ public class ExcelWriterBuilder { return this; } - /** - * Ignore the custom columns. - */ - public ExcelWriterBuilder excludeColumnIndexes(Collection excludeColumnIndexes) { - writeWorkbook.setExcludeColumnIndexes(excludeColumnIndexes); - return this; - } - - /** - * Ignore the custom columns. - */ - public ExcelWriterBuilder excludeColumnFiledNames(Collection excludeColumnFiledNames) { - writeWorkbook.setExcludeColumnFiledNames(excludeColumnFiledNames); - return this; - } - - /** - * Only output the custom columns. - */ - public ExcelWriterBuilder includeColumnIndexes(Collection includeColumnIndexes) { - writeWorkbook.setIncludeColumnIndexes(includeColumnIndexes); - return this; - } - - /** - * Only output the custom columns. - */ - public ExcelWriterBuilder includeColumnFiledNames(Collection includeColumnFiledNames) { - writeWorkbook.setIncludeColumnFiledNames(includeColumnFiledNames); - return this; - } - /** * Excel is also written in the event of an exception being thrown.The default false. */ @@ -181,34 +82,6 @@ public class ExcelWriterBuilder { return this; } - /** - * Custom type conversions override the default. - * - * @param converter - * @return - */ - public ExcelWriterBuilder registerConverter(Converter converter) { - if (writeWorkbook.getCustomConverterList() == null) { - writeWorkbook.setCustomConverterList(new ArrayList()); - } - writeWorkbook.getCustomConverterList().add(converter); - return this; - } - - /** - * Custom write handler - * - * @param writeHandler - * @return - */ - public ExcelWriterBuilder registerWriteHandler(WriteHandler writeHandler) { - if (writeWorkbook.getCustomWriteHandlerList() == null) { - writeWorkbook.setCustomWriteHandlerList(new ArrayList()); - } - writeWorkbook.getCustomWriteHandlerList().add(writeHandler); - return this; - } - public ExcelWriterBuilder excelType(ExcelTypeEnum excelType) { writeWorkbook.setExcelType(excelType); return this; @@ -281,4 +154,8 @@ public class ExcelWriterBuilder { return excelWriterSheetBuilder; } + @Override + protected WriteWorkbook parameter() { + return writeWorkbook; + } } diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java index 5cb71cc..f79b771 100644 --- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterSheetBuilder.java @@ -1,13 +1,9 @@ package com.alibaba.excel.write.builder; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.converters.Converter; import com.alibaba.excel.exception.ExcelGenerateException; -import com.alibaba.excel.write.handler.WriteHandler; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.fill.FillConfig; @@ -16,7 +12,7 @@ import com.alibaba.excel.write.metadata.fill.FillConfig; * * @author Jiaju Zhuang */ -public class ExcelWriterSheetBuilder { +public class ExcelWriterSheetBuilder extends AbstractExcelWriterParameterBuilder { private ExcelWriter excelWriter; /** * Sheet @@ -32,99 +28,6 @@ public class ExcelWriterSheetBuilder { this.excelWriter = excelWriter; } - /** - * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. - * - * @param relativeHeadRowIndex - * @return - */ - public ExcelWriterSheetBuilder relativeHeadRowIndex(Integer relativeHeadRowIndex) { - writeSheet.setRelativeHeadRowIndex(relativeHeadRowIndex); - return this; - } - - /** - * You can only choose one of the {@link ExcelWriterSheetBuilder#head(List)} and - * {@link ExcelWriterSheetBuilder#head(Class)} - * - * @param head - * @return - */ - public ExcelWriterSheetBuilder head(List> head) { - writeSheet.setHead(head); - return this; - } - - /** - * You can only choose one of the {@link ExcelWriterSheetBuilder#head(List)} and - * {@link ExcelWriterSheetBuilder#head(Class)} - * - * @param clazz - * @return - */ - public ExcelWriterSheetBuilder head(Class clazz) { - writeSheet.setClazz(clazz); - return this; - } - - /** - * Need Head - */ - public ExcelWriterSheetBuilder needHead(Boolean needHead) { - writeSheet.setNeedHead(needHead); - return this; - } - - /** - * Use the default style.Default is true. - * - * @param useDefaultStyle - * @return - */ - public ExcelWriterSheetBuilder useDefaultStyle(Boolean useDefaultStyle) { - writeSheet.setUseDefaultStyle(useDefaultStyle); - return this; - } - - /** - * Whether to automatically merge headers.Default is true. - * - * @param automaticMergeHead - * @return - */ - public ExcelWriterSheetBuilder automaticMergeHead(Boolean automaticMergeHead) { - writeSheet.setAutomaticMergeHead(automaticMergeHead); - return this; - } - - /** - * Custom type conversions override the default. - * - * @param converter - * @return - */ - public ExcelWriterSheetBuilder registerConverter(Converter converter) { - if (writeSheet.getCustomConverterList() == null) { - writeSheet.setCustomConverterList(new ArrayList()); - } - writeSheet.getCustomConverterList().add(converter); - return this; - } - - /** - * Custom write handler - * - * @param writeHandler - * @return - */ - public ExcelWriterSheetBuilder registerWriteHandler(WriteHandler writeHandler) { - if (writeSheet.getCustomWriteHandlerList() == null) { - writeSheet.setCustomWriteHandlerList(new ArrayList()); - } - writeSheet.getCustomWriteHandlerList().add(writeHandler); - return this; - } - /** * Starting from 0 * @@ -147,38 +50,6 @@ public class ExcelWriterSheetBuilder { return this; } - /** - * Ignore the custom columns. - */ - public ExcelWriterSheetBuilder excludeColumnIndexes(Collection excludeColumnIndexes) { - writeSheet.setExcludeColumnIndexes(excludeColumnIndexes); - return this; - } - - /** - * Ignore the custom columns. - */ - public ExcelWriterSheetBuilder excludeColumnFiledNames(Collection excludeColumnFiledNames) { - writeSheet.setExcludeColumnFiledNames(excludeColumnFiledNames); - return this; - } - - /** - * Only output the custom columns. - */ - public ExcelWriterSheetBuilder includeColumnIndexes(Collection includeColumnIndexes) { - writeSheet.setIncludeColumnIndexes(includeColumnIndexes); - return this; - } - - /** - * Only output the custom columns. - */ - public ExcelWriterSheetBuilder includeColumnFiledNames(Collection includeColumnFiledNames) { - writeSheet.setIncludeColumnFiledNames(includeColumnFiledNames); - return this; - } - public WriteSheet build() { return writeSheet; } @@ -215,4 +86,9 @@ public class ExcelWriterSheetBuilder { return excelWriterTableBuilder; } + @Override + protected WriteSheet parameter() { + return writeSheet; + } + } diff --git a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java index 2b461a9..077361a 100644 --- a/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java +++ b/src/main/java/com/alibaba/excel/write/builder/ExcelWriterTableBuilder.java @@ -1,13 +1,9 @@ package com.alibaba.excel.write.builder; -import java.util.ArrayList; -import java.util.Collection; import java.util.List; import com.alibaba.excel.ExcelWriter; -import com.alibaba.excel.converters.Converter; import com.alibaba.excel.exception.ExcelGenerateException; -import com.alibaba.excel.write.handler.WriteHandler; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteTable; @@ -16,7 +12,7 @@ import com.alibaba.excel.write.metadata.WriteTable; * * @author Jiaju Zhuang */ -public class ExcelWriterTableBuilder { +public class ExcelWriterTableBuilder extends AbstractExcelWriterParameterBuilder { private ExcelWriter excelWriter; @@ -36,99 +32,6 @@ public class ExcelWriterTableBuilder { this.writeTable = new WriteTable(); } - /** - * Writes the head relative to the existing contents of the sheet. Indexes are zero-based. - * - * @param relativeHeadRowIndex - * @return - */ - public ExcelWriterTableBuilder relativeHeadRowIndex(Integer relativeHeadRowIndex) { - writeTable.setRelativeHeadRowIndex(relativeHeadRowIndex); - return this; - } - - /** - * You can only choose one of the {@link ExcelWriterTableBuilder#head(List)} and - * {@link ExcelWriterTableBuilder#head(Class)} - * - * @param head - * @return - */ - public ExcelWriterTableBuilder head(List> head) { - writeTable.setHead(head); - return this; - } - - /** - * You can only choose one of the {@link ExcelWriterTableBuilder#head(List)} and - * {@link ExcelWriterTableBuilder#head(Class)} - * - * @param clazz - * @return - */ - public ExcelWriterTableBuilder head(Class clazz) { - writeTable.setClazz(clazz); - return this; - } - - /** - * Need Head - */ - public ExcelWriterTableBuilder needHead(Boolean needHead) { - writeTable.setNeedHead(needHead); - return this; - } - - /** - * Use the default style.Default is true. - * - * @param useDefaultStyle - * @return - */ - public ExcelWriterTableBuilder useDefaultStyle(Boolean useDefaultStyle) { - writeTable.setUseDefaultStyle(useDefaultStyle); - return this; - } - - /** - * Whether to automatically merge headers.Default is true. - * - * @param automaticMergeHead - * @return - */ - public ExcelWriterTableBuilder automaticMergeHead(Boolean automaticMergeHead) { - writeTable.setAutomaticMergeHead(automaticMergeHead); - return this; - } - - /** - * Custom type conversions override the default. - * - * @param converter - * @return - */ - public ExcelWriterTableBuilder registerConverter(Converter converter) { - if (writeTable.getCustomConverterList() == null) { - writeTable.setCustomConverterList(new ArrayList()); - } - writeTable.getCustomConverterList().add(converter); - return this; - } - - /** - * Custom write handler - * - * @param writeHandler - * @return - */ - public ExcelWriterTableBuilder registerWriteHandler(WriteHandler writeHandler) { - if (writeTable.getCustomWriteHandlerList() == null) { - writeTable.setCustomWriteHandlerList(new ArrayList()); - } - writeTable.getCustomWriteHandlerList().add(writeHandler); - return this; - } - /** * Starting from 0 * @@ -140,38 +43,6 @@ public class ExcelWriterTableBuilder { return this; } - /** - * Ignore the custom columns. - */ - public ExcelWriterTableBuilder excludeColumnIndexes(Collection excludeColumnIndexes) { - writeTable.setExcludeColumnIndexes(excludeColumnIndexes); - return this; - } - - /** - * Ignore the custom columns. - */ - public ExcelWriterTableBuilder excludeColumnFiledNames(Collection excludeColumnFiledNames) { - writeTable.setExcludeColumnFiledNames(excludeColumnFiledNames); - return this; - } - - /** - * Only output the custom columns. - */ - public ExcelWriterTableBuilder includeColumnIndexes(Collection includeColumnIndexes) { - writeTable.setIncludeColumnIndexes(includeColumnIndexes); - return this; - } - - /** - * Only output the custom columns. - */ - public ExcelWriterTableBuilder includeColumnFiledNames(Collection includeColumnFiledNames) { - writeSheet.setIncludeColumnFiledNames(includeColumnFiledNames); - return this; - } - public WriteTable build() { return writeTable; } @@ -184,4 +55,8 @@ public class ExcelWriterTableBuilder { excelWriter.finish(); } + @Override + protected WriteTable parameter() { + return writeTable; + } } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatData.java b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatData.java index d627e46..1930bce 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatData.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatData.java @@ -8,7 +8,9 @@ import lombok.Data; @Data public class DateFormatData { private String date; - private String dateString; + private String dateStringCn; + private String dateStringUs; private String number; - private String numberString; + private String numberStringCn; + private String numberStringUs; } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java index 69b6709..477652b 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java @@ -2,7 +2,9 @@ package com.alibaba.easyexcel.test.core.dataformat; import java.io.File; import java.util.List; +import java.util.Locale; +import org.junit.Assert; import org.junit.BeforeClass; import org.junit.Test; import org.slf4j.Logger; @@ -10,7 +12,6 @@ import org.slf4j.LoggerFactory; import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; -import com.alibaba.fastjson.JSON; /** * @@ -30,21 +31,31 @@ public class DateFormatTest { @Test public void t01Read07() { - read(file07); + readCn(file07); + readUs(file07); } @Test public void t02Read03() { - read(file03); + readCn(file03); + readUs(file03); } - private void read(File file) { - List list = EasyExcel.read(file, DateFormatData.class, null).sheet().doReadSync(); + private void readCn(File file) { + List list = + EasyExcel.read(file, DateFormatData.class, null).locale(Locale.CHINA).sheet().doReadSync(); for (DateFormatData data : list) { - if (!data.getDate().equals(data.getDateString())) { - LOGGER.info("返回:{}", JSON.toJSONString(data)); - } + Assert.assertEquals(data.getDate(), data.getDateStringCn()); + Assert.assertEquals(data.getNumber(), data.getNumberStringCn()); } } + private void readUs(File file) { + List list = + EasyExcel.read(file, DateFormatData.class, null).locale(Locale.US).sheet().doReadSync(); + for (DateFormatData data : list) { + Assert.assertEquals(data.getDate(), data.getDateStringUs()); + Assert.assertEquals(data.getNumber(), data.getNumberStringUs()); + } + } } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java index d3db5e0..e165d98 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/dataformat/DataFormatTest.java @@ -146,7 +146,7 @@ public class DataFormatTest { @Test public void test3556() throws IOException, InvalidFormatException { - String file = "D://test/dataformat.xlsx"; + String file = "D://test/dataformat1.xlsx"; XSSFWorkbook xssfWorkbook = new XSSFWorkbook(file); Sheet xssfSheet = xssfWorkbook.getSheetAt(0); DataFormatter d = new DataFormatter(Locale.CHINA); diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java index 68fff70..fa41704 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/poi/PoiWriteTest.java @@ -2,6 +2,7 @@ package com.alibaba.easyexcel.test.temp.poi; import java.io.FileOutputStream; import java.io.IOException; +import java.math.BigDecimal; import java.util.regex.Pattern; import org.apache.poi.xssf.streaming.SXSSFCell; @@ -35,9 +36,20 @@ public class PoiWriteTest { cell1.setCellValue(999999999999999L); SXSSFCell cell2 = row.createCell(1); cell2.setCellValue(1000000000000001L); + SXSSFCell cell32 = row.createCell(2); + cell32.setCellValue(300.35f); sxxsFWorkbook.write(fileOutputStream); } + @Test + public void write01() throws IOException { + float ff = 300.35f; + BigDecimal bd = new BigDecimal(Float.toString(ff)); + System.out.println(bd.doubleValue()); + System.out.println(bd.floatValue()); + + } + @Test public void write() throws IOException { FileOutputStream fileOutputStream = diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/JsonData.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/JsonData.java new file mode 100644 index 0000000..a9ba7fa --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/JsonData.java @@ -0,0 +1,15 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import lombok.Data; + +/** + * TODO + * + * @author Jiaju Zhuang + **/ +@Data +public class JsonData { + private String SS1; + private String sS2; + private String ss3; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java index 44bc943..6157181 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/Wirte.java @@ -14,6 +14,7 @@ import com.alibaba.easyexcel.test.core.large.LargeData; import com.alibaba.easyexcel.test.demo.write.DemoData; import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; import net.sf.cglib.beans.BeanMap; @@ -43,7 +44,35 @@ public class Wirte { String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx"; // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 // 如果这里想使用03 则 传入excelType参数即可 - EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data()); + EasyExcel.write(fileName, DemoData.class).relativeHeadRowIndex(10).sheet("模板").doWrite(data()); + } + + @Test + public void simpleWrite2() { + // 写法1 + String fileName = TestFileUtil.getPath() + "t22" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + // 如果这里想使用03 则 传入excelType参数即可 + EasyExcel.write(fileName, WriteData.class).sheet("模板").doWrite(data1()); + } + + @Test + public void json() { + JsonData jsonData = new JsonData(); + jsonData.setSS1("11"); + jsonData.setSS2("22"); + jsonData.setSs3("33"); + System.out.println(JSON.toJSONString(jsonData)); + + } + + @Test + public void json3() { + String json = "{\"SS1\":\"11\",\"sS2\":\"22\",\"ss3\":\"33\"}"; + + JsonData jsonData = JSON.parseObject(json, JsonData.class); + System.out.println(JSON.toJSONString(jsonData)); + } private List> head() { @@ -72,4 +101,14 @@ public class Wirte { return list; } + private List data1() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + WriteData data = new WriteData(); + data.setF(300.35f); + list.add(data); + } + return list; + } + } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java b/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java new file mode 100644 index 0000000..b8ff14d --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/simple/WriteData.java @@ -0,0 +1,13 @@ +package com.alibaba.easyexcel.test.temp.simple; + +import lombok.Data; + +/** + * write data + * + * @author Jiaju Zhuang + **/ +@Data +public class WriteData { + private float f; +} diff --git a/src/test/resources/dataformat/dataformat.xls b/src/test/resources/dataformat/dataformat.xls new file mode 100644 index 0000000000000000000000000000000000000000..c03847e4e5cde9f156ddf23b5d8263dc1357453e GIT binary patch literal 26112 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 Hx%~eDWlI1` literal 0 HcmV?d00001 diff --git a/src/test/resources/dataformat/dataformat.xlsx b/src/test/resources/dataformat/dataformat.xlsx index 370d983a931862faf90274a954ed71e38cb92ac5..0085930c31d5b3a08eb63f6f868089eb89c6a29d 100644 GIT binary patch delta 7423 zcmZ9RWl-Erv-X$8-6gmLcZc8*+!nXs?izysaSOhCs=|zB)Enw1Ohp^@8_+0 z&vWL(R9DxpXR2nps_W|BGdMMB%!fn7{17ap2`zzR0T?beSEV;Xrqr+y7-Kt<0ybiu z4O8qoYJ6@EjT=G*7rFsktUnP3D_>(MMI-Mgq4!UCFk6GucVUZ)9CU~N2*T999C*Sp z^Cxz@-pM7H(9p6^;V83GB|$yi__v|A?*^Nu&>;+P7y8gIsl>S1q*{-)ot*BJ_m$_aB8!L!0%a7 zNY={_=`^Qg1B>qwc~$k@7eoOR0(UBmnEL5udhOMu?fr>!QSyvmD_v;yy7zQm4zQXTFIWU)N_UAT|T*ZTvx%&$5xmYZbBl$ZhQmoBdaLpx8Of7~B%wqV1@ z!eNzTx%urNf=tKZSnw#QkC)Q5KPWZAQ%W`GfW_l^bn!hTZBNFe zSN2i@xa!~RR#RR)O(N=)PJW6pyg$2KF>Tk|?CD?(kA}yq7VuCH|B{#wtk^JWmtTNa zDnl9NH&dBI5@&N(mNAvEowN*m20cE(ruZ7(aqKlUC5I%Ai^`yW{!CwuLcCZ=OK%4F zPo1?xVeXA7AM6%cAJ*4+xw!Y#U2cD;*_dY8V!GTUv+=z1+vMAtM!u4|ZJFVdiZn~J z{}EK*AG}MN>p%N3H-P5@AQFai^6g#2%4nMlu>pN83BtsVPxQ!9`Yw;6;^}2O8~hHL zYlqk&j%>DHh1B>&;4RhtU>G_!$)S8g{l#vt%;E~Mc41s0{Fm6Xc~YOzhdeM4RYp(v z8KiBMo%}o0LYpAD8@nj(#ad~Xo$1|DEc z)WzpQyRn_3bIxcNB&}Tx+-}K=Efsowc$6B?~KKyJxJE4ce#wq-b$i>VCW!!6HUM88w|T2Ai#0 zcKzawS+YGAkd~{v@fScr$@8VF5M`bnZfPFi&c15L_?c)&B)!)!V*=+3HiHXt+i^-agXYYMq}QWeLgiAxB) zvy}RB&w2&72PimA1+H)!2gK?JFJQJ?r06i3!-Yo22*yW=Bts9DGE(291wl!KL3iOL zf<1HC;vs|!s9a3F6pHX|Fm^7*3T?M7eb61RLE&PLqETWpyyV>5NYHhOrkSj-WE^0K zXvfZ#sE9Dg^8DKgufYtqM6zb-w|yd7{?b(Jd;5!*y$R+egZ?sDJ$EiR5FDE~JcEw?%MXfcJknYnn#>1+%P1x51)(Cu#@udA-Oa!b&o*a<&m{M#+sK z;I&`I>?O&sc!7SEx+TFo+x4DrI%fpODC6_rz(e!bXAZFZ-RwH)x;_hV#*eKE{NHk+ zyNiSzF~&#H+$Z9}3@rDE$(|Qq?BlaDeoJ%)A!)fmhZ|_l<&!4r+-0))81K+>&^LIQ zzbtMv2z38}gDArz5P(1+6i}4fzT{y*%O)x!0^-99IZizEJ0=&N7JFVcpMm+AF8|s* zW!^{6qfsam78@X|<7o^0etv#_bUfNG6Ty{vdaE#XP_8FtdV>=aC|>G5f9G=7eY7n4 znlK?M^Cpw8mpOU6EdG9{J9z$q9D@(E}?D|IfEBpms z#$9GYCIX_eToYNk-ECtLb-8_TT>Ob=UT-ec_$zEdtM^h`tjftYb=|to)_myHPeSV5 z##MR_96+BWV6FCDuI6jCpr!$v27Gg3oA7T#>$dh!=ew8_`)8gHhK?;;ChxD2tZr&N zA1))t9A-z!AQN_?`7(}C-rdYU$$9pjx(WJ_uG^H*3W}&nZ;uz*5OFB0=t92ApS)A4m z&;ausG+P=)@I3;fwHPb3^*1hPOqA9G)6k8C+FpnX0sCG6eH{5N)=}-KY!zI+oe3iP zJ)=A1^E;K;PO-TAX`c@F^Uii&#X<)gsgu<{3OxB4<4DU0cs%@wJ8~*~&EhR~C5rA# zh^gD8Jla-qWrTf|;-l9t!lKiHK>Psb62Ox;_%*@V+ohPu*4ofDIgl6?HN+t1I&g@b z*JKPoqJ$?Uki4mQu)%^b9d#`Stv~uq0Wlv7<)D)HwPt$VCl1M-(4_{mO1(0d9rL9L zSv1*kYrY1H&mSk)#a*I=l%^WRNTX!Wkv%YIVi!2{tgk69ZK8vaC3by^x?MH*JAtPM zX}2(>1cesR0x!PC{`7RX$jwGhGcH5}lJ5Y1<4Q`#N zn3q4g{TagRjbOat2&v87Dc;sO{y@0?G^ckg`zZkS-d8uaNa-wc1h!uOBY{X@n{G;9 zUG>!`7S$_ub9hp3b4UZPt$GU8ND6>M`JMqD9+?=$X_m=qA z$>MNjA`j-u~u_*)H*@)hU{$^*tGpp5myM139%Z1;R{T=P^53d?DtRG<0T- z`3u!doi+&LcU}JCtm0$0X`N*Tfg=wt-+EGv@5|wzk)$LLbWI|b`fV_eC}w~O$i~(q zljp~qA%iZ3NFN1FD*N7}Ky7}tDGO^g+`1@Cq(E=cF$Y8!OjQ_rXWodStalsYInPyZ zd`2@$zAtJeg{nLeF%&v_TzJBNI{hB|myo?5oe;~gWoqzBnF|9q`tJIq-caOo)1*^# z!1r0X^2{6rozCY*?*gsWDtN`1BnR~A`N+sDC7IySY-k$r3Cl)|6;Y{rVX{=;Ak6Gx zyc8tTRZm}nd!w_k7J=(5@|2yfDX#JMZfFmVv@vFNcsGcmx^ONDN{lZHIAA}xDY9`b zW-Z=zLTI8`Qp3Moq1lnETm;*Nu$p8>7KYY1{9vExdubQ8wa;vggqE(Cz~K?V=m^oI zy^GkgjzuE%`M0{+6w~o|aCLC>7)ZLWM?jW&E;16v(mbB=VjZ?lkWkEBu2`BHy%*1xa#Zqz1h>_ zhAlqNaJ8w8!pP3y`h0;PqDaF#i93N?B9jo9*$>;;J!XGcGaE{6ZN;=ZQ2+1pky2IZ zjEeyR6qx=Rca_tFg1|#xmiHxY?f&NLL_}jaDjCj2D}2lM?`j z&!*AmF_R=mXnwl}e!GBQHL%V_ZImsnoD3(^Wz7n%b=CamDrr{k?>JpvR;iItS;YcgP0w4dx988Z z_MbZ+7Nqbu<2M$fIG^~uJ>b+%p*?XrS!U71Vl?a0-`KuRWf=MGjpj5ZY|F1m8`hwB zSVPr%hN#1=P}&u_g~axuw4+RUr`xN_N4_gAp(A~@#({?v#?=+<8|So)I(J*A4h09R)U)9ZasVUio_DRUee{D(1^ zSCG-ZgE~aBO2-$jB-v@wx#$DS?>w5crg6?F4ov{1M$3V}Z)l5f+R#0h{p6JY*JE2W z4-O*R4>r(7x_n7=_xqR2I-r9~iA$%+=ht%L49po8+lhqR2I0OIt>M87gc z{S~m*?|w5|U!=d)`Iv+gTW&;lCP8jEbpbt)KN!dU20ggnwOpzB!RukBQFIX1&p=Fj zij_<2W$+^w)K1-ku#hJ9Lx&8FFO4r7@lxI!hx{>!Br2vOqvipZG!RbEd(C~&pzj74teq&V0dTfbMHzHR^h2?jDwjfoRh93mGl$Q}Ib-D^hT zS7KOHlvKJLH`Jx@J_NODAUotGi5c%gsAS**CFG0kw=64W&+Au{OrAWJai~SM!SPzH1#iIuP?V(KP{9Sg{!O3uJ|ywVB~| z|G7|DQ)$($g%EH%H|dCnob#=|;NInJab(jnajbY5ucTI&+jkl2x<%RLY;Rt4%m(6@ zV^lvh&oFVb?xOsfUzwHbn>(L<-y3q?=VR=MP9&q_pe-0bX7i>QqeR1~lWmGEa%nf&Uz&AzZ`wMoFA*vVg6 z2u%4$e)s_Y4K;pb+Xk!(hON zB_R}sA?xtW>Nl3CPDD;=uh3BlR6zVS3A^BAs3`C*eeDvf&Yt&COp{QRppw5$UyHSj zg%USJIk^COkwYzVC@ldu*u#{cmYtEyM1d+|t2Nq^LE_0(@tRiIBFnz(H4!cjL(@#H z%MUL?ZZ4ChaJ(fy1_B(rEQkf=oBE7-s?(m>9%k@BYNo1u`9Rzo9{PQ+(i5VT57XyA zT?&DbM`%L9pib)0y~xagh|gfhRWW1uJdKL>qD)Ht`cYGExu=t0a)bqi{C?maQ6a55{v!P-T+)1X`+kP)tGJ zv%Y=UhzMq3CkTW$)hyA!_WKfXi;LwMt}!|%Ys^xI`bnQ@!dTz}6AsCC*KANc`r3ed^lDp<4Iz+d#iVi4Brh!=u#aG-~@Pb8QNgtw} z7DL;emcx@0OA$+FV=7+pvT!L)RlM3;Kq^ScZ79;CupA#9Qy?h+GM?=O9gY)Hauai7 z#E9Z;Ay~3!m9jvUgc~A(oJ6vap#bFLw+MIbvScX+%*1R7rD5mmfz zlM8VLo@CrA`ZE6MPn8_s9MOmL}q8G{#vA(yb(i99xM&hlm5w<-E5i&gJ}U z@LHbOc-PF@>61fQW5%aL#feK@HzR|@pU1w|(X0Ujx+mzpl@lc6)tf3DiS-rEsMNhFce!CKT4vMt8 zwhd0FlAIVuGojY$JKc$N>yv5vZtXHoy=f+1=<}oI3bB}2o)ke^OOpqE&TgGmYV`zB zK$WM`LNiU8v^Vs3H~)$KbsU<6xF?TV=lSu2fR zDJU;KOmnLJ@da+9!frlR*iwm!JkK)X-Hl9kk{72|m8!Jw-EQj^LDWsfUP%buDHSSy z2eF9$z>WFJ8lp=Q2H-ug4{^=k96T{{QVrYW+EVq*RiX^eq>eO1M=DpxuoQpVloZ9N zL<}A;pz^gVN*vw9a_lVLc-3hl%(pZdjZ0X=U=guLtrf!}aA}MEIlm|S_wqeT5Cshm z``zA|L@)SE?d7HqnYaM~DdPGCWWJFg@#paFxTd8-zCpt09`I6PQKu*}VEps4u{KC& z`dXbLn4QbHG+vUth|Q!4D=8zQH8a4+4Yoi&+_`;oO<8kGyK(1bbwq~Nrq!x-GnRZ|g|7;T?>43Wv z_h4T)5Z9PZ4KNX$V44a93A0urWd};}YkMcX_qiN+Q&tEmb=s+VXbP4T=mFDLB3U2AgOf9&fsgG5P-CUeSSb7Ql(;{4n9FcWNo1iv=_MA!=6OjG5Feaka1g9zmEw`Q7n9RuM-MM z^IIAf7zc2(g2EhpK35On5L6yi@Tb|b_TaJ);8v+YFz1$I=O>d-5x!nK)tNCOPmj;H zeaLB?MGQ*ZxY~g4U$?0cKK~^6%y|~E`#`$A1i<}PyXxBRb?okp^`j9ALU!Jg%69hL z2^*>^*E*}>s;&VMB>+^?erUb`|9x~ zHZ4##?-35YW`lG!Vaq+ksF5yu>%`0G`<=S}ar5PKG@^F%{@rdpoKAXZKkmC4;!J!n z6(FpRw0a2ChMzx3)HlI^{}vUNYPITZa3E0X-#NuUovMFCg`K&FwUw5ahrNsKzuF>D zdroPXi=-dDPX^VmMVUw2sx^)Kn(Mk$T=Lz4uKv4+5u2j}M`#q*Xpb!RTyB z!*0gcreFMRcfjIKf57B@+2D)yn>!AxdZ8Z7Q@gt3}u=w?TbVWR*iNr=J z@=(d4nX0Y<(U1(gM=8q6Y^GAS>Jrn6#fy$i5pl*Ky<%vj z;wfmDq35U6p1o?NDkuDn(v>?Q%r|T}Ov9!OGtwLq8h}6i5s~ZV`Nird$+laFfaN1> z$TrbZ+}~%2k}RSr9<3QKbhMuTj3|d#zwW8TP`V84pP9hUsb;qgzVh@C=_NZr`{S@4 zmD#aC0(7vq4YzDiYdhiMei}84~i`RJqGiQ&;jRVAX z4(^bL zOez0w^ykK`4TlRIWtK#iMEExepuMc*P$m{EunYrKh=m{QzyNh+VI%*)>GC&YKyV=H zzk3M{w1b6#{Qrv7{}0#_LVvLc3x{I;d%l;QwX-!RL>UfD@NeGzr$hR0XA}tp$|M7U z@c#+@yZ&>06&CaglMour$^wq1gVwT&z?nmjS!u}sd&c&^BjOSMnYcmUuyKNm(f&1q R|C%Wne@zx7DdvCB{{byD`cD7= delta 7099 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 3.4.0(jdk6) +* 修复xls 用Map接收时多次接收会是同一个对象的bug +* 修复浮点型数据导入到excel 会丢失精度的bug + # 2.1.3 * 每个java进程单独创建一个缓存目录 [Issue #813](https://github.com/alibaba/easyexcel/issues/813) * 统一修改合并为unsafe,提高大量数据导出的合并的效率 From 2c58b5e5fcb58df71e406377a103e27b6f3cfaaf Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Wed, 25 Dec 2019 18:32:21 +0800 Subject: [PATCH 08/38] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E6=89=B9=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .travis.yml | 2 +- README.md | 1 + pom.xml | 8 ++- .../excel/analysis/ExcelAnalyserImpl.java | 37 +++++------ .../v03/AbstractXlsRecordHandler.java | 6 ++ .../analysis/v03/XlsListSheetListener.java | 4 +- .../excel/analysis/v03/XlsSaxAnalyser.java | 64 +++++-------------- .../handlers/BlankOrErrorRecordHandler.java | 5 ++ .../v03/handlers/BofRecordHandler.java | 19 +++--- .../v03/handlers/FormulaRecordHandler.java | 6 +- .../v03/handlers/IndexRecordHandler.java | 12 ++-- .../v03/handlers/LabelRecordHandler.java | 6 ++ .../MissingCellDummyRecordHandler.java | 5 ++ .../v03/handlers/NoteRecordHandler.java | 5 ++ .../v03/handlers/NumberRecordHandler.java | 13 ++-- .../v03/handlers/RkRecordHandler.java | 5 ++ .../v03/handlers/SstRecordHandler.java | 5 ++ .../v03/handlers/TextObjectRecordHandler.java | 39 +++++++++++ .../v07/handlers/DefaultCellHandler.java | 2 +- .../excel/context/DefaultXlsReadContext.java | 16 +++++ .../excel/context/WriteContextImpl.java | 9 --- .../alibaba/excel/context/XlsReadContext.java | 11 ++++ .../alibaba/excel/enums/ExtraReadEnum.java | 13 ++++ .../metadata/AbstractParameterBuilder.java | 5 ++ .../com/alibaba/excel/metadata/CellExtra.java | 18 ++++++ .../excel/read/metadata/ReadWorkbook.java | 16 +++++ .../read/metadata/holder/ReadRowHolder.java | 32 ---------- .../metadata/holder/ReadWorkbookHolder.java | 24 ++++++- .../demo/read/DemoCellCommentsListener.java | 26 +++----- .../easyexcel/test/temp/read/CommentTest.java | 34 ++++++++++ update.md | 2 + 31 files changed, 289 insertions(+), 161 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java create mode 100644 src/main/java/com/alibaba/excel/context/XlsReadContext.java create mode 100644 src/main/java/com/alibaba/excel/enums/ExtraReadEnum.java create mode 100644 src/main/java/com/alibaba/excel/metadata/CellExtra.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java diff --git a/.travis.yml b/.travis.yml index 8191cf3..74750ec 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,5 +6,5 @@ cache: before_install: - chmod +x mvnw install: - - ./mvnw install -Dgpg.skip -B -V -Dmaven.test.skip=true + - ./mvnw install -B -V -Dmaven.test.skip=true - ./mvnw javadoc:javadoc \ No newline at end of file diff --git a/README.md b/README.md index 72cc016..0622245 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都 * [快速使用](https://alibaba-easyexcel.github.io/) * [关于软件](/abouteasyexcel.md) * [更新记事](/update.md) +* [贡献代码](https://alibaba-easyexcel.github.io/support/contribute.html) ## 维护者 玉霄、庄家钜、怀宇 diff --git a/pom.xml b/pom.xml index cb5bb97..4a47b3d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.1.4 + 2.2.0-beta1 jar easyexcel @@ -15,9 +15,10 @@ - UTF-8 1.6 + true + true @@ -159,6 +160,8 @@ com/alibaba/excel/event/AnalysisEventListener.java + com/alibaba/excel/metadata/DataFormatter.java + com/alibaba/excel/util/DateUtils.java @@ -201,7 +204,6 @@ - org.apache.maven.plugins maven-gpg-plugin diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index feec16b..90cfad0 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -15,6 +15,8 @@ import com.alibaba.excel.analysis.v03.XlsSaxAnalyser; import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContextImpl; +import com.alibaba.excel.context.DefaultXlsReadContext; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.read.metadata.ReadSheet; @@ -43,8 +45,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { public ExcelAnalyserImpl(ReadWorkbook readWorkbook) { try { - analysisContext = new AnalysisContextImpl(readWorkbook); - choiceExcelExecutor(); + choiceExcelExecutor(readWorkbook); } catch (RuntimeException e) { finish(); throw e; @@ -54,28 +55,25 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { } } - private void choiceExcelExecutor() throws Exception { - ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); - ExcelTypeEnum excelType = readWorkbookHolder.getExcelType(); - if (excelType == null) { - excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null); - return; - } + private void choiceExcelExecutor(ReadWorkbook readWorkbook) throws Exception { + ExcelTypeEnum excelType = + ExcelTypeEnum.valueOf(readWorkbook.getFile(), readWorkbook.getInputStream(), readWorkbook.getExcelType()); + readWorkbook.setExcelType(excelType); switch (excelType) { case XLS: POIFSFileSystem poifsFileSystem; - if (readWorkbookHolder.getFile() != null) { - poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getFile()); + if (readWorkbook.getFile() != null) { + poifsFileSystem = new POIFSFileSystem(readWorkbook.getFile()); } else { - poifsFileSystem = new POIFSFileSystem(readWorkbookHolder.getInputStream()); + poifsFileSystem = new POIFSFileSystem(readWorkbook.getInputStream()); } // So in encrypted excel, it looks like XLS but it's actually XLSX if (poifsFileSystem.getRoot().hasEntry(Decryptor.DEFAULT_POIFS_ENTRY)) { InputStream decryptedStream = null; try { - decryptedStream = - DocumentFactoryHelper.getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(), - analysisContext.readWorkbookHolder().getPassword()); + decryptedStream = DocumentFactoryHelper + .getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(), readWorkbook.getPassword()); + analysisContext = new AnalysisContextImpl(readWorkbook); excelReadExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream); return; } finally { @@ -85,12 +83,15 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { poifsFileSystem.close(); } } - if (analysisContext.readWorkbookHolder().getPassword() != null) { - Biff8EncryptionKey.setCurrentUserPassword(analysisContext.readWorkbookHolder().getPassword()); + if (readWorkbook.getPassword() != null) { + Biff8EncryptionKey.setCurrentUserPassword(readWorkbook.getPassword()); } - excelReadExecutor = new XlsSaxAnalyser(analysisContext, poifsFileSystem); + XlsReadContext xlsReadContext = new DefaultXlsReadContext(readWorkbook); + analysisContext = xlsReadContext; + excelReadExecutor = new XlsSaxAnalyser(xlsReadContext, poifsFileSystem); break; case XLSX: + analysisContext = new AnalysisContextImpl(readWorkbook); excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null); break; default: diff --git a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java index 6128708..0deba91 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java @@ -1,5 +1,6 @@ package com.alibaba.excel.analysis.v03; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.metadata.CellData; /** @@ -10,6 +11,11 @@ public abstract class AbstractXlsRecordHandler implements XlsRecordHandler { protected int row = -1; protected int column = -1; protected CellData cellData; + protected XlsReadContext analysisContext; + + public AbstractXlsRecordHandler(XlsReadContext analysisContext) { + this.analysisContext = analysisContext; + } @Override public int getRow() { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java index 6f8e716..bc93731 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java @@ -14,7 +14,7 @@ import org.apache.poi.hssf.record.Record; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler; -import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.read.metadata.ReadSheet; @@ -28,7 +28,7 @@ public class XlsListSheetListener implements HSSFListener { private List sheetList; private BofRecordHandler bofRecordHandler; - public XlsListSheetListener(AnalysisContext analysisContext, POIFSFileSystem poifsFileSystem) { + public XlsListSheetListener(XlsReadContext analysisContext, POIFSFileSystem poifsFileSystem) { this.poifsFileSystem = poifsFileSystem; sheetList = new ArrayList(); bofRecordHandler = new BofRecordHandler(analysisContext, sheetList, false, false); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index 5ef640e..edd763e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -3,12 +3,10 @@ package com.alibaba.excel.analysis.v03; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import com.alibaba.excel.util.StringUtils; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; @@ -21,11 +19,6 @@ import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; -import org.apache.poi.ss.usermodel.Comment; -import org.apache.poi.ss.usermodel.Sheet; -import org.apache.poi.ss.usermodel.Workbook; -import org.apache.poi.ss.usermodel.WorkbookFactory; -import org.apache.poi.ss.util.CellAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -40,7 +33,8 @@ import com.alibaba.excel.analysis.v03.handlers.NoteRecordHandler; import com.alibaba.excel.analysis.v03.handlers.NumberRecordHandler; import com.alibaba.excel.analysis.v03.handlers.RkRecordHandler; import com.alibaba.excel.analysis.v03.handlers.SstRecordHandler; -import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.analysis.v03.handlers.TextObjectRecordHandler; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.metadata.CellData; @@ -72,6 +66,8 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { private List readSheetList; private int lastRowNumber; private int lastColumnNumber; + private int ii = 0; + /** * For parsing Formulas */ @@ -81,19 +77,12 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { private List sheets; private HSSFWorkbook stubWorkbook; private List recordHandlers = new ArrayList(); - private AnalysisContext analysisContext; - private Workbook poiWorkbook; - private Map rowComments; + private XlsReadContext analysisContext; - public XlsSaxAnalyser(AnalysisContext context, POIFSFileSystem poifsFileSystem) { + public XlsSaxAnalyser(XlsReadContext context, POIFSFileSystem poifsFileSystem) { this.analysisContext = context; this.records = new LinkedHashMap(); this.poifsFileSystem = poifsFileSystem; - try { - this.poiWorkbook = WorkbookFactory.create(poifsFileSystem); - } catch (IOException e) { - e.printStackTrace(); - } analysisContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem); } @@ -154,7 +143,6 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { thisRow = handler.getRow(); thisColumn = handler.getColumn(); cellData = handler.getCellData(); - handleComments(thisRow, thisColumn); if (cellData != null) { cellData.checkEmpty(); if (CellDataTypeEnum.EMPTY != cellData.getType()) { @@ -186,26 +174,6 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { processLastCellOfRow(record); } - public void handleComments(int row, int col) { - if (null == this.poiWorkbook || null == analysisContext.readSheetHolder() || row < 0 || col < 0) { - return; - } - Sheet currentSheet = poiWorkbook.getSheetAt(analysisContext.readSheetHolder().getSheetNo()); - Map cellComments = currentSheet.getCellComments(); - if (CollectionUtils.isEmpty(cellComments)) { - return; - } - Comment comment = cellComments.get(new CellAddress(row, col)); - if (null == comment) { - return; - } - String commentsStr = comment.getString().toString(); - if (!StringUtils.isEmpty(commentsStr)) { - rowComments = rowComments == null ? new HashMap(8) : rowComments; - rowComments.put(col, commentsStr); - } - } - private boolean ignoreRecord(Record record) { return analysisContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid && record.getSid() != BOFRecord.sid; @@ -224,17 +192,14 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { } analysisContext.readRowHolder( new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration())); - if (!CollectionUtils.isEmpty(rowComments)) { - analysisContext.readRowHolder().setRowComments(rowComments); - } analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext); - records = new HashMap(); + this.records = new LinkedHashMap(); lastColumnNumber = -1; } private void buildXlsRecordHandlers() { if (CollectionUtils.isEmpty(recordHandlers)) { - recordHandlers.add(new BlankOrErrorRecordHandler()); + recordHandlers.add(new BlankOrErrorRecordHandler(analysisContext)); // The table has been counted and there are no duplicate statistics if (sheets == null) { sheets = new ArrayList(); @@ -242,14 +207,15 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { } else { recordHandlers.add(new BofRecordHandler(analysisContext, sheets, true, true)); } - recordHandlers.add(new FormulaRecordHandler(stubWorkbook, formatListener)); - recordHandlers.add(new LabelRecordHandler()); - recordHandlers.add(new NoteRecordHandler()); + recordHandlers.add(new FormulaRecordHandler(analysisContext, stubWorkbook, formatListener)); + recordHandlers.add(new LabelRecordHandler(analysisContext)); + recordHandlers.add(new NoteRecordHandler(analysisContext)); recordHandlers.add(new NumberRecordHandler(analysisContext, formatListener)); - recordHandlers.add(new RkRecordHandler()); - recordHandlers.add(new SstRecordHandler()); - recordHandlers.add(new MissingCellDummyRecordHandler()); + recordHandlers.add(new RkRecordHandler(analysisContext)); + recordHandlers.add(new SstRecordHandler(analysisContext)); + recordHandlers.add(new MissingCellDummyRecordHandler(analysisContext)); recordHandlers.add(new IndexRecordHandler(analysisContext)); + recordHandlers.add(new TextObjectRecordHandler(analysisContext)); Collections.sort(recordHandlers); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java index f64d437..686ffb0 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java @@ -5,6 +5,7 @@ import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -15,6 +16,10 @@ import com.alibaba.excel.metadata.CellData; */ public class BlankOrErrorRecordHandler extends AbstractXlsRecordHandler { + public BlankOrErrorRecordHandler(XlsReadContext analysisContext) { + super(analysisContext); + } + @Override public boolean support(Record record) { return BlankRecord.sid == record.getSid() || BoolErrRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java index 083edbc..af1a2b4 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -8,7 +8,7 @@ import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; -import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.util.SheetUtils; @@ -24,13 +24,12 @@ public class BofRecordHandler extends AbstractXlsRecordHandler { private List sheets; private Boolean readAll; private List readSheetList; - private AnalysisContext context; private boolean alreadyInit; private boolean needInitSheet; - public BofRecordHandler(AnalysisContext context, List sheets, boolean alreadyInit, + public BofRecordHandler(XlsReadContext analysisContext, List sheets, boolean alreadyInit, boolean needInitSheet) { - this.context = context; + super(analysisContext); this.sheets = sheets; this.alreadyInit = alreadyInit; this.needInitSheet = needInitSheet; @@ -68,17 +67,17 @@ public class BofRecordHandler extends AbstractXlsRecordHandler { } } assert readSheet != null : "Can't find the sheet."; - context.readWorkbookHolder().setIgnoreRecord03(Boolean.TRUE); + analysisContext.readWorkbookHolder().setIgnoreRecord03(Boolean.TRUE); // Copy the parameter to the current sheet readSheet = SheetUtils.match(readSheet, readSheetList, readAll, - context.readWorkbookHolder().getGlobalConfiguration()); + analysisContext.readWorkbookHolder().getGlobalConfiguration()); if (readSheet != null) { - if (readSheet.getSheetNo() != 0 && context.readSheetHolder() != null) { + if (readSheet.getSheetNo() != 0 && analysisContext.readSheetHolder() != null) { // Prompt for the end of the previous form read - context.readSheetHolder().notifyAfterAllAnalysed(context); + analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext); } - context.currentSheet(readSheet); - context.readWorkbookHolder().setIgnoreRecord03(Boolean.FALSE); + analysisContext.currentSheet(readSheet); + analysisContext.readWorkbookHolder().setIgnoreRecord03(Boolean.FALSE); } } sheetIndex++; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java index 0ff8f99..b19e36d 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -13,6 +13,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -32,7 +33,9 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler { private FormatTrackingHSSFListener formatListener; private HSSFWorkbook stubWorkbook; - public FormulaRecordHandler(HSSFWorkbook stubWorkbook, FormatTrackingHSSFListener formatListener) { + public FormulaRecordHandler(XlsReadContext analysisContext, HSSFWorkbook stubWorkbook, + FormatTrackingHSSFListener formatListener) { + super(analysisContext); this.stubWorkbook = stubWorkbook; this.formatListener = formatListener; } @@ -46,7 +49,6 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler { public void processRecord(Record record) { if (record.getSid() == FormulaRecord.sid) { FormulaRecord frec = (FormulaRecord)record; - this.row = frec.getRow(); this.column = frec.getColumn(); CellType cellType = CellType.forInt(frec.getCachedResultType()); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java index 6837ebd..83105bf 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java @@ -4,7 +4,7 @@ import org.apache.poi.hssf.record.IndexRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; -import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.context.XlsReadContext; /** * Record handler @@ -13,10 +13,8 @@ import com.alibaba.excel.context.AnalysisContext; */ public class IndexRecordHandler extends AbstractXlsRecordHandler { - private AnalysisContext context; - - public IndexRecordHandler(AnalysisContext context) { - this.context = context; + public IndexRecordHandler(XlsReadContext analysisContext) { + super(analysisContext); } @Override @@ -29,10 +27,10 @@ public class IndexRecordHandler extends AbstractXlsRecordHandler { @Override public void processRecord(Record record) { - if (context.readSheetHolder() == null) { + if (analysisContext.readSheetHolder() == null) { return; } - context.readSheetHolder().setApproximateTotalRowNumber(((IndexRecord)record).getLastRowAdd1()); + analysisContext.readSheetHolder().setApproximateTotalRowNumber(((IndexRecord)record).getLastRowAdd1()); } @Override diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java index 35732c1..79db34a 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java @@ -4,6 +4,7 @@ import org.apache.poi.hssf.record.LabelRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.metadata.CellData; /** @@ -12,6 +13,11 @@ import com.alibaba.excel.metadata.CellData; * @author Dan Zheng */ public class LabelRecordHandler extends AbstractXlsRecordHandler { + + public LabelRecordHandler(XlsReadContext analysisContext) { + super(analysisContext); + } + @Override public boolean support(Record record) { return LabelRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java index c879504..f40422a 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java @@ -4,6 +4,7 @@ import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -13,6 +14,10 @@ import com.alibaba.excel.metadata.CellData; * @author Dan Zheng */ public class MissingCellDummyRecordHandler extends AbstractXlsRecordHandler { + public MissingCellDummyRecordHandler(XlsReadContext analysisContext) { + super(analysisContext); + } + @Override public boolean support(Record record) { return record instanceof MissingCellDummyRecord; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java index 9ab800c..f63d9ee 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java @@ -4,6 +4,7 @@ import org.apache.poi.hssf.record.NoteRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -13,6 +14,10 @@ import com.alibaba.excel.metadata.CellData; * @author Dan Zheng */ public class NoteRecordHandler extends AbstractXlsRecordHandler { + public NoteRecordHandler(XlsReadContext analysisContext) { + super(analysisContext); + } + @Override public boolean support(Record record) { return NoteRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java index af02488..948cf53 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -8,7 +8,7 @@ import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; import com.alibaba.excel.constant.BuiltinFormats; -import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.metadata.CellData; /** @@ -19,10 +19,8 @@ import com.alibaba.excel.metadata.CellData; public class NumberRecordHandler extends AbstractXlsRecordHandler { private FormatTrackingHSSFListener formatListener; - private AnalysisContext context; - - public NumberRecordHandler(AnalysisContext context, FormatTrackingHSSFListener formatListener) { - this.context = context; + public NumberRecordHandler(XlsReadContext analysisContext, FormatTrackingHSSFListener formatListener) { + super(analysisContext); this.formatListener = formatListener; } @@ -39,8 +37,9 @@ public class NumberRecordHandler extends AbstractXlsRecordHandler { this.cellData = new CellData(BigDecimal.valueOf(numrec.getValue())); int dataFormat = formatListener.getFormatIndex(numrec); this.cellData.setDataFormat(dataFormat); - this.cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, - formatListener.getFormatString(numrec), context.readSheetHolder().getGlobalConfiguration().getLocale())); + this.cellData + .setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, formatListener.getFormatString(numrec), + analysisContext.readSheetHolder().getGlobalConfiguration().getLocale())); } @Override diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java index 140fb72..08e2ac2 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java @@ -4,6 +4,7 @@ import org.apache.poi.hssf.record.RKRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -13,6 +14,10 @@ import com.alibaba.excel.metadata.CellData; * @author Dan Zheng */ public class RkRecordHandler extends AbstractXlsRecordHandler { + public RkRecordHandler(XlsReadContext analysisContext) { + super(analysisContext); + } + @Override public boolean support(Record record) { return RKRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java index 5c1c8ae..67962bd 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java @@ -5,6 +5,7 @@ import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.SSTRecord; import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -16,6 +17,10 @@ import com.alibaba.excel.metadata.CellData; public class SstRecordHandler extends AbstractXlsRecordHandler { private SSTRecord sstRecord; + public SstRecordHandler(XlsReadContext analysisContext) { + super(analysisContext); + } + @Override public boolean support(Record record) { return SSTRecord.sid == record.getSid() || LabelSSTRecord.sid == record.getSid(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java new file mode 100644 index 0000000..ee502dc --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java @@ -0,0 +1,39 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.ObjRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.TextObjectRecord; + +import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; + +/** + * Record handler + * + * @author Jiaju Zhuang + */ +public class TextObjectRecordHandler extends AbstractXlsRecordHandler { + public TextObjectRecordHandler(XlsReadContext analysisContext) { + super(analysisContext); + } + + @Override + public boolean support(Record record) { + return TextObjectRecord.sid == record.getSid() || ObjRecord.sid == record.getSid(); + } + + @Override + public void processRecord(Record record) { + System.out.println(record); + } + + @Override + public void init() { + + } + + @Override + public int getOrder() { + return 0; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java index f4534fb..3a489e1 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -159,7 +159,7 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder @Override public void handleComments(String comment) { - analysisContext.readRowHolder().addComments(curCol, comment); + // analysisContext.readRowHolder().addComments(curCol, comment); } @Override diff --git a/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java b/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java new file mode 100644 index 0000000..3f7da09 --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java @@ -0,0 +1,16 @@ +package com.alibaba.excel.context; + +import com.alibaba.excel.read.metadata.ReadWorkbook; + +/** + * + * A context is the main anchorage point of a ls xls reader. + * + * @author Jiaju Zhuang + */ +public class DefaultXlsReadContext extends AnalysisContextImpl implements XlsReadContext { + + public DefaultXlsReadContext(ReadWorkbook readWorkbook) { + super(readWorkbook); + } +} diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index 2130169..77ba7ec 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -282,7 +282,6 @@ public class WriteContextImpl implements WriteContext { throwable = t; } } - if (!isOutputStreamEncrypt) { try { if (writeExcel) { @@ -293,7 +292,6 @@ public class WriteContextImpl implements WriteContext { throwable = t; } } - try { Workbook workbook = writeWorkbookHolder.getWorkbook(); if (workbook instanceof SXSSFWorkbook) { @@ -302,7 +300,6 @@ public class WriteContextImpl implements WriteContext { } catch (Throwable t) { throwable = t; } - try { if (writeWorkbookHolder.getAutoCloseStream() && writeWorkbookHolder.getOutputStream() != null) { writeWorkbookHolder.getOutputStream().close(); @@ -310,7 +307,6 @@ public class WriteContextImpl implements WriteContext { } catch (Throwable t) { throwable = t; } - if (writeExcel && !isOutputStreamEncrypt) { try { doFileEncrypt07(); @@ -318,7 +314,6 @@ public class WriteContextImpl implements WriteContext { throwable = t; } } - try { if (writeWorkbookHolder.getTempTemplateInputStream() != null) { writeWorkbookHolder.getTempTemplateInputStream().close(); @@ -326,15 +321,11 @@ public class WriteContextImpl implements WriteContext { } catch (Throwable t) { throwable = t; } - clearEncrypt03(); - removeThreadLocalCache(); - if (throwable != null) { throw new ExcelGenerateException("Can not close IO.", throwable); } - if (LOGGER.isDebugEnabled()) { LOGGER.debug("Finished write."); } diff --git a/src/main/java/com/alibaba/excel/context/XlsReadContext.java b/src/main/java/com/alibaba/excel/context/XlsReadContext.java new file mode 100644 index 0000000..a96009b --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/XlsReadContext.java @@ -0,0 +1,11 @@ +package com.alibaba.excel.context; + +/** + * + * A context is the main anchorage point of a ls xls reader. + * + * @author Jiaju Zhuang + */ +public interface XlsReadContext extends AnalysisContext { + +} diff --git a/src/main/java/com/alibaba/excel/enums/ExtraReadEnum.java b/src/main/java/com/alibaba/excel/enums/ExtraReadEnum.java new file mode 100644 index 0000000..2dee2bf --- /dev/null +++ b/src/main/java/com/alibaba/excel/enums/ExtraReadEnum.java @@ -0,0 +1,13 @@ +package com.alibaba.excel.enums; + +/** + * Read some extra data + * + * @author Jiaju Zhuang + **/ +public enum ExtraReadEnum { + /** + * Read the comment + */ + COMMENT,; +} diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java b/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java index 5840046..66df25b 100644 --- a/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java +++ b/src/main/java/com/alibaba/excel/metadata/AbstractParameterBuilder.java @@ -89,5 +89,10 @@ public abstract class AbstractParameterBuilder extraReadSet; /** * The default is all excel objects.Default is true. *

@@ -212,4 +220,12 @@ public class ReadWorkbook extends ReadBasicParameter { public void setUseDefaultListener(Boolean useDefaultListener) { this.useDefaultListener = useDefaultListener; } + + public Set getExtraReadSet() { + return extraReadSet; + } + + public void setExtraReadSet(Set extraReadSet) { + this.extraReadSet = extraReadSet; + } } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java index 24079f7..9916015 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java @@ -3,10 +3,6 @@ package com.alibaba.excel.read.metadata.holder; import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.Holder; -import com.alibaba.excel.util.CollectionUtils; - -import java.util.HashMap; -import java.util.Map; /** * sheet holder @@ -28,34 +24,6 @@ public class ReadRowHolder implements Holder { */ private GlobalConfiguration globalConfiguration; - /** - * Return row comments - * key: col index - * value: comments - */ - private Map rowComments; - - public Map getRowComments() { - return rowComments; - } - - public void setRowComments(Map rowComments) { - this.rowComments = rowComments; - } - - public void addComments(Integer index, String comments) { - this.rowComments = this.rowComments == null ? new HashMap(8) : this.rowComments; - this.rowComments.put(index, comments); - } - - public String getComments(Integer index) { - if (CollectionUtils.isEmpty(rowComments)) { - return null; - } else { - return rowComments.get(index); - } - } - public ReadRowHolder(Integer rowIndex, GlobalConfiguration globalConfiguration) { this.rowIndex = rowIndex; this.globalConfiguration = globalConfiguration; diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java index cbda93f..c03edf2 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java @@ -16,6 +16,7 @@ import com.alibaba.excel.cache.selector.EternalReadCacheSelector; import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.cache.selector.SimpleReadCacheSelector; import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.enums.ExtraReadEnum; import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.exception.ExcelAnalysisException; @@ -96,6 +97,12 @@ public class ReadWorkbookHolder extends AbstractReadHolder { * @see SAXParserFactory#newInstance(String, ClassLoader) */ private String xlsxSAXParserFactoryName; + /** + * Read some additional fields. None are read by default. + * + * @see ExtraReadEnum + */ + private Set extraReadSet; /** * The default is all excel objects.if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a * field. if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed. @@ -155,9 +162,7 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.autoCloseStream = readWorkbook.getAutoCloseStream(); } - // The type of excel is read according to the judgment.Because encrypted XLSX needs to be specified as XLS to - // properly parse. - this.excelType = ExcelTypeEnum.valueOf(file, inputStream, readWorkbook.getExcelType()); + this.excelType = readWorkbook.getExcelType(); if (ExcelTypeEnum.XLS == excelType && getGlobalConfiguration().getUse1904windowing() == null) { getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); @@ -186,6 +191,11 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.defaultReturnMap = readWorkbook.getDefaultReturnMap(); } this.xlsxSAXParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName(); + if (readWorkbook.getExtraReadSet() == null) { + this.extraReadSet = new HashSet(); + } else { + this.extraReadSet = readWorkbook.getExtraReadSet(); + } this.hasReadSheet = new HashSet(); this.ignoreRecord03 = Boolean.FALSE; this.password = readWorkbook.getPassword(); @@ -343,6 +353,14 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.xlsxSAXParserFactoryName = xlsxSAXParserFactoryName; } + public Set getExtraReadSet() { + return extraReadSet; + } + + public void setExtraReadSet(Set extraReadSet) { + this.extraReadSet = extraReadSet; + } + @Override public HolderEnum holderType() { return HolderEnum.WORKBOOK; diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java index 733005c..e7d8def 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java @@ -1,16 +1,16 @@ package com.alibaba.easyexcel.test.demo.read; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.exception.ExcelDataConvertException; -import com.alibaba.excel.util.CollectionUtils; import com.alibaba.fastjson.JSON; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; /** * 读取单元格的批注 @@ -37,7 +37,7 @@ public class DemoCellCommentsListener extends AnalysisEventListener { public void onException(Exception exception, AnalysisContext context) { LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage()); if (exception instanceof ExcelDataConvertException) { - ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception; + ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(), excelDataConvertException.getColumnIndex()); } @@ -50,15 +50,7 @@ public class DemoCellCommentsListener extends AnalysisEventListener { * @param context */ @Override - public void invokeHeadMap(Map headMap, AnalysisContext context) { - Map rowComments = context.readRowHolder().getRowComments(); - LOGGER.info("解析到一条头数据:{}", JSON.toJSONString(headMap)); - if (!CollectionUtils.isEmpty(rowComments)) { - for (Integer i : rowComments.keySet()) { - LOGGER.info("解析到头数据低{}列包含批注:{}", i, rowComments.get(i)); - } - } - } + public void invokeHeadMap(Map headMap, AnalysisContext context) {} @Override public void invoke(DemoData data, AnalysisContext context) { diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java new file mode 100644 index 0000000..bcb1d99 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java @@ -0,0 +1,34 @@ +package com.alibaba.easyexcel.test.temp.read; + +import java.io.File; +import java.util.List; +import java.util.Map; + +import org.junit.Ignore; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.fastjson.JSON; + +/** + * 临时测试 + * + * @author Jiaju Zhuang + **/ +@Ignore +public class CommentTest { + private static final Logger LOGGER = LoggerFactory.getLogger(CommentTest.class); + + @Test + public void comment() throws Exception { + File file = new File("D:\\test\\comment.xls"); + List> datas = EasyExcel.read(file).sheet(0).doReadSync(); + for (Map data : datas) { + LOGGER.info("数据:{}", JSON.toJSONString(data.get(0))); + } + } + +} diff --git a/update.md b/update.md index 1d7c6a1..0968528 100644 --- a/update.md +++ b/update.md @@ -3,6 +3,8 @@ * 降低Ehcache版本 3.7.1(jkd7) -> 3.4.0(jdk6) * 修复xls 用Map接收时多次接收会是同一个对象的bug * 修复浮点型数据导入到excel 会丢失精度的bug +* 新增支持接收批注 + # 2.1.4 * 新增参数`useDefaultListener` 可以排除默认对象转换 From f0d9051db20c8b26bec981d926e2ffddc887ed4a Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Fri, 27 Dec 2019 17:04:44 +0800 Subject: [PATCH 09/38] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E6=89=B9=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v03/AbstractXlsRecordHandler.java | 39 ----- .../v03/IgnorableXlsRecordHandler.java | 8 + .../analysis/v03/XlsListSheetListener.java | 4 +- .../excel/analysis/v03/XlsRecordHandler.java | 49 +----- .../excel/analysis/v03/XlsSaxAnalyser.java | 139 ++++++++-------- .../handlers/BlankOrErrorRecordHandler.java | 52 ------ .../v03/handlers/BlankRecordHandler.java | 22 +++ .../v03/handlers/BofRecordHandler.java | 122 +++++--------- .../v03/handlers/BoolErrRecordHandler.java | 25 +++ .../v03/handlers/BoundSheetRecordHandler.java | 21 +++ .../handlers/DummyRecordRecordHandler.java | 36 +++++ .../v03/handlers/EofRecordHandler.java | 21 +++ .../v03/handlers/FormulaRecordHandler.java | 133 +++++----------- .../v03/handlers/IndexRecordHandler.java | 28 +--- .../v03/handlers/LabelRecordHandler.java | 33 +--- .../v03/handlers/LabelSSTRecordHandler.java | 38 +++++ .../MissingCellDummyRecordHandler.java | 43 ----- .../v03/handlers/NoteRecordHandler.java | 40 ++--- .../v03/handlers/NumberRecordHandler.java | 47 ++---- .../v03/handlers/ObjRecordHandler.java | 30 ++++ .../v03/handlers/RkRecordHandler.java | 32 +--- .../v03/handlers/SstRecordHandler.java | 44 +----- .../v03/handlers/StringRecordHandler.java | 33 ++++ .../v03/handlers/TextObjectRecordHandler.java | 37 ++--- .../excel/analysis/v07/XlsxRowHandler.java | 4 +- .../com/alibaba/excel/cache/XlsCache.java | 37 +++++ .../excel/context/AnalysisContext.java | 37 +++++ .../excel/context/AnalysisContextImpl.java | 12 ++ .../excel/context/DefaultXlsReadContext.java | 110 +++++++++++++ .../alibaba/excel/context/XlsReadContext.java | 84 ++++++++++ .../com/alibaba/excel/enums/RowTypeEnum.java | 21 +++ .../alibaba/excel/metadata/AbstractCell.java | 33 ++++ .../java/com/alibaba/excel/metadata/Cell.java | 22 +++ .../com/alibaba/excel/metadata/CellData.java | 38 ++++- .../com/alibaba/excel/metadata/CellExtra.java | 12 +- .../listener/ReadListenerRegistryCenter.java | 39 ----- .../listener/event/AnalysisFinishEvent.java | 20 --- .../event/EachRowAnalysisFinishEvent.java | 21 --- .../metadata/holder/AbstractReadHolder.java | 133 +--------------- .../read/metadata/holder/ReadRowHolder.java | 32 +++- .../metadata/holder/ReadWorkbookHolder.java | 15 -- .../processor/AnalysisEventProcessor.java | 26 +++ .../DefalutAnalysisEventProcessor.java | 149 ++++++++++++++++++ .../com/alibaba/excel/util/SheetUtils.java | 18 +-- update.md | 1 + 45 files changed, 1070 insertions(+), 870 deletions(-) delete mode 100644 src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/IgnorableXlsRecordHandler.java delete mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSSTRecordHandler.java delete mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/cache/XlsCache.java create mode 100644 src/main/java/com/alibaba/excel/enums/RowTypeEnum.java create mode 100644 src/main/java/com/alibaba/excel/metadata/AbstractCell.java create mode 100644 src/main/java/com/alibaba/excel/metadata/Cell.java delete mode 100644 src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java delete mode 100644 src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java delete mode 100644 src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java create mode 100644 src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java create mode 100644 src/main/java/com/alibaba/excel/read/processor/DefalutAnalysisEventProcessor.java diff --git a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java deleted file mode 100644 index 0deba91..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v03/AbstractXlsRecordHandler.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.alibaba.excel.analysis.v03; - -import com.alibaba.excel.context.XlsReadContext; -import com.alibaba.excel.metadata.CellData; - -/** - * - * @author Dan Zheng - */ -public abstract class AbstractXlsRecordHandler implements XlsRecordHandler { - protected int row = -1; - protected int column = -1; - protected CellData cellData; - protected XlsReadContext analysisContext; - - public AbstractXlsRecordHandler(XlsReadContext analysisContext) { - this.analysisContext = analysisContext; - } - - @Override - public int getRow() { - return row; - } - - @Override - public int getColumn() { - return column; - } - - @Override - public CellData getCellData() { - return cellData; - } - - @Override - public int compareTo(XlsRecordHandler o) { - return this.getOrder() - o.getOrder(); - } -} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/IgnorableXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/IgnorableXlsRecordHandler.java new file mode 100644 index 0000000..cb7e4a8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/IgnorableXlsRecordHandler.java @@ -0,0 +1,8 @@ +package com.alibaba.excel.analysis.v03; + +/** + * Need to ignore the current handler without reading the current sheet. + * + * @author Jiaju Zhuang + */ +public interface IgnorableXlsRecordHandler extends XlsRecordHandler {} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java index bc93731..906b377 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java @@ -25,9 +25,10 @@ import com.alibaba.excel.read.metadata.ReadSheet; */ public class XlsListSheetListener implements HSSFListener { private POIFSFileSystem poifsFileSystem; - private List sheetList; private BofRecordHandler bofRecordHandler; + private static fin + public XlsListSheetListener(XlsReadContext analysisContext, POIFSFileSystem poifsFileSystem) { this.poifsFileSystem = poifsFileSystem; sheetList = new ArrayList(); @@ -49,7 +50,6 @@ public class XlsListSheetListener implements HSSFListener { EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); request.addListenerForAllRecords(workbookBuildingListener); - try { factory.processWorkbookEvents(request, poifsFileSystem); } catch (IOException e) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java index b786bcb..fca15b5 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java @@ -2,60 +2,19 @@ package com.alibaba.excel.analysis.v03; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.context.XlsReadContext; /** * Intercepts handle xls reads. * * @author Dan Zheng */ -public interface XlsRecordHandler extends Comparable { - /** - * Which tags are supported - * - * @param record - * Excel analysis record - * @return Which tags are supported - */ - boolean support(Record record); - - /** - * Initialize - */ - void init(); - +public interface XlsRecordHandler { /** * Processing record * + * @param xlsReadContext * @param record */ - void processRecord(Record record); - - /** - * Get row - * - * @return Row index - */ - int getRow(); - - /** - * Get column - * - * @return Column index - */ - int getColumn(); - - /** - * Get value - * - * @return Excel internal cell data - */ - CellData getCellData(); - - /** - * Get order - * - * @return Order - */ - int getOrder(); + void processRecord(XlsReadContext xlsReadContext, Record record); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index edd763e..68b0c47 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -3,7 +3,7 @@ package com.alibaba.excel.analysis.v03; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; -import java.util.LinkedHashMap; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -15,15 +15,16 @@ import org.apache.poi.hssf.eventusermodel.HSSFRequest; import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.poifs.filesystem.POIFSFileSystem; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.ExcelReadExecutor; import com.alibaba.excel.analysis.v03.handlers.BlankOrErrorRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.BlankRecordHandler; import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler; import com.alibaba.excel.analysis.v03.handlers.FormulaRecordHandler; import com.alibaba.excel.analysis.v03.handlers.IndexRecordHandler; @@ -60,44 +61,56 @@ import com.alibaba.excel.util.CollectionUtils; */ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class); - + // + // private Boolean readAll; + // private List readSheetList; + // /** + // * For parsing Formulas + // */ + // private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; + // private FormatTrackingHSSFListener formatListener; + // private List sheets; + // private HSSFWorkbook stubWorkbook; + // private Map recordHandlerMap; + private XlsReadContext xlsReadContext; private POIFSFileSystem poifsFileSystem; - private Boolean readAll; - private List readSheetList; - private int lastRowNumber; - private int lastColumnNumber; - private int ii = 0; - - /** - * For parsing Formulas - */ - private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; - private FormatTrackingHSSFListener formatListener; - private Map records; - private List sheets; - private HSSFWorkbook stubWorkbook; - private List recordHandlers = new ArrayList(); - private XlsReadContext analysisContext; - - public XlsSaxAnalyser(XlsReadContext context, POIFSFileSystem poifsFileSystem) { - this.analysisContext = context; - this.records = new LinkedHashMap(); + + private static final Map XLS_RECORD_HANDLER_MAP = new HashMap(32); + + static { + XLS_RECORD_HANDLER_MAP.put(BlankRecord.sid, new BlankRecordHandler()); + } + + public XlsSaxAnalyser(XlsReadContext xlsReadContext, POIFSFileSystem poifsFileSystem) { + this.xlsReadContext = xlsReadContext; this.poifsFileSystem = poifsFileSystem; - analysisContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem); + xlsReadContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem); } @Override public List sheetList() { - if (sheets == null) { + if (xlsReadContext.readSheetDataList() == null) { + earlySheetDataList(); + LOGGER.warn("Getting the 'sheetList' before reading will cause the file to be read twice."); - XlsListSheetListener xlsListSheetListener = new XlsListSheetListener(analysisContext, poifsFileSystem); - sheets = xlsListSheetListener.getSheetList(); + XlsListSheetListener xlsListSheetListener = new XlsListSheetListener(xlsReadContext, poifsFileSystem); } - return sheets; + return xlsReadContext.readSheetDataList(); + } + + private void earlySheetDataList() { + LOGGER.warn("Getting the 'sheetList' before reading will cause the file to be read twice."); + + sheetList = new ArrayList(); + bofRecordHandler = new BofRecordHandler(analysisContext, sheetList, false, false); + bofRecordHandler.init(); + bofRecordHandler.init(null, true); + + XlsListSheetListener xlsListSheetListener = new XlsListSheetListener(xlsReadContext, poifsFileSystem); } @Override - public void execute(List readSheetList, Boolean readAll) { + public void execute() { this.readAll = readAll; this.readSheetList = readSheetList; MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); @@ -116,24 +129,27 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { throw new ExcelAnalysisException(e); } // Sometimes tables lack the end record of the last column - if (!records.isEmpty()) { + if (!xlsReadContext.cellMap().isEmpty()) { endRow(); } } private void init() { - lastRowNumber = 0; - lastColumnNumber = 0; - records = new LinkedHashMap(); + recordHandlerMap = new HashMap(32); + buildXlsRecordHandlers(); + } @Override public void processRecord(Record record) { - // Not data from the current sheet - if (ignoreRecord(record)) { + XlsRecordHandler handler = recordHandlerMap.get(record.getSid()); + if ((handler instanceof IgnorableXlsRecordHandler) && xlsReadContext.readWorkbookHolder().getIgnoreRecord03()) { + // No need to read the current sheet return; } + handler.processRecord(xlsReadContext, record); + int thisRow = -1; int thisColumn = -1; CellData cellData = null; @@ -153,69 +169,52 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { } } // If we got something to print out, do so - if (cellData != null && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim() + if (cellData != null && xlsReadContext.currentReadHolder().globalConfiguration().getAutoTrim() && CellDataTypeEnum.STRING == cellData.getType()) { cellData.setStringValue(cellData.getStringValue().trim()); } - // Handle new row - if (thisRow != -1 && thisRow != lastRowNumber) { - lastColumnNumber = -1; - } - - // Update column and row count - if (thisRow > -1) { - lastRowNumber = thisRow; - } - if (thisColumn > -1) { - lastColumnNumber = thisColumn; - } - processLastCellOfRow(record); } private boolean ignoreRecord(Record record) { - return analysisContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid + return xlsReadContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid && record.getSid() != BOFRecord.sid; } private void processLastCellOfRow(Record record) { // Handle end of row if (record instanceof LastCellOfRowDummyRecord) { + System.out.println("----" + record.getSid()); endRow(); } } private void endRow() { - if (lastColumnNumber == -1) { - lastColumnNumber = 0; - } - analysisContext.readRowHolder( - new ReadRowHolder(lastRowNumber, analysisContext.readSheetHolder().getGlobalConfiguration())); - analysisContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), analysisContext); - this.records = new LinkedHashMap(); - lastColumnNumber = -1; + xlsReadContext + .readRowHolder(new ReadRowHolder(lastRowNumber, xlsReadContext.readSheetHolder().getGlobalConfiguration())); + xlsReadContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), xlsReadContext); } private void buildXlsRecordHandlers() { if (CollectionUtils.isEmpty(recordHandlers)) { - recordHandlers.add(new BlankOrErrorRecordHandler(analysisContext)); + recordHandlers.add(new BlankOrErrorRecordHandler(xlsReadContext)); // The table has been counted and there are no duplicate statistics if (sheets == null) { sheets = new ArrayList(); - recordHandlers.add(new BofRecordHandler(analysisContext, sheets, false, true)); + recordHandlers.add(new BofRecordHandler(xlsReadContext, sheets, false, true)); } else { - recordHandlers.add(new BofRecordHandler(analysisContext, sheets, true, true)); + recordHandlers.add(new BofRecordHandler(xlsReadContext, sheets, true, true)); } - recordHandlers.add(new FormulaRecordHandler(analysisContext, stubWorkbook, formatListener)); - recordHandlers.add(new LabelRecordHandler(analysisContext)); - recordHandlers.add(new NoteRecordHandler(analysisContext)); - recordHandlers.add(new NumberRecordHandler(analysisContext, formatListener)); - recordHandlers.add(new RkRecordHandler(analysisContext)); - recordHandlers.add(new SstRecordHandler(analysisContext)); - recordHandlers.add(new MissingCellDummyRecordHandler(analysisContext)); - recordHandlers.add(new IndexRecordHandler(analysisContext)); - recordHandlers.add(new TextObjectRecordHandler(analysisContext)); + recordHandlers.add(new FormulaRecordHandler(xlsReadContext, stubWorkbook, formatListener)); + recordHandlers.add(new LabelRecordHandler(xlsReadContext)); + recordHandlers.add(new NoteRecordHandler(xlsReadContext)); + recordHandlers.add(new NumberRecordHandler(xlsReadContext, formatListener)); + recordHandlers.add(new RkRecordHandler(xlsReadContext)); + recordHandlers.add(new SstRecordHandler(xlsReadContext)); + recordHandlers.add(new MissingCellDummyRecordHandler(xlsReadContext)); + recordHandlers.add(new IndexRecordHandler(xlsReadContext)); + recordHandlers.add(new TextObjectRecordHandler(xlsReadContext)); Collections.sort(recordHandlers); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java deleted file mode 100644 index 686ffb0..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankOrErrorRecordHandler.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.alibaba.excel.analysis.v03.handlers; - -import org.apache.poi.hssf.record.BlankRecord; -import org.apache.poi.hssf.record.BoolErrRecord; -import org.apache.poi.hssf.record.Record; - -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; -import com.alibaba.excel.enums.CellDataTypeEnum; -import com.alibaba.excel.metadata.CellData; - -/** - * Record handler - * - * @author Dan Zheng - */ -public class BlankOrErrorRecordHandler extends AbstractXlsRecordHandler { - - public BlankOrErrorRecordHandler(XlsReadContext analysisContext) { - super(analysisContext); - } - - @Override - public boolean support(Record record) { - return BlankRecord.sid == record.getSid() || BoolErrRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { - if (record.getSid() == BlankRecord.sid) { - BlankRecord br = (BlankRecord)record; - this.row = br.getRow(); - this.column = br.getColumn(); - this.cellData = new CellData(CellDataTypeEnum.EMPTY); - } else if (record.getSid() == BoolErrRecord.sid) { - BoolErrRecord ber = (BoolErrRecord)record; - this.row = ber.getRow(); - this.column = ber.getColumn(); - this.cellData = new CellData(ber.getBooleanValue()); - } - } - - @Override - public void init() { - - } - - @Override - public int getOrder() { - return 0; - } -} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java new file mode 100644 index 0000000..24d9905 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java @@ -0,0 +1,22 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.BlankRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class BlankRecordHandler implements IgnorableXlsRecordHandler { + + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + BlankRecord br = (BlankRecord)record; + xlsReadContext.cellMap().put((int)br.getColumn(), CellData.newEmptyInstance(br.getRow(), (int)br.getColumn())); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java index af1a2b4..5137d18 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -7,8 +7,9 @@ import org.apache.poi.hssf.record.BOFRecord; import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.XlsRecordHandler; import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.util.SheetUtils; @@ -17,91 +18,52 @@ import com.alibaba.excel.util.SheetUtils; * * @author Dan Zheng */ -public class BofRecordHandler extends AbstractXlsRecordHandler { - private List boundSheetRecords = new ArrayList(); - private BoundSheetRecord[] orderedBsrs; - private int sheetIndex; - private List sheets; - private Boolean readAll; - private List readSheetList; - private boolean alreadyInit; - private boolean needInitSheet; - - public BofRecordHandler(XlsReadContext analysisContext, List sheets, boolean alreadyInit, - boolean needInitSheet) { - super(analysisContext); - this.sheets = sheets; - this.alreadyInit = alreadyInit; - this.needInitSheet = needInitSheet; - } +public class BofRecordHandler implements XlsRecordHandler { @Override - public boolean support(Record record) { - return BoundSheetRecord.sid == record.getSid() || BOFRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { - if (record.getSid() == BoundSheetRecord.sid) { - boundSheetRecords.add((BoundSheetRecord)record); - } else if (record.getSid() == BOFRecord.sid) { - BOFRecord br = (BOFRecord)record; - if (br.getType() == BOFRecord.TYPE_WORKSHEET) { - if (orderedBsrs == null) { - orderedBsrs = BoundSheetRecord.orderByBofPosition(boundSheetRecords); - } - String sheetName = orderedBsrs[sheetIndex].getSheetname(); - // Find the currently read sheet - ReadSheet readSheet = null; - if (!alreadyInit) { - readSheet = new ReadSheet(sheetIndex, sheetName); - sheets.add(readSheet); - } - if (needInitSheet) { - if (readSheet == null) { - for (ReadSheet sheet : sheets) { - if (sheet.getSheetNo() == sheetIndex) { - readSheet = sheet; - break; - } - } - } - assert readSheet != null : "Can't find the sheet."; - analysisContext.readWorkbookHolder().setIgnoreRecord03(Boolean.TRUE); - // Copy the parameter to the current sheet - readSheet = SheetUtils.match(readSheet, readSheetList, readAll, - analysisContext.readWorkbookHolder().getGlobalConfiguration()); - if (readSheet != null) { - if (readSheet.getSheetNo() != 0 && analysisContext.readSheetHolder() != null) { - // Prompt for the end of the previous form read - analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext); - } - analysisContext.currentSheet(readSheet); - analysisContext.readWorkbookHolder().setIgnoreRecord03(Boolean.FALSE); - } - } - sheetIndex++; - } + public void processRecord(XlsReadContext xlsReadContext, Record record) { + BOFRecord br = (BOFRecord)record; + if (br.getType() != BOFRecord.TYPE_WORKSHEET) { + return; } - } - - @Override - public void init() { - sheetIndex = 0; - orderedBsrs = null; - boundSheetRecords.clear(); - if (!alreadyInit) { - sheets.clear(); + // Init read sheet Data + initReadSheetDataList(xlsReadContext); + Integer readSheetIndex = xlsReadContext.readSheetIndex(); + if (readSheetIndex == null) { + readSheetIndex = 0; + xlsReadContext.readSheetIndex(readSheetIndex); } - } - public void init(List readSheetList, Boolean readAll) { - this.readSheetList = readSheetList; - this.readAll = readAll; + ReadSheet readSheet = xlsReadContext.readSheetDataList().get(readSheetIndex); + assert readSheet != null : "Can't find the sheet."; + // Copy the parameter to the current sheet + readSheet = SheetUtils.match(readSheet, xlsReadContext); + if (readSheet != null) { + xlsReadContext.currentSheet0(readSheet); + xlsReadContext.ignoreRecord(Boolean.FALSE); + } else { + xlsReadContext.ignoreRecord(Boolean.TRUE); + } + // Go read the next one + xlsReadContext.readSheetIndex(xlsReadContext.readSheetIndex() + 1); } - @Override - public int getOrder() { - return 0; + private void initReadSheetDataList(XlsReadContext xlsReadContext) { + if (xlsReadContext.readSheetDataList() != null) { + return; + } + BoundSheetRecord[] boundSheetRecords = + BoundSheetRecord.orderByBofPosition(xlsReadContext.boundSheetRecordList()); + List readSheetDataList = new ArrayList(); + for (int i = 0; i < boundSheetRecords.length; i++) { + BoundSheetRecord boundSheetRecord = boundSheetRecords[i]; + ReadSheet readSheet = new ReadSheet(i, boundSheetRecord.getSheetname()); + readSheetDataList.add(readSheet); + } + xlsReadContext.readSheetDataList(readSheetDataList); + // Just need to get the list of sheets + if (!xlsReadContext.needReadSheet()) { + throw new ExcelAnalysisStopException("Just need to get the list of sheets."); + } } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java new file mode 100644 index 0000000..27d521c --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java @@ -0,0 +1,25 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.BoolErrRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class BoolErrRecordHandler implements IgnorableXlsRecordHandler { + + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + BoolErrRecord ber = (BoolErrRecord)record; + xlsReadContext.cellMap().put((int)ber.getColumn(), + CellData.newInstance(ber.getBooleanValue(), ber.getRow(), (int)ber.getColumn())); + xlsReadContext.tempRowType(RowTypeEnum.DATA); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java new file mode 100644 index 0000000..809d7fd --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.BoundSheetRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class BoundSheetRecordHandler implements IgnorableXlsRecordHandler { + + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + BoundSheetRecord bsr = (BoundSheetRecord)record; + xlsReadContext.boundSheetRecordList().add((BoundSheetRecord)record); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordRecordHandler.java new file mode 100644 index 0000000..53d4d35 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordRecordHandler.java @@ -0,0 +1,36 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import java.util.LinkedHashMap; + +import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; +import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.metadata.Cell; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class DummyRecordRecordHandler implements IgnorableXlsRecordHandler { + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + if (record instanceof LastCellOfRowDummyRecord) { + // End of this row + LastCellOfRowDummyRecord lcrdr = (LastCellOfRowDummyRecord)record; + xlsReadContext.rowIndex(lcrdr.getRow()); + xlsReadContext.readRowHolder(new ReadRowHolder(lcrdr.getRow(), xlsReadContext.tempRowType(), + xlsReadContext.readSheetHolder().getGlobalConfiguration())); + xlsReadContext.analysisEventProcessor().endRow(xlsReadContext); + xlsReadContext.cellMap(new LinkedHashMap()); + } else if (record instanceof MissingCellDummyRecord) { + MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record; + xlsReadContext.cellMap().put(mcdr.getColumn(), CellData.newEmptyInstance(mcdr.getRow(), mcdr.getColumn())); + } + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java new file mode 100644 index 0000000..9efe988 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class EofRecordHandler implements IgnorableXlsRecordHandler { + + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + if (xlsReadContext.readSheetHolder() != null) { + xlsReadContext.analysisEventProcessor().endSheet(xlsReadContext); + } + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java index b19e36d..261b7e1 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -2,17 +2,14 @@ package com.alibaba.excel.analysis.v03.handlers; import java.math.BigDecimal; -import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.record.FormulaRecord; import org.apache.poi.hssf.record.Record; -import org.apache.poi.hssf.record.StringRecord; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.CellType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -22,97 +19,51 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class FormulaRecordHandler extends AbstractXlsRecordHandler { +public class FormulaRecordHandler implements IgnorableXlsRecordHandler { private static final Logger LOGGER = LoggerFactory.getLogger(FormulaRecordHandler.class); - private static final String ERROR = "#VALUE!"; - private int nextRow; - private int nextColumn; - private boolean outputNextStringRecord; - private CellData tempCellData; - private FormatTrackingHSSFListener formatListener; - private HSSFWorkbook stubWorkbook; - - public FormulaRecordHandler(XlsReadContext analysisContext, HSSFWorkbook stubWorkbook, - FormatTrackingHSSFListener formatListener) { - super(analysisContext); - this.stubWorkbook = stubWorkbook; - this.formatListener = formatListener; - } @Override - public boolean support(Record record) { - return FormulaRecord.sid == record.getSid() || StringRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { - if (record.getSid() == FormulaRecord.sid) { - FormulaRecord frec = (FormulaRecord)record; - this.row = frec.getRow(); - this.column = frec.getColumn(); - CellType cellType = CellType.forInt(frec.getCachedResultType()); - String formulaValue = null; - try { - formulaValue = HSSFFormulaParser.toFormulaString(stubWorkbook, frec.getParsedExpression()); - } catch (Exception e) { - LOGGER.warn("Get formula value error.{}", e.getMessage()); - } - switch (cellType) { - case STRING: - // Formula result is a string - // This is stored in the next record - outputNextStringRecord = true; - nextRow = frec.getRow(); - nextColumn = frec.getColumn(); - tempCellData = new CellData(CellDataTypeEnum.STRING); - tempCellData.setFormula(Boolean.TRUE); - tempCellData.setFormulaValue(formulaValue); - break; - case NUMERIC: - this.cellData = new CellData(BigDecimal.valueOf(frec.getValue())); - this.cellData.setFormula(Boolean.TRUE); - this.cellData.setFormulaValue(formulaValue); - break; - case ERROR: - this.cellData = new CellData(CellDataTypeEnum.ERROR); - this.cellData.setStringValue(ERROR); - this.cellData.setFormula(Boolean.TRUE); - this.cellData.setFormulaValue(formulaValue); - break; - case BOOLEAN: - this.cellData = new CellData(frec.getCachedBooleanValue()); - this.cellData.setFormula(Boolean.TRUE); - this.cellData.setFormulaValue(formulaValue); - break; - default: - this.cellData = new CellData(CellDataTypeEnum.EMPTY); - this.cellData.setFormula(Boolean.TRUE); - this.cellData.setFormulaValue(formulaValue); - break; - } - } else if (record.getSid() == StringRecord.sid) { - if (outputNextStringRecord) { - // String for formula - StringRecord srec = (StringRecord)record; - this.cellData = tempCellData; - this.cellData.setStringValue(srec.getString()); - this.row = nextRow; - this.column = nextColumn; - outputNextStringRecord = false; - tempCellData = null; - } + public void processRecord(XlsReadContext xlsReadContext, Record record) { + FormulaRecord frec = (FormulaRecord)record; + CellData tempCellData = new CellData(); + tempCellData.setRowIndex(frec.getRow()); + tempCellData.setColumnIndex((int)frec.getColumn()); + CellType cellType = CellType.forInt(frec.getCachedResultType()); + String formulaValue = null; + try { + formulaValue = HSSFFormulaParser.toFormulaString(xlsReadContext.hsffWorkbook(), frec.getParsedExpression()); + } catch (Exception e) { + LOGGER.debug("Get formula value error.", e); + } + tempCellData.setFormula(Boolean.TRUE); + tempCellData.setFormulaValue(formulaValue); + switch (cellType) { + case STRING: + // Formula result is a string + // This is stored in the next record + tempCellData.setType(CellDataTypeEnum.STRING); + xlsReadContext.tempCellData(tempCellData); + break; + case NUMERIC: + tempCellData.setType(CellDataTypeEnum.NUMBER); + tempCellData.setNumberValue(BigDecimal.valueOf(frec.getValue())); + xlsReadContext.cellMap().put((int)frec.getColumn(), tempCellData); + break; + case ERROR: + tempCellData.setType(CellDataTypeEnum.ERROR); + tempCellData.setStringValue(ERROR); + xlsReadContext.cellMap().put((int)frec.getColumn(), tempCellData); + break; + case BOOLEAN: + tempCellData.setType(CellDataTypeEnum.BOOLEAN); + tempCellData.setBooleanValue(frec.getCachedBooleanValue()); + xlsReadContext.cellMap().put((int)frec.getColumn(), tempCellData); + break; + default: + tempCellData.setType(CellDataTypeEnum.EMPTY); + xlsReadContext.cellMap().put((int)frec.getColumn(), tempCellData); + break; } - } - - @Override - public void init() { - this.nextRow = 0; - this.nextColumn = 0; - } - - @Override - public int getOrder() { - return 0; } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java index 83105bf..08a5a56 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java @@ -3,7 +3,7 @@ package com.alibaba.excel.analysis.v03.handlers; import org.apache.poi.hssf.record.IndexRecord; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.XlsReadContext; /** @@ -11,30 +11,12 @@ import com.alibaba.excel.context.XlsReadContext; * * @author Jiaju Zhuang */ -public class IndexRecordHandler extends AbstractXlsRecordHandler { - - public IndexRecordHandler(XlsReadContext analysisContext) { - super(analysisContext); - } - - @Override - public boolean support(Record record) { - return record instanceof IndexRecord; - } - +public class IndexRecordHandler implements IgnorableXlsRecordHandler { @Override - public void init() {} - - @Override - public void processRecord(Record record) { - if (analysisContext.readSheetHolder() == null) { + public void processRecord(XlsReadContext xlsReadContext, Record record) { + if (xlsReadContext.readSheetHolder() == null) { return; } - analysisContext.readSheetHolder().setApproximateTotalRowNumber(((IndexRecord)record).getLastRowAdd1()); - } - - @Override - public int getOrder() { - return 1; + xlsReadContext.readSheetHolder().setApproximateTotalRowNumber(((IndexRecord)record).getLastRowAdd1()); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java index 79db34a..93259e6 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java @@ -3,8 +3,9 @@ package com.alibaba.excel.analysis.v03.handlers; import org.apache.poi.hssf.record.LabelRecord; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.CellData; /** @@ -12,32 +13,12 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class LabelRecordHandler extends AbstractXlsRecordHandler { - - public LabelRecordHandler(XlsReadContext analysisContext) { - super(analysisContext); - } - +public class LabelRecordHandler implements IgnorableXlsRecordHandler { @Override - public boolean support(Record record) { - return LabelRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { + public void processRecord(XlsReadContext xlsReadContext, Record record) { LabelRecord lrec = (LabelRecord)record; - this.row = lrec.getRow(); - this.column = lrec.getColumn(); - this.cellData = new CellData(lrec.getValue()); - } - - @Override - public void init() { - - } - - @Override - public int getOrder() { - return 0; + xlsReadContext.cellMap().put((int)lrec.getColumn(), + CellData.newInstance(lrec.getValue(), lrec.getRow(), (int)lrec.getColumn())); + xlsReadContext.tempRowType(RowTypeEnum.DATA); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSSTRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSSTRecordHandler.java new file mode 100644 index 0000000..5e08ff8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSSTRecordHandler.java @@ -0,0 +1,38 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.cache.ReadCache; +import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class LabelSSTRecordHandler implements IgnorableXlsRecordHandler { + + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + LabelSSTRecord lsrec = (LabelSSTRecord)record; + ReadCache readCache = xlsReadContext.readWorkbookHolder().getReadCache(); + if (readCache == null) { + xlsReadContext.cellMap().put((int)lsrec.getColumn(), + CellData.newEmptyInstance(lsrec.getRow(), (int)lsrec.getColumn())); + return; + } + String data = readCache.get(lsrec.getSSTIndex()); + if (data == null) { + xlsReadContext.cellMap().put((int)lsrec.getColumn(), + CellData.newEmptyInstance(lsrec.getRow(), (int)lsrec.getColumn())); + return; + } + xlsReadContext.cellMap().put((int)lsrec.getColumn(), + CellData.newInstance(data, lsrec.getRow(), (int)lsrec.getColumn())); + xlsReadContext.tempRowType(RowTypeEnum.DATA); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java deleted file mode 100644 index f40422a..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MissingCellDummyRecordHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.alibaba.excel.analysis.v03.handlers; - -import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; -import org.apache.poi.hssf.record.Record; - -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; -import com.alibaba.excel.enums.CellDataTypeEnum; -import com.alibaba.excel.metadata.CellData; - -/** - * Record handler - * - * @author Dan Zheng - */ -public class MissingCellDummyRecordHandler extends AbstractXlsRecordHandler { - public MissingCellDummyRecordHandler(XlsReadContext analysisContext) { - super(analysisContext); - } - - @Override - public boolean support(Record record) { - return record instanceof MissingCellDummyRecord; - } - - @Override - public void init() { - - } - - @Override - public void processRecord(Record record) { - MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record; - this.row = mcdr.getRow(); - this.column = mcdr.getColumn(); - this.cellData = new CellData(CellDataTypeEnum.EMPTY); - } - - @Override - public int getOrder() { - return 1; - } -} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java index f63d9ee..255eb98 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java @@ -3,41 +3,27 @@ package com.alibaba.excel.analysis.v03.handlers; import org.apache.poi.hssf.record.NoteRecord; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.XlsReadContext; -import com.alibaba.excel.enums.CellDataTypeEnum; -import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.CellExtra; /** * Record handler * * @author Dan Zheng */ -public class NoteRecordHandler extends AbstractXlsRecordHandler { - public NoteRecordHandler(XlsReadContext analysisContext) { - super(analysisContext); - } - - @Override - public boolean support(Record record) { - return NoteRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { - NoteRecord nrec = (NoteRecord)record; - this.row = nrec.getRow(); - this.column = nrec.getColumn(); - this.cellData = new CellData(CellDataTypeEnum.EMPTY); - } - - @Override - public void init() { - - } +public class NoteRecordHandler implements IgnorableXlsRecordHandler { @Override - public int getOrder() { - return 0; + public void processRecord(XlsReadContext xlsReadContext, Record record) { + NoteRecord nr = (NoteRecord)record; + String note = xlsReadContext.objectCacheMap().get(nr.getShapeId()); + CellExtra cellExtra = new CellExtra(); + cellExtra.setRowIndex(nr.getRow()); + cellExtra.setRowIndex(nr.getColumn()); + cellExtra.setNote(note); + xlsReadContext.cellMap().put(nr.getColumn(), cellExtra); + xlsReadContext.tempRowType(RowTypeEnum.EXTRA); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java index 948cf53..381bacd 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -2,13 +2,13 @@ package com.alibaba.excel.analysis.v03.handlers; import java.math.BigDecimal; -import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.CellData; /** @@ -16,39 +16,18 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class NumberRecordHandler extends AbstractXlsRecordHandler { - private FormatTrackingHSSFListener formatListener; - - public NumberRecordHandler(XlsReadContext analysisContext, FormatTrackingHSSFListener formatListener) { - super(analysisContext); - this.formatListener = formatListener; - } - - @Override - public boolean support(Record record) { - return NumberRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { - NumberRecord numrec = (NumberRecord)record; - this.row = numrec.getRow(); - this.column = numrec.getColumn(); - this.cellData = new CellData(BigDecimal.valueOf(numrec.getValue())); - int dataFormat = formatListener.getFormatIndex(numrec); - this.cellData.setDataFormat(dataFormat); - this.cellData - .setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, formatListener.getFormatString(numrec), - analysisContext.readSheetHolder().getGlobalConfiguration().getLocale())); - } - - @Override - public void init() { - - } +public class NumberRecordHandler implements IgnorableXlsRecordHandler { @Override - public int getOrder() { - return 0; + public void processRecord(XlsReadContext xlsReadContext, Record record) { + NumberRecord nr = (NumberRecord)record; + CellData cellData = CellData.newInstance(BigDecimal.valueOf(nr.getValue()), nr.getRow(), (int)nr.getColumn()); + Integer dataFormat = xlsReadContext.formatTrackingHSSFListener().getFormatIndex(nr); + cellData.setDataFormat(dataFormat); + cellData.setDataFormatString( + BuiltinFormats.getBuiltinFormat(dataFormat, xlsReadContext.formatTrackingHSSFListener().getFormatString(nr), + xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale())); + xlsReadContext.cellMap().put((int)nr.getColumn(), cellData); + xlsReadContext.tempRowType(RowTypeEnum.DATA); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java new file mode 100644 index 0000000..5144a73 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java @@ -0,0 +1,30 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.CommonObjectDataSubRecord; +import org.apache.poi.hssf.record.ObjRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.SubRecord; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; + +/** + * Record handler + * + * @author Jiaju Zhuang + */ +public class ObjRecordHandler implements IgnorableXlsRecordHandler { + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + ObjRecord or = (ObjRecord)record; + for (SubRecord subRecord : or.getSubRecords()) { + if (subRecord instanceof CommonObjectDataSubRecord) { + CommonObjectDataSubRecord codsr = (CommonObjectDataSubRecord)subRecord; + if (CommonObjectDataSubRecord.OBJECT_TYPE_COMMENT == codsr.getObjectType()) { + xlsReadContext.tempObjectIndex(codsr.getObjectId()); + } + break; + } + } + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java index 08e2ac2..cc902ef 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java @@ -3,9 +3,8 @@ package com.alibaba.excel.analysis.v03.handlers; import org.apache.poi.hssf.record.RKRecord; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.XlsReadContext; -import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; /** @@ -13,32 +12,11 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class RkRecordHandler extends AbstractXlsRecordHandler { - public RkRecordHandler(XlsReadContext analysisContext) { - super(analysisContext); - } - - @Override - public boolean support(Record record) { - return RKRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { - RKRecord rkrec = (RKRecord)record; - - this.row = rkrec.getRow(); - this.row = rkrec.getColumn(); - this.cellData = new CellData(CellDataTypeEnum.EMPTY); - } - - @Override - public void init() { - - } +public class RkRecordHandler implements IgnorableXlsRecordHandler { @Override - public int getOrder() { - return 0; + public void processRecord(XlsReadContext xlsReadContext, Record record) { + RKRecord re = (RKRecord)record; + xlsReadContext.cellMap().put((int)re.getColumn(), CellData.newEmptyInstance(re.getRow(), (int)re.getColumn())); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java index 67962bd..7f0f01d 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java @@ -1,54 +1,20 @@ package com.alibaba.excel.analysis.v03.handlers; -import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.SSTRecord; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.cache.XlsCache; import com.alibaba.excel.context.XlsReadContext; -import com.alibaba.excel.enums.CellDataTypeEnum; -import com.alibaba.excel.metadata.CellData; /** * Record handler * * @author Dan Zheng */ -public class SstRecordHandler extends AbstractXlsRecordHandler { - private SSTRecord sstRecord; - - public SstRecordHandler(XlsReadContext analysisContext) { - super(analysisContext); - } - - @Override - public boolean support(Record record) { - return SSTRecord.sid == record.getSid() || LabelSSTRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { - if (record.getSid() == SSTRecord.sid) { - sstRecord = (SSTRecord)record; - } else if (record.getSid() == LabelSSTRecord.sid) { - LabelSSTRecord lsrec = (LabelSSTRecord)record; - this.row = lsrec.getRow(); - this.column = lsrec.getColumn(); - if (sstRecord == null) { - this.cellData = new CellData(CellDataTypeEnum.EMPTY); - } else { - this.cellData = new CellData(sstRecord.getString(lsrec.getSSTIndex()).toString()); - } - } - } - - @Override - public void init() { - - } - +public class SstRecordHandler implements IgnorableXlsRecordHandler { @Override - public int getOrder() { - return 0; + public void processRecord(XlsReadContext xlsReadContext, Record record) { + xlsReadContext.readWorkbookHolder().setReadCache(new XlsCache((SSTRecord)record)); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java new file mode 100644 index 0000000..63e6953 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java @@ -0,0 +1,33 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.Record; +import org.apache.poi.hssf.record.StringRecord; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.metadata.CellData; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class StringRecordHandler implements IgnorableXlsRecordHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(StringRecordHandler.class); + + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + // String for formula + StringRecord srec = (StringRecord)record; + CellData tempCellData = xlsReadContext.tempCellData(); + if (tempCellData == null) { + LOGGER.warn("String type formula but no value found."); + return; + } + tempCellData.setStringValue(srec.getString()); + xlsReadContext.cellMap().put(tempCellData.getColumnIndex(), tempCellData); + xlsReadContext.tempCellData(null); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java index ee502dc..764b69e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java @@ -1,10 +1,11 @@ package com.alibaba.excel.analysis.v03.handlers; -import org.apache.poi.hssf.record.ObjRecord; import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.TextObjectRecord; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -import com.alibaba.excel.analysis.v03.AbstractXlsRecordHandler; +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.XlsReadContext; /** @@ -12,28 +13,18 @@ import com.alibaba.excel.context.XlsReadContext; * * @author Jiaju Zhuang */ -public class TextObjectRecordHandler extends AbstractXlsRecordHandler { - public TextObjectRecordHandler(XlsReadContext analysisContext) { - super(analysisContext); - } - - @Override - public boolean support(Record record) { - return TextObjectRecord.sid == record.getSid() || ObjRecord.sid == record.getSid(); - } - - @Override - public void processRecord(Record record) { - System.out.println(record); - } - - @Override - public void init() { - - } +public class TextObjectRecordHandler implements IgnorableXlsRecordHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(TextObjectRecordHandler.class); @Override - public int getOrder() { - return 0; + public void processRecord(XlsReadContext xlsReadContext, Record record) { + TextObjectRecord tor = (TextObjectRecord)record; + Integer tempObjectIndex = xlsReadContext.tempObjectIndex(); + if (tempObjectIndex == null) { + LOGGER.debug("tempObjectIndex is null."); + return; + } + xlsReadContext.objectCacheMap().put(tempObjectIndex, tor.getStr().getString()); + xlsReadContext.tempObjectIndex(null); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java index b6702c1..bc433cf 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java @@ -2,8 +2,6 @@ package com.alibaba.excel.analysis.v07; import java.util.List; -import com.alibaba.excel.constant.ExcelXmlConstants; -import com.alibaba.excel.util.StringUtils; import org.apache.poi.ss.util.CellAddress; import org.apache.poi.xssf.model.CommentsTable; import org.apache.poi.xssf.model.StylesTable; @@ -12,7 +10,9 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; +import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.util.StringUtils; /** * diff --git a/src/main/java/com/alibaba/excel/cache/XlsCache.java b/src/main/java/com/alibaba/excel/cache/XlsCache.java new file mode 100644 index 0000000..9e814e0 --- /dev/null +++ b/src/main/java/com/alibaba/excel/cache/XlsCache.java @@ -0,0 +1,37 @@ +package com.alibaba.excel.cache; + +import org.apache.poi.hssf.record.SSTRecord; + +import com.alibaba.excel.context.AnalysisContext; + +/** + * + * Use SSTRecord. + * + * @author Jiaju Zhuang + */ +public class XlsCache implements ReadCache { + private SSTRecord sstRecord; + + public XlsCache(SSTRecord sstRecord) { + this.sstRecord = sstRecord; + } + + @Override + public void init(AnalysisContext analysisContext) {} + + @Override + public void put(String value) {} + + @Override + public String get(Integer key) { + return sstRecord.getString(key).toString(); + } + + @Override + public void putFinished() {} + + @Override + public void destroy() {} + +} diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java index 66c69a5..b441459 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContext.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -1,6 +1,7 @@ package com.alibaba.excel.context; import java.io.InputStream; +import java.util.List; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.metadata.Sheet; @@ -9,6 +10,7 @@ import com.alibaba.excel.read.metadata.holder.ReadHolder; import com.alibaba.excel.read.metadata.holder.ReadRowHolder; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; +import com.alibaba.excel.read.processor.AnalysisEventProcessor; import com.alibaba.excel.support.ExcelTypeEnum; /** @@ -69,6 +71,41 @@ public interface AnalysisContext { */ Object getCustom(); + /** + * Event processor + * + * @return + */ + AnalysisEventProcessor analysisEventProcessor(); + + /** + * Data that the customer needs to read + * + * @return + */ + List readSheetList(); + + /** + * Data that the customer needs to read + * + * @return + */ + void readSheetList(List readSheetList); + + /** + * Read all sheets + * + * @return + */ + Boolean readAll(); + + /** + * Read all sheets + * + * @return + */ + void readAll(Boolean readAll); + /** * get current sheet * diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java index e5ded50..9f03bcf 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java @@ -13,6 +13,8 @@ import com.alibaba.excel.read.metadata.holder.ReadHolder; import com.alibaba.excel.read.metadata.holder.ReadRowHolder; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; +import com.alibaba.excel.read.processor.AnalysisEventProcessor; +import com.alibaba.excel.read.processor.DefalutAnalysisEventProcessor; import com.alibaba.excel.support.ExcelTypeEnum; /** @@ -37,6 +39,10 @@ public class AnalysisContextImpl implements AnalysisContext { * Configuration of currently operated cell */ private ReadHolder currentReadHolder; + /** + * Event processor + */ + private AnalysisEventProcessor analysisEventProcessor; public AnalysisContextImpl(ReadWorkbook readWorkbook) { if (readWorkbook == null) { @@ -44,6 +50,7 @@ public class AnalysisContextImpl implements AnalysisContext { } readWorkbookHolder = new ReadWorkbookHolder(readWorkbook); currentReadHolder = readWorkbookHolder; + analysisEventProcessor = new DefalutAnalysisEventProcessor(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Initialization 'AnalysisContextImpl' complete"); } @@ -92,6 +99,11 @@ public class AnalysisContextImpl implements AnalysisContext { return readWorkbookHolder.getCustomObject(); } + @Override + public AnalysisEventProcessor analysisEventProcessor() { + return analysisEventProcessor; + } + @Override public Sheet getCurrentSheet() { Sheet sheet = new Sheet(readSheetHolder.getSheetNo() + 1); diff --git a/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java b/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java index 3f7da09..9487859 100644 --- a/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java +++ b/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java @@ -1,5 +1,17 @@ package com.alibaba.excel.context; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.apache.poi.hssf.record.BoundSheetRecord; + +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.Cell; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.CellExtra; +import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadWorkbook; /** @@ -9,8 +21,106 @@ import com.alibaba.excel.read.metadata.ReadWorkbook; * @author Jiaju Zhuang */ public class DefaultXlsReadContext extends AnalysisContextImpl implements XlsReadContext { + private Map cellMap; + private RowTypeEnum rowType; + private Integer rowIndex; + private CellData cellData; + private CellExtra cellExtra; + /** + * Excel 2003 cannot read specific sheet. It can only read sheet by sheet.So when you specify one sheet, you ignore + * the others. + */ + private Boolean ignoreRecord; + + /** + * Bound sheet record + * + * @return + */ + List boundSheetRecordList; public DefaultXlsReadContext(ReadWorkbook readWorkbook) { super(readWorkbook); + cellMap = new LinkedHashMap(); + rowType = RowTypeEnum.EMPTY; + boundSheetRecordList = new ArrayList(); + } + + @Override + public RowTypeEnum rowType() { + return null; + } + + @Override + public void rowType(RowTypeEnum rowType) { + + } + + @Override + public RowTypeEnum tempRowType() { + return null; + } + + @Override + public void tempRowType(RowTypeEnum tempRowType) { + + } + + @Override + public CellData cellData() { + return null; + } + + @Override + public void cellData(CellData cellData) { + + } + + @Override + public CellExtra cellExtra() { + return null; + } + + @Override + public void cellExtra(CellExtra cellExtra) { + + } + + @Override + public Map cellMap() { + return null; + } + + @Override + public void cellMap(Map cellMap) { + + } + + @Override + public Integer rowIndex() { + return null; + } + + @Override + public void rowIndex(Integer rowIndex) { + + } + + @Override + public Boolean ignoreRecord() { + return null; + } + + @Override + public void ignoreRecord(Boolean ignoreRecord) { + + } + + @Override + public void currentSheet0(ReadSheet readSheet) { + currentSheet(readSheet); + cellMap = new LinkedHashMap(); + ignoreRecord = Boolean.FALSE; + rowType = RowTypeEnum.EMPTY; } } diff --git a/src/main/java/com/alibaba/excel/context/XlsReadContext.java b/src/main/java/com/alibaba/excel/context/XlsReadContext.java index a96009b..7af83cb 100644 --- a/src/main/java/com/alibaba/excel/context/XlsReadContext.java +++ b/src/main/java/com/alibaba/excel/context/XlsReadContext.java @@ -1,5 +1,18 @@ package com.alibaba.excel.context; +import java.util.List; +import java.util.Map; + +import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; +import org.apache.poi.hssf.record.BoundSheetRecord; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; + +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.Cell; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.CellExtra; +import com.alibaba.excel.read.metadata.ReadSheet; + /** * * A context is the main anchorage point of a ls xls reader. @@ -8,4 +21,75 @@ package com.alibaba.excel.context; */ public interface XlsReadContext extends AnalysisContext { + RowTypeEnum tempRowType(); + + void tempRowType(RowTypeEnum tempRowType); + + CellData cellData(); + + void cellData(CellData cellData); + + CellExtra cellExtra(); + + void cellExtra(CellExtra cellExtra); + + Map cellMap(); + + void cellMap(Map cellMap); + + Integer rowIndex(); + + void rowIndex(Integer rowIndex); + + Boolean ignoreRecord(); + + void ignoreRecord(Boolean ignoreRecord); + + /** + * Select the current table + * + * @param readSheet + * sheet to read + */ + void currentSheet0(ReadSheet readSheet); + + FormatTrackingHSSFListener formatTrackingHSSFListener(); + + HSSFWorkbook hsffWorkbook(); + + List boundSheetRecordList(); + + void boundSheetRecordList(List boundSheetRecordList); + + /** + * Actual data + * + * @return + */ + List readSheetDataList(); + + /** + * Actual data + * + * @return + */ + void readSheetDataList(List readSheetDataList); + + Boolean needReadSheet(); + + void needReadSheet(Boolean needReadSheet); + + Integer readSheetIndex(); + + void readSheetIndex(Integer readSheetIndex); + + CellData tempCellData(); + + void tempCellData(CellData tempCellData); + + Integer tempObjectIndex(); + + void tempObjectIndex(Integer tempObjectIndex); + + Map objectCacheMap(); } diff --git a/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java b/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java new file mode 100644 index 0000000..75dfc67 --- /dev/null +++ b/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.enums; + +/** + * The types of row + * + * @author Jiaju Zhuang + **/ +public enum RowTypeEnum { + /** + * data + */ + DATA, + /** + * extra + */ + EXTRA, + /** + * empty + */ + EMPTY,; +} diff --git a/src/main/java/com/alibaba/excel/metadata/AbstractCell.java b/src/main/java/com/alibaba/excel/metadata/AbstractCell.java new file mode 100644 index 0000000..5cea37c --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/AbstractCell.java @@ -0,0 +1,33 @@ +package com.alibaba.excel.metadata; + +/** + * cell + * + * @author Jiaju Zhuang + **/ +public class AbstractCell implements Cell { + /** + * Row index + */ + private Integer rowIndex; + /** + * Column index + */ + private Integer columnIndex; + + public Integer getRowIndex() { + return rowIndex; + } + + public void setRowIndex(Integer rowIndex) { + this.rowIndex = rowIndex; + } + + public Integer getColumnIndex() { + return columnIndex; + } + + public void setColumnIndex(Integer columnIndex) { + this.columnIndex = columnIndex; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/Cell.java b/src/main/java/com/alibaba/excel/metadata/Cell.java new file mode 100644 index 0000000..259df7a --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/Cell.java @@ -0,0 +1,22 @@ +package com.alibaba.excel.metadata; + +/** + * Cell + * + * @author Jiaju Zhuang + **/ +public interface Cell { + /** + * Row index + * + * @return + */ + Integer getRowIndex(); + + /** + * Column index + * + * @return + */ + Integer getColumnIndex(); +} diff --git a/src/main/java/com/alibaba/excel/metadata/CellData.java b/src/main/java/com/alibaba/excel/metadata/CellData.java index 7cd5496..2124e10 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellData.java +++ b/src/main/java/com/alibaba/excel/metadata/CellData.java @@ -12,7 +12,7 @@ import com.alibaba.excel.util.StringUtils; * * @author Jiaju Zhuang */ -public class CellData { +public class CellData extends AbstractCell { private CellDataTypeEnum type; /** * {@link CellDataTypeEnum#NUMBER} @@ -226,6 +226,42 @@ public class CellData { } } + public static CellData newEmptyInstance() { + return newEmptyInstance(null, null); + } + + public static CellData newEmptyInstance(Integer rowIndex, Integer columnIndex) { + CellData cellData = new CellData(CellDataTypeEnum.EMPTY); + cellData.setRowIndex(rowIndex); + cellData.setColumnIndex(columnIndex); + return cellData; + } + + public static CellData newInstance(Boolean booleanValue) { + return newInstance(booleanValue, null, null); + } + + public static CellData newInstance(Boolean booleanValue, Integer rowIndex, Integer columnIndex) { + CellData cellData = new CellData(booleanValue); + cellData.setRowIndex(rowIndex); + cellData.setColumnIndex(columnIndex); + return cellData; + } + + public static CellData newInstance(String stringValue, Integer rowIndex, Integer columnIndex) { + CellData cellData = new CellData(stringValue); + cellData.setRowIndex(rowIndex); + cellData.setColumnIndex(columnIndex); + return cellData; + } + + public static CellData newInstance(BigDecimal numberValue, Integer rowIndex, Integer columnIndex) { + CellData cellData = new CellData(numberValue); + cellData.setRowIndex(rowIndex); + cellData.setColumnIndex(columnIndex); + return cellData; + } + @Override public String toString() { if (type == null) { diff --git a/src/main/java/com/alibaba/excel/metadata/CellExtra.java b/src/main/java/com/alibaba/excel/metadata/CellExtra.java index 84e313d..3570eb9 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellExtra.java +++ b/src/main/java/com/alibaba/excel/metadata/CellExtra.java @@ -5,14 +5,14 @@ package com.alibaba.excel.metadata; * * @author Jiaju Zhuang */ -public class CellExtra { - private String comment; +public class CellExtra extends AbstractCell { + private String note; - public String getComment() { - return comment; + public String getNote() { + return note; } - public void setComment(String comment) { - this.comment = comment; + public void setNote(String note) { + this.note = note; } } diff --git a/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java b/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java deleted file mode 100644 index 07bc68c..0000000 --- a/src/main/java/com/alibaba/excel/read/listener/ReadListenerRegistryCenter.java +++ /dev/null @@ -1,39 +0,0 @@ -package com.alibaba.excel.read.listener; - -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.event.AnalysisEventListener; -import com.alibaba.excel.read.listener.event.AnalysisFinishEvent; - -/** - * Registry center. - * - * @author jipengfei - */ -public interface ReadListenerRegistryCenter { - - /** - * register - * - * @param listener - * Analysis listener - */ - void register(AnalysisEventListener listener); - - /** - * Parse one row to notify all event listeners - * - * @param event - * parse event - * @param analysisContext - * Analysis context - */ - void notifyEndOneRow(AnalysisFinishEvent event, AnalysisContext analysisContext); - - /** - * Notify after all analysed - * - * @param analysisContext - * Analysis context - */ - void notifyAfterAllAnalysed(AnalysisContext analysisContext); -} diff --git a/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java deleted file mode 100644 index 9749cf0..0000000 --- a/src/main/java/com/alibaba/excel/read/listener/event/AnalysisFinishEvent.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.alibaba.excel.read.listener.event; - -import java.util.Map; - -import com.alibaba.excel.metadata.CellData; - -/** - * - * Event - * - * @author jipengfei - */ -public interface AnalysisFinishEvent { - /** - * Get result - * - * @return - */ - Map getAnalysisResult(); -} diff --git a/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java b/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java deleted file mode 100644 index 879a59a..0000000 --- a/src/main/java/com/alibaba/excel/read/listener/event/EachRowAnalysisFinishEvent.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.alibaba.excel.read.listener.event; - -import java.util.Map; - -import com.alibaba.excel.metadata.CellData; - -/** - * @author jipengfei - */ -public class EachRowAnalysisFinishEvent implements AnalysisFinishEvent { - private Map result; - - public EachRowAnalysisFinishEvent(Map content) { - this.result = content; - } - - @Override - public Map getAnalysisResult() { - return result; - } -} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java index 7133f99..a0bf7f1 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/AbstractReadHolder.java @@ -3,41 +3,27 @@ package com.alibaba.excel.read.metadata.holder; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.converters.DefaultConverterLoader; -import com.alibaba.excel.enums.HeadKindEnum; import com.alibaba.excel.enums.HolderEnum; -import com.alibaba.excel.event.AnalysisEventListener; -import com.alibaba.excel.exception.ExcelAnalysisException; -import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.metadata.AbstractHolder; -import com.alibaba.excel.metadata.CellData; -import com.alibaba.excel.metadata.Head; -import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.read.listener.ModelBuildEventListener; import com.alibaba.excel.read.listener.ReadListener; -import com.alibaba.excel.read.listener.ReadListenerRegistryCenter; -import com.alibaba.excel.read.listener.event.AnalysisFinishEvent; import com.alibaba.excel.read.metadata.ReadBasicParameter; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; -import com.alibaba.excel.util.CollectionUtils; -import com.alibaba.excel.util.ConverterUtils; -import com.alibaba.excel.util.StringUtils; /** * Read Holder * * @author Jiaju Zhuang */ -public abstract class AbstractReadHolder extends AbstractHolder implements ReadHolder, ReadListenerRegistryCenter { +public abstract class AbstractReadHolder extends AbstractHolder implements ReadHolder { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractReadHolder.class); /** @@ -117,123 +103,6 @@ public abstract class AbstractReadHolder extends AbstractHolder implements ReadH } } - @Override - public void register(AnalysisEventListener listener) { - readListenerList.add(listener); - } - - @Override - public void notifyEndOneRow(AnalysisFinishEvent event, AnalysisContext analysisContext) { - Map cellDataMap = event.getAnalysisResult(); - if (CollectionUtils.isEmpty(cellDataMap)) { - if (LOGGER.isDebugEnabled()) { - LOGGER.warn("Empty row!"); - } - if (analysisContext.readWorkbookHolder().getIgnoreEmptyRow()) { - return; - } - } - ReadRowHolder readRowHolder = analysisContext.readRowHolder(); - readRowHolder.setCurrentRowAnalysisResult(cellDataMap); - int rowIndex = readRowHolder.getRowIndex(); - int currentheadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber(); - - if (rowIndex >= currentheadRowNumber) { - // Now is data - for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) { - try { - readListener.invoke(readRowHolder.getCurrentRowAnalysisResult(), analysisContext); - } catch (Exception e) { - for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) { - try { - readListenerException.onException(e, analysisContext); - } catch (Exception exception) { - throw new ExcelAnalysisException(exception.getMessage(), exception); - } - } - break; - } - if (!readListener.hasNext(analysisContext)) { - throw new ExcelAnalysisStopException(); - } - } - } else { - // Last head column - if (currentheadRowNumber == rowIndex + 1) { - buildHead(analysisContext, cellDataMap); - } - // Now is header - for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) { - try { - readListener.invokeHead(cellDataMap, analysisContext); - } catch (Exception e) { - for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) { - try { - readListenerException.onException(e, analysisContext); - } catch (Exception exception) { - throw new ExcelAnalysisException(exception.getMessage(), exception); - } - } - break; - } - if (!readListener.hasNext(analysisContext)) { - throw new ExcelAnalysisStopException(); - } - } - } - } - - @Override - public void notifyAfterAllAnalysed(AnalysisContext analysisContext) { - for (ReadListener readListener : readListenerList) { - readListener.doAfterAllAnalysed(analysisContext); - } - } - - private void buildHead(AnalysisContext analysisContext, Map cellDataMap) { - if (!HeadKindEnum.CLASS.equals(analysisContext.currentReadHolder().excelReadHeadProperty().getHeadKind())) { - return; - } - Map dataMap = ConverterUtils.convertToStringMap(cellDataMap, analysisContext); - ExcelReadHeadProperty excelHeadPropertyData = analysisContext.readSheetHolder().excelReadHeadProperty(); - Map headMapData = excelHeadPropertyData.getHeadMap(); - Map contentPropertyMapData = excelHeadPropertyData.getContentPropertyMap(); - Map tmpHeadMap = new HashMap(headMapData.size() * 4 / 3 + 1); - Map tmpContentPropertyMap = - new HashMap(contentPropertyMapData.size() * 4 / 3 + 1); - for (Map.Entry entry : headMapData.entrySet()) { - Head headData = entry.getValue(); - if (headData.getForceIndex() || !headData.getForceName()) { - tmpHeadMap.put(entry.getKey(), headData); - tmpContentPropertyMap.put(entry.getKey(), contentPropertyMapData.get(entry.getKey())); - continue; - } - List headNameList = headData.getHeadNameList(); - String headName = headNameList.get(headNameList.size() - 1); - for (Map.Entry stringEntry : dataMap.entrySet()) { - if (stringEntry == null) { - continue; - } - String headString = stringEntry.getValue(); - Integer stringKey = stringEntry.getKey(); - if (StringUtils.isEmpty(headString)) { - continue; - } - if (analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) { - headString = headString.trim(); - } - if (headName.equals(headString)) { - headData.setColumnIndex(stringKey); - tmpHeadMap.put(stringKey, headData); - tmpContentPropertyMap.put(stringKey, contentPropertyMapData.get(entry.getKey())); - break; - } - } - } - excelHeadPropertyData.setHeadMap(tmpHeadMap); - excelHeadPropertyData.setContentPropertyMap(tmpContentPropertyMap); - } - public List getReadListenerList() { return readListenerList; } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java index 9916015..da74509 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java @@ -1,6 +1,10 @@ package com.alibaba.excel.read.metadata.holder; +import java.util.Map; + import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.Cell; import com.alibaba.excel.metadata.GlobalConfiguration; import com.alibaba.excel.metadata.Holder; @@ -14,7 +18,14 @@ public class ReadRowHolder implements Holder { * Returns row index of a row in the sheet that contains this cell.Start form 0. */ private Integer rowIndex; - + /** + * Row type + */ + private RowTypeEnum rowType; + /** + * Cell map + */ + private Map cellMap; /** * The result of the previous listener */ @@ -24,8 +35,9 @@ public class ReadRowHolder implements Holder { */ private GlobalConfiguration globalConfiguration; - public ReadRowHolder(Integer rowIndex, GlobalConfiguration globalConfiguration) { + public ReadRowHolder(Integer rowIndex, RowTypeEnum rowType, GlobalConfiguration globalConfiguration) { this.rowIndex = rowIndex; + this.rowType = rowType; this.globalConfiguration = globalConfiguration; } @@ -53,6 +65,22 @@ public class ReadRowHolder implements Holder { this.rowIndex = rowIndex; } + public RowTypeEnum getRowType() { + return rowType; + } + + public void setRowType(RowTypeEnum rowType) { + this.rowType = rowType; + } + + public Map getCellMap() { + return cellMap; + } + + public void setCellMap(Map cellMap) { + this.cellMap = cellMap; + } + @Override public HolderEnum holderType() { return HolderEnum.ROW; diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java index c03edf2..b97395e 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java @@ -131,12 +131,6 @@ public class ReadWorkbookHolder extends AbstractReadHolder { */ private POIFSFileSystem poifsFileSystem; - /** - * Excel 2003 cannot read specific sheet. It can only read sheet by sheet.So when you specify one sheet, you ignore - * the others. - */ - private Boolean ignoreRecord03; - public ReadWorkbookHolder(ReadWorkbook readWorkbook) { super(readWorkbook, null, readWorkbook.getConvertAllFiled()); this.readWorkbook = readWorkbook; @@ -197,7 +191,6 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.extraReadSet = readWorkbook.getExtraReadSet(); } this.hasReadSheet = new HashSet(); - this.ignoreRecord03 = Boolean.FALSE; this.password = readWorkbook.getPassword(); } @@ -329,14 +322,6 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.poifsFileSystem = poifsFileSystem; } - public Boolean getIgnoreRecord03() { - return ignoreRecord03; - } - - public void setIgnoreRecord03(Boolean ignoreRecord03) { - this.ignoreRecord03 = ignoreRecord03; - } - public String getPassword() { return password; } diff --git a/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java b/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java new file mode 100644 index 0000000..cd48538 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java @@ -0,0 +1,26 @@ +package com.alibaba.excel.read.processor; + +import com.alibaba.excel.context.AnalysisContext; + +/** + * + * Event processor + * + * @author jipengfei + */ +public interface AnalysisEventProcessor { + /** + * End row + * + * @param analysisContext + */ + void endRow(AnalysisContext analysisContext); + + /** + * Notify after all analysed + * + * @param analysisContext + * Analysis context + */ + void endSheet(AnalysisContext analysisContext); +} diff --git a/src/main/java/com/alibaba/excel/read/processor/DefalutAnalysisEventProcessor.java b/src/main/java/com/alibaba/excel/read/processor/DefalutAnalysisEventProcessor.java new file mode 100644 index 0000000..e673913 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/processor/DefalutAnalysisEventProcessor.java @@ -0,0 +1,149 @@ +package com.alibaba.excel.read.processor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.enums.HeadKindEnum; +import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelAnalysisStopException; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.read.listener.ReadListener; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.read.metadata.property.ExcelReadHeadProperty; +import com.alibaba.excel.util.ConverterUtils; +import com.alibaba.excel.util.StringUtils; + +/** + * Analysis event + * + * @author jipengfei + */ +public class DefalutAnalysisEventProcessor implements AnalysisEventProcessor { + private static final Logger LOGGER = LoggerFactory.getLogger(DefalutAnalysisEventProcessor.class); + + @Override + public void endRow(AnalysisContext analysisContext) { + + switch (analysisContext.readRowHolder().getRowType()) { + case EMPTY: + if (LOGGER.isDebugEnabled()) { + LOGGER.warn("Empty row!"); + } + if (analysisContext.readWorkbookHolder().getIgnoreEmptyRow()) { + return; + } + // Need to continue to notify invoke. + dealData(analysisContext); + break; + case DATA: + dealData(analysisContext); + break; + case EXTRA: + dealExtra(analysisContext); + break; + default: + throw new ExcelAnalysisException("Wrong row type."); + } + + } + + @Override + public void endSheet(AnalysisContext analysisContext) { + for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) { + readListener.doAfterAllAnalysed(analysisContext); + } + } + + private void dealExtra(AnalysisContext analysisContext) {} + + private void dealData(AnalysisContext analysisContext) { + ReadRowHolder readRowHolder = analysisContext.readRowHolder(); + Map cellDataMap = (Map)readRowHolder.getCellMap(); + readRowHolder.setCurrentRowAnalysisResult(cellDataMap); + int rowIndex = readRowHolder.getRowIndex(); + int currentHeadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber(); + + boolean isData = rowIndex >= currentHeadRowNumber; + + // Last head column + if (!isData && currentHeadRowNumber == rowIndex + 1) { + buildHead(analysisContext, cellDataMap); + } + + // Now is data + for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) { + try { + if (isData) { + readListener.invoke(readRowHolder.getCurrentRowAnalysisResult(), analysisContext); + } else { + readListener.invokeHead(cellDataMap, analysisContext); + } + } catch (Exception e) { + for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) { + try { + readListenerException.onException(e, analysisContext); + } catch (RuntimeException re) { + throw re; + } catch (Exception e1) { + throw new ExcelAnalysisException(e1.getMessage(), e1); + } + } + break; + } + if (!readListener.hasNext(analysisContext)) { + throw new ExcelAnalysisStopException(); + } + } + } + + private void buildHead(AnalysisContext analysisContext, Map cellDataMap) { + if (!HeadKindEnum.CLASS.equals(analysisContext.currentReadHolder().excelReadHeadProperty().getHeadKind())) { + return; + } + Map dataMap = ConverterUtils.convertToStringMap(cellDataMap, analysisContext); + ExcelReadHeadProperty excelHeadPropertyData = analysisContext.readSheetHolder().excelReadHeadProperty(); + Map headMapData = excelHeadPropertyData.getHeadMap(); + Map contentPropertyMapData = excelHeadPropertyData.getContentPropertyMap(); + Map tmpHeadMap = new HashMap(headMapData.size() * 4 / 3 + 1); + Map tmpContentPropertyMap = + new HashMap(contentPropertyMapData.size() * 4 / 3 + 1); + for (Map.Entry entry : headMapData.entrySet()) { + Head headData = entry.getValue(); + if (headData.getForceIndex() || !headData.getForceName()) { + tmpHeadMap.put(entry.getKey(), headData); + tmpContentPropertyMap.put(entry.getKey(), contentPropertyMapData.get(entry.getKey())); + continue; + } + List headNameList = headData.getHeadNameList(); + String headName = headNameList.get(headNameList.size() - 1); + for (Map.Entry stringEntry : dataMap.entrySet()) { + if (stringEntry == null) { + continue; + } + String headString = stringEntry.getValue(); + Integer stringKey = stringEntry.getKey(); + if (StringUtils.isEmpty(headString)) { + continue; + } + if (analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) { + headString = headString.trim(); + } + if (headName.equals(headString)) { + headData.setColumnIndex(stringKey); + tmpHeadMap.put(stringKey, headData); + tmpContentPropertyMap.put(stringKey, contentPropertyMapData.get(entry.getKey())); + break; + } + } + } + excelHeadPropertyData.setHeadMap(tmpHeadMap); + excelHeadPropertyData.setContentPropertyMap(tmpContentPropertyMap); + } +} diff --git a/src/main/java/com/alibaba/excel/util/SheetUtils.java b/src/main/java/com/alibaba/excel/util/SheetUtils.java index 66a1c48..398fe5a 100644 --- a/src/main/java/com/alibaba/excel/util/SheetUtils.java +++ b/src/main/java/com/alibaba/excel/util/SheetUtils.java @@ -1,11 +1,9 @@ package com.alibaba.excel.util; -import java.util.List; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.excel.metadata.GlobalConfiguration; +import com.alibaba.excel.context.XlsReadContext; import com.alibaba.excel.read.metadata.ReadSheet; /** @@ -23,17 +21,14 @@ public class SheetUtils { * * @param readSheet * actual sheet - * @param parameterReadSheetList - * parameters - * @param readAll + * @param xlsReadContext * @return */ - public static ReadSheet match(ReadSheet readSheet, List parameterReadSheetList, Boolean readAll, - GlobalConfiguration globalConfiguration) { - if (readAll) { + public static ReadSheet match(ReadSheet readSheet, XlsReadContext xlsReadContext) { + if (xlsReadContext.readAll()) { return readSheet; } - for (ReadSheet parameterReadSheet : parameterReadSheetList) { + for (ReadSheet parameterReadSheet : xlsReadContext.readSheetList()) { if (parameterReadSheet == null) { continue; } @@ -49,7 +44,8 @@ public class SheetUtils { String parameterSheetName = parameterReadSheet.getSheetName(); if (!StringUtils.isEmpty(parameterSheetName)) { boolean autoTrim = (parameterReadSheet.getAutoTrim() != null && parameterReadSheet.getAutoTrim()) - || (parameterReadSheet.getAutoTrim() == null && globalConfiguration.getAutoTrim()); + || (parameterReadSheet.getAutoTrim() == null + && xlsReadContext.readWorkbookHolder().getGlobalConfiguration().getAutoTrim()); if (autoTrim) { parameterSheetName = parameterSheetName.trim(); } diff --git a/update.md b/update.md index 0968528..8f2c477 100644 --- a/update.md +++ b/update.md @@ -4,6 +4,7 @@ * 修复xls 用Map接收时多次接收会是同一个对象的bug * 修复浮点型数据导入到excel 会丢失精度的bug * 新增支持接收批注 +* 如果是`RuntimeException`则不再封装对象 # 2.1.4 From 6ed614612abedf717262c49a656a07ae2e391b87 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Thu, 2 Jan 2020 16:41:23 +0800 Subject: [PATCH 10/38] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=8E=A5=E6=94=B6=E6=89=B9=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/analysis/ExcelAnalyserImpl.java | 37 ++-- .../excel/analysis/ExcelReadExecutor.java | 7 +- .../analysis/v03/XlsListSheetListener.java | 39 ++-- .../excel/analysis/v03/XlsRecordHandler.java | 2 +- .../excel/analysis/v03/XlsSaxAnalyser.java | 198 ++++++------------ .../v03/handlers/BlankRecordHandler.java | 5 +- .../v03/handlers/BofRecordHandler.java | 33 +-- .../v03/handlers/BoolErrRecordHandler.java | 6 +- .../v03/handlers/BoundSheetRecordHandler.java | 4 +- ...rdHandler.java => DummyRecordHandler.java} | 15 +- .../v03/handlers/EofRecordHandler.java | 2 +- .../v03/handlers/FormulaRecordHandler.java | 18 +- .../v03/handlers/IndexRecordHandler.java | 2 +- .../v03/handlers/LabelRecordHandler.java | 12 +- ...andler.java => LabelSstRecordHandler.java} | 22 +- .../v03/handlers/NoteRecordHandler.java | 8 +- .../v03/handlers/NumberRecordHandler.java | 14 +- .../v03/handlers/ObjRecordHandler.java | 4 +- .../v03/handlers/RkRecordHandler.java | 5 +- .../v03/handlers/SstRecordHandler.java | 2 +- .../v03/handlers/StringRecordHandler.java | 10 +- .../v03/handlers/TextObjectRecordHandler.java | 10 +- .../excel/context/AnalysisContextImpl.java | 49 ++++- .../excel/context/DefaultXlsReadContext.java | 126 ----------- .../alibaba/excel/context/XlsReadContext.java | 95 --------- .../context/xls/DefaultXlsReadContext.java | 30 +++ .../excel/context/xls/XlsReadContext.java | 26 +++ .../context/xlsx/DefaultXlsxReadContext.java | 30 +++ .../excel/context/xlsx/XlsxReadContext.java | 28 +++ .../metadata/holder/ReadWorkbookHolder.java | 75 ++++--- .../holder/xls/XlsReadSheetHolder.java | 112 ++++++++++ .../holder/xls/XlsReadWorkbookHolder.java | 95 +++++++++ .../holder/xlsx/XlsxReadSheetHolder.java | 16 ++ .../holder/xlsx/XlsxReadWorkbookHolder.java | 52 +++++ .../com/alibaba/excel/util/SheetUtils.java | 2 +- 35 files changed, 670 insertions(+), 521 deletions(-) rename src/main/java/com/alibaba/excel/analysis/v03/handlers/{DummyRecordRecordHandler.java => DummyRecordHandler.java} (65%) rename src/main/java/com/alibaba/excel/analysis/v03/handlers/{LabelSSTRecordHandler.java => LabelSstRecordHandler.java} (50%) delete mode 100644 src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java delete mode 100644 src/main/java/com/alibaba/excel/context/XlsReadContext.java create mode 100644 src/main/java/com/alibaba/excel/context/xls/DefaultXlsReadContext.java create mode 100644 src/main/java/com/alibaba/excel/context/xls/XlsReadContext.java create mode 100644 src/main/java/com/alibaba/excel/context/xlsx/DefaultXlsxReadContext.java create mode 100644 src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java create mode 100644 src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java create mode 100644 src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java create mode 100644 src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java create mode 100644 src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index 90cfad0..97ee3af 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -15,13 +15,15 @@ import com.alibaba.excel.analysis.v03.XlsSaxAnalyser; import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.context.AnalysisContextImpl; -import com.alibaba.excel.context.DefaultXlsReadContext; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.DefaultXlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; import com.alibaba.excel.support.ExcelTypeEnum; import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.DateUtils; @@ -58,7 +60,6 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { private void choiceExcelExecutor(ReadWorkbook readWorkbook) throws Exception { ExcelTypeEnum excelType = ExcelTypeEnum.valueOf(readWorkbook.getFile(), readWorkbook.getInputStream(), readWorkbook.getExcelType()); - readWorkbook.setExcelType(excelType); switch (excelType) { case XLS: POIFSFileSystem poifsFileSystem; @@ -73,7 +74,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { try { decryptedStream = DocumentFactoryHelper .getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(), readWorkbook.getPassword()); - analysisContext = new AnalysisContextImpl(readWorkbook); + analysisContext = new AnalysisContextImpl(readWorkbook, ExcelTypeEnum.XLSX); excelReadExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream); return; } finally { @@ -86,15 +87,17 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { if (readWorkbook.getPassword() != null) { Biff8EncryptionKey.setCurrentUserPassword(readWorkbook.getPassword()); } - XlsReadContext xlsReadContext = new DefaultXlsReadContext(readWorkbook); + XlsReadContext xlsReadContext = new DefaultXlsReadContext(readWorkbook, ExcelTypeEnum.XLS); + xlsReadContext.xlsReadWorkbookHolder().setPoifsFileSystem(poifsFileSystem); analysisContext = xlsReadContext; - excelReadExecutor = new XlsSaxAnalyser(xlsReadContext, poifsFileSystem); + excelReadExecutor = new XlsSaxAnalyser(xlsReadContext); break; case XLSX: - analysisContext = new AnalysisContextImpl(readWorkbook); + analysisContext = new AnalysisContextImpl(readWorkbook, ExcelTypeEnum.XLSX); excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null); break; default: + break; } } @@ -104,19 +107,15 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { if (!readAll && CollectionUtils.isEmpty(readSheetList)) { throw new IllegalArgumentException("Specify at least one read sheet."); } + analysisContext.readWorkbookHolder().setParametersheetDataList(readSheetList); + analysisContext.readWorkbookHolder().setReadAll(readAll); try { - excelReadExecutor.execute(readSheetList, readAll); + excelReadExecutor.execute(); } catch (ExcelAnalysisStopException e) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Custom stop!"); } } - // The last sheet is read - if (excelReadExecutor instanceof XlsSaxAnalyser) { - if (analysisContext.readSheetHolder() != null) { - analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext); - } - } } catch (RuntimeException e) { finish(); throw e; @@ -147,15 +146,17 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { throwable = t; } try { - if (readWorkbookHolder.getOpcPackage() != null) { - readWorkbookHolder.getOpcPackage().revert(); + if ((readWorkbookHolder instanceof XlsxReadWorkbookHolder) + && ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage() != null) { + ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage().revert(); } } catch (Throwable t) { throwable = t; } try { - if (readWorkbookHolder.getPoifsFileSystem() != null) { - readWorkbookHolder.getPoifsFileSystem().close(); + if ((readWorkbookHolder instanceof XlsReadWorkbookHolder) + && ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem() != null) { + ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem().close(); } } catch (Throwable t) { throwable = t; diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java b/src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java index 10ced98..085caab 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelReadExecutor.java @@ -20,11 +20,6 @@ public interface ExcelReadExecutor { /** * Read the sheet. - * - * @param readSheetList - * Which sheets you need to read. - * @param readAll - * The readSheetList parameter is ignored, and all sheets are read. */ - void execute(List readSheetList, Boolean readAll); + void execute(); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java index 906b377..31d2db8 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java @@ -1,8 +1,8 @@ package com.alibaba.excel.analysis.v03; import java.io.IOException; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; +import java.util.Map; import org.apache.poi.hssf.eventusermodel.EventWorkbookBuilder; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; @@ -10,13 +10,14 @@ import org.apache.poi.hssf.eventusermodel.HSSFEventFactory; import org.apache.poi.hssf.eventusermodel.HSSFListener; import org.apache.poi.hssf.eventusermodel.HSSFRequest; import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; +import org.apache.poi.hssf.record.BOFRecord; +import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.analysis.v03.handlers.BoundSheetRecordHandler; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.exception.ExcelAnalysisException; -import com.alibaba.excel.read.metadata.ReadSheet; /** * In some cases, you need to know the number of sheets in advance and only read the file once in advance. @@ -24,25 +25,28 @@ import com.alibaba.excel.read.metadata.ReadSheet; * @author Jiaju Zhuang */ public class XlsListSheetListener implements HSSFListener { - private POIFSFileSystem poifsFileSystem; - private BofRecordHandler bofRecordHandler; + private XlsReadContext xlsReadContext; + private static final Map XLS_RECORD_HANDLER_MAP = new HashMap(); - private static fin + static { + XLS_RECORD_HANDLER_MAP.put(BOFRecord.sid, new BofRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(BoundSheetRecord.sid, new BoundSheetRecordHandler()); + } - public XlsListSheetListener(XlsReadContext analysisContext, POIFSFileSystem poifsFileSystem) { - this.poifsFileSystem = poifsFileSystem; - sheetList = new ArrayList(); - bofRecordHandler = new BofRecordHandler(analysisContext, sheetList, false, false); - bofRecordHandler.init(); - bofRecordHandler.init(null, true); + public XlsListSheetListener(XlsReadContext xlsReadContext) { + this.xlsReadContext = xlsReadContext; } @Override public void processRecord(Record record) { - bofRecordHandler.processRecord(record); + XlsRecordHandler handler = XLS_RECORD_HANDLER_MAP.get(record.getSid()); + if (handler == null) { + return; + } + handler.processRecord(xlsReadContext, record); } - public List getSheetList() { + public void execute() { MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); HSSFListener formatListener = new FormatTrackingHSSFListener(listener); HSSFEventFactory factory = new HSSFEventFactory(); @@ -51,10 +55,9 @@ public class XlsListSheetListener implements HSSFListener { new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); request.addListenerForAllRecords(workbookBuildingListener); try { - factory.processWorkbookEvents(request, poifsFileSystem); + factory.processWorkbookEvents(request, xlsReadContext.xlsReadWorkbookHolder().getPoifsFileSystem()); } catch (IOException e) { throw new ExcelAnalysisException(e); } - return sheetList; } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java index fca15b5..dea327f 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java @@ -2,7 +2,7 @@ package com.alibaba.excel.analysis.v03; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; /** * Intercepts handle xls reads. diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index 68b0c47..c90f655 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -1,8 +1,6 @@ package com.alibaba.excel.analysis.v03; import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -16,33 +14,46 @@ import org.apache.poi.hssf.eventusermodel.MissingRecordAwareHSSFListener; import org.apache.poi.hssf.eventusermodel.dummyrecord.LastCellOfRowDummyRecord; import org.apache.poi.hssf.record.BOFRecord; import org.apache.poi.hssf.record.BlankRecord; +import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.BoundSheetRecord; +import org.apache.poi.hssf.record.EOFRecord; +import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.IndexRecord; +import org.apache.poi.hssf.record.LabelRecord; +import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.NoteRecord; +import org.apache.poi.hssf.record.NumberRecord; +import org.apache.poi.hssf.record.ObjRecord; +import org.apache.poi.hssf.record.RKRecord; import org.apache.poi.hssf.record.Record; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; +import org.apache.poi.hssf.record.SSTRecord; +import org.apache.poi.hssf.record.StringRecord; +import org.apache.poi.hssf.record.TextObjectRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.ExcelReadExecutor; -import com.alibaba.excel.analysis.v03.handlers.BlankOrErrorRecordHandler; import com.alibaba.excel.analysis.v03.handlers.BlankRecordHandler; import com.alibaba.excel.analysis.v03.handlers.BofRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.BoolErrRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.BoundSheetRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.DummyRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.EofRecordHandler; import com.alibaba.excel.analysis.v03.handlers.FormulaRecordHandler; import com.alibaba.excel.analysis.v03.handlers.IndexRecordHandler; import com.alibaba.excel.analysis.v03.handlers.LabelRecordHandler; -import com.alibaba.excel.analysis.v03.handlers.MissingCellDummyRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.LabelSstRecordHandler; import com.alibaba.excel.analysis.v03.handlers.NoteRecordHandler; import com.alibaba.excel.analysis.v03.handlers.NumberRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.ObjRecordHandler; import com.alibaba.excel.analysis.v03.handlers.RkRecordHandler; import com.alibaba.excel.analysis.v03.handlers.SstRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.StringRecordHandler; import com.alibaba.excel.analysis.v03.handlers.TextObjectRecordHandler; -import com.alibaba.excel.context.XlsReadContext; -import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.exception.ExcelAnalysisException; -import com.alibaba.excel.metadata.CellData; -import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent; import com.alibaba.excel.read.metadata.ReadSheet; -import com.alibaba.excel.read.metadata.holder.ReadRowHolder; -import com.alibaba.excel.util.CollectionUtils; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; /** * /** * A text extractor for Excel files. * @@ -61,169 +72,78 @@ import com.alibaba.excel.util.CollectionUtils; */ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { private static final Logger LOGGER = LoggerFactory.getLogger(XlsSaxAnalyser.class); - // - // private Boolean readAll; - // private List readSheetList; - // /** - // * For parsing Formulas - // */ - // private EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener; - // private FormatTrackingHSSFListener formatListener; - // private List sheets; - // private HSSFWorkbook stubWorkbook; - // private Map recordHandlerMap; + private static final short DUMMY_RECORD_SID = -1; private XlsReadContext xlsReadContext; - private POIFSFileSystem poifsFileSystem; - private static final Map XLS_RECORD_HANDLER_MAP = new HashMap(32); static { XLS_RECORD_HANDLER_MAP.put(BlankRecord.sid, new BlankRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(BOFRecord.sid, new BofRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(BoolErrRecord.sid, new BoolErrRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(BoundSheetRecord.sid, new BoundSheetRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(DUMMY_RECORD_SID, new DummyRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(EOFRecord.sid, new EofRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(FormulaRecord.sid, new FormulaRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(IndexRecord.sid, new IndexRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(LabelRecord.sid, new LabelRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(LabelSSTRecord.sid, new LabelSstRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(NoteRecord.sid, new NoteRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(NumberRecord.sid, new NumberRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(ObjRecord.sid, new ObjRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(RKRecord.sid, new RkRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(SSTRecord.sid, new SstRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(StringRecord.sid, new StringRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(TextObjectRecord.sid, new TextObjectRecordHandler()); } - public XlsSaxAnalyser(XlsReadContext xlsReadContext, POIFSFileSystem poifsFileSystem) { + public XlsSaxAnalyser(XlsReadContext xlsReadContext) { this.xlsReadContext = xlsReadContext; - this.poifsFileSystem = poifsFileSystem; - xlsReadContext.readWorkbookHolder().setPoifsFileSystem(poifsFileSystem); } @Override public List sheetList() { - if (xlsReadContext.readSheetDataList() == null) { - earlySheetDataList(); - + if (xlsReadContext.readWorkbookHolder().getActualSheetDataList() == null) { LOGGER.warn("Getting the 'sheetList' before reading will cause the file to be read twice."); - XlsListSheetListener xlsListSheetListener = new XlsListSheetListener(xlsReadContext, poifsFileSystem); + new XlsListSheetListener(xlsReadContext).execute(); } - return xlsReadContext.readSheetDataList(); - } - - private void earlySheetDataList() { - LOGGER.warn("Getting the 'sheetList' before reading will cause the file to be read twice."); - - sheetList = new ArrayList(); - bofRecordHandler = new BofRecordHandler(analysisContext, sheetList, false, false); - bofRecordHandler.init(); - bofRecordHandler.init(null, true); - - XlsListSheetListener xlsListSheetListener = new XlsListSheetListener(xlsReadContext, poifsFileSystem); + return xlsReadContext.readWorkbookHolder().getActualSheetDataList(); } @Override public void execute() { - this.readAll = readAll; - this.readSheetList = readSheetList; + XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder(); MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this); - formatListener = new FormatTrackingHSSFListener(listener); - workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener(formatListener); - if (workbookBuildingListener != null && stubWorkbook == null) { - stubWorkbook = workbookBuildingListener.getStubHSSFWorkbook(); - } - init(); + xlsReadWorkbookHolder.setFormatTrackingHSSFListener(new FormatTrackingHSSFListener(listener)); + EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener = + new EventWorkbookBuilder.SheetRecordCollectingListener( + xlsReadWorkbookHolder.getFormatTrackingHSSFListener()); + xlsReadWorkbookHolder.setHsffWorkbook(workbookBuildingListener.getStubHSSFWorkbook()); HSSFEventFactory factory = new HSSFEventFactory(); HSSFRequest request = new HSSFRequest(); - request.addListenerForAllRecords(formatListener); + request.addListenerForAllRecords(xlsReadWorkbookHolder.getFormatTrackingHSSFListener()); try { - factory.processWorkbookEvents(request, poifsFileSystem); + factory.processWorkbookEvents(request, xlsReadWorkbookHolder.getPoifsFileSystem()); } catch (IOException e) { throw new ExcelAnalysisException(e); } // Sometimes tables lack the end record of the last column - if (!xlsReadContext.cellMap().isEmpty()) { - endRow(); + if (!xlsReadContext.xlsReadSheetHolder().getCellMap().isEmpty()) { + // Forge a termination data + processRecord(new LastCellOfRowDummyRecord(xlsReadContext.xlsReadSheetHolder().getRowIndex() + 1, -1)); } } - private void init() { - recordHandlerMap = new HashMap(32); - - buildXlsRecordHandlers(); - - } - @Override public void processRecord(Record record) { - XlsRecordHandler handler = recordHandlerMap.get(record.getSid()); - if ((handler instanceof IgnorableXlsRecordHandler) && xlsReadContext.readWorkbookHolder().getIgnoreRecord03()) { + XlsRecordHandler handler = XLS_RECORD_HANDLER_MAP.get(record.getSid()); + if (handler == null) { + return; + } + if ((handler instanceof IgnorableXlsRecordHandler) && xlsReadContext.xlsReadSheetHolder().getIgnoreRecord()) { // No need to read the current sheet return; } handler.processRecord(xlsReadContext, record); - - int thisRow = -1; - int thisColumn = -1; - CellData cellData = null; - for (XlsRecordHandler handler : this.recordHandlers) { - if (handler.support(record)) { - handler.processRecord(record); - thisRow = handler.getRow(); - thisColumn = handler.getColumn(); - cellData = handler.getCellData(); - if (cellData != null) { - cellData.checkEmpty(); - if (CellDataTypeEnum.EMPTY != cellData.getType()) { - records.put(thisColumn, cellData); - } - } - break; - } - } - // If we got something to print out, do so - if (cellData != null && xlsReadContext.currentReadHolder().globalConfiguration().getAutoTrim() - && CellDataTypeEnum.STRING == cellData.getType()) { - cellData.setStringValue(cellData.getStringValue().trim()); - } - - processLastCellOfRow(record); - } - - private boolean ignoreRecord(Record record) { - return xlsReadContext.readWorkbookHolder().getIgnoreRecord03() && record.getSid() != BoundSheetRecord.sid - && record.getSid() != BOFRecord.sid; - } - - private void processLastCellOfRow(Record record) { - // Handle end of row - if (record instanceof LastCellOfRowDummyRecord) { - System.out.println("----" + record.getSid()); - endRow(); - } - } - - private void endRow() { - xlsReadContext - .readRowHolder(new ReadRowHolder(lastRowNumber, xlsReadContext.readSheetHolder().getGlobalConfiguration())); - xlsReadContext.readSheetHolder().notifyEndOneRow(new EachRowAnalysisFinishEvent(records), xlsReadContext); } - private void buildXlsRecordHandlers() { - if (CollectionUtils.isEmpty(recordHandlers)) { - recordHandlers.add(new BlankOrErrorRecordHandler(xlsReadContext)); - // The table has been counted and there are no duplicate statistics - if (sheets == null) { - sheets = new ArrayList(); - recordHandlers.add(new BofRecordHandler(xlsReadContext, sheets, false, true)); - } else { - recordHandlers.add(new BofRecordHandler(xlsReadContext, sheets, true, true)); - } - recordHandlers.add(new FormulaRecordHandler(xlsReadContext, stubWorkbook, formatListener)); - recordHandlers.add(new LabelRecordHandler(xlsReadContext)); - recordHandlers.add(new NoteRecordHandler(xlsReadContext)); - recordHandlers.add(new NumberRecordHandler(xlsReadContext, formatListener)); - recordHandlers.add(new RkRecordHandler(xlsReadContext)); - recordHandlers.add(new SstRecordHandler(xlsReadContext)); - recordHandlers.add(new MissingCellDummyRecordHandler(xlsReadContext)); - recordHandlers.add(new IndexRecordHandler(xlsReadContext)); - recordHandlers.add(new TextObjectRecordHandler(xlsReadContext)); - Collections.sort(recordHandlers); - } - - for (XlsRecordHandler x : recordHandlers) { - x.init(); - if (x instanceof BofRecordHandler) { - BofRecordHandler bofRecordHandler = (BofRecordHandler)x; - bofRecordHandler.init(readSheetList, readAll); - } - } - } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java index 24d9905..372a44c 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java @@ -4,7 +4,7 @@ import org.apache.poi.hssf.record.BlankRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.metadata.CellData; /** @@ -17,6 +17,7 @@ public class BlankRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { BlankRecord br = (BlankRecord)record; - xlsReadContext.cellMap().put((int)br.getColumn(), CellData.newEmptyInstance(br.getRow(), (int)br.getColumn())); + xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)br.getColumn(), + CellData.newEmptyInstance(br.getRow(), (int)br.getColumn())); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java index 5137d18..59870ba 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -8,9 +8,11 @@ import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.XlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; import com.alibaba.excel.util.SheetUtils; /** @@ -26,43 +28,44 @@ public class BofRecordHandler implements XlsRecordHandler { if (br.getType() != BOFRecord.TYPE_WORKSHEET) { return; } + XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder(); + XlsReadSheetHolder XlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); // Init read sheet Data - initReadSheetDataList(xlsReadContext); - Integer readSheetIndex = xlsReadContext.readSheetIndex(); + initReadSheetDataList(xlsReadWorkbookHolder); + Integer readSheetIndex = xlsReadWorkbookHolder.getReadSheetIndex(); if (readSheetIndex == null) { readSheetIndex = 0; - xlsReadContext.readSheetIndex(readSheetIndex); + xlsReadWorkbookHolder.setReadSheetIndex(readSheetIndex); } - - ReadSheet readSheet = xlsReadContext.readSheetDataList().get(readSheetIndex); + ReadSheet readSheet = xlsReadWorkbookHolder.getActualSheetDataList().get(readSheetIndex); assert readSheet != null : "Can't find the sheet."; // Copy the parameter to the current sheet readSheet = SheetUtils.match(readSheet, xlsReadContext); if (readSheet != null) { - xlsReadContext.currentSheet0(readSheet); - xlsReadContext.ignoreRecord(Boolean.FALSE); + xlsReadContext.currentSheet(readSheet); + XlsReadSheetHolder.setIgnoreRecord(Boolean.FALSE); } else { - xlsReadContext.ignoreRecord(Boolean.TRUE); + XlsReadSheetHolder.setIgnoreRecord(Boolean.TRUE); } // Go read the next one - xlsReadContext.readSheetIndex(xlsReadContext.readSheetIndex() + 1); + xlsReadWorkbookHolder.setReadSheetIndex(xlsReadWorkbookHolder.getReadSheetIndex() + 1); } - private void initReadSheetDataList(XlsReadContext xlsReadContext) { - if (xlsReadContext.readSheetDataList() != null) { + private void initReadSheetDataList(XlsReadWorkbookHolder xlsReadWorkbookHolder) { + if (xlsReadWorkbookHolder.getActualSheetDataList() != null) { return; } BoundSheetRecord[] boundSheetRecords = - BoundSheetRecord.orderByBofPosition(xlsReadContext.boundSheetRecordList()); + BoundSheetRecord.orderByBofPosition(xlsReadWorkbookHolder.getBoundSheetRecordList()); List readSheetDataList = new ArrayList(); for (int i = 0; i < boundSheetRecords.length; i++) { BoundSheetRecord boundSheetRecord = boundSheetRecords[i]; ReadSheet readSheet = new ReadSheet(i, boundSheetRecord.getSheetname()); readSheetDataList.add(readSheet); } - xlsReadContext.readSheetDataList(readSheetDataList); + xlsReadWorkbookHolder.setActualSheetDataList(readSheetDataList); // Just need to get the list of sheets - if (!xlsReadContext.needReadSheet()) { + if (!xlsReadWorkbookHolder.getNeedReadSheet()) { throw new ExcelAnalysisStopException("Just need to get the list of sheets."); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java index 27d521c..60e7233 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java @@ -4,7 +4,7 @@ import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -18,8 +18,8 @@ public class BoolErrRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { BoolErrRecord ber = (BoolErrRecord)record; - xlsReadContext.cellMap().put((int)ber.getColumn(), + xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)ber.getColumn(), CellData.newInstance(ber.getBooleanValue(), ber.getRow(), (int)ber.getColumn())); - xlsReadContext.tempRowType(RowTypeEnum.DATA); + xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java index 809d7fd..96e7b33 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java @@ -4,7 +4,7 @@ import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; /** * Record handler @@ -16,6 +16,6 @@ public class BoundSheetRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { BoundSheetRecord bsr = (BoundSheetRecord)record; - xlsReadContext.boundSheetRecordList().add((BoundSheetRecord)record); + xlsReadContext.xlsReadWorkbookHolder().getBoundSheetRecordList().add((BoundSheetRecord)record); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java similarity index 65% rename from src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordRecordHandler.java rename to src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java index 53d4d35..15a68dc 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java @@ -7,30 +7,33 @@ import org.apache.poi.hssf.eventusermodel.dummyrecord.MissingCellDummyRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.metadata.Cell; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; /** * Record handler * * @author Dan Zheng */ -public class DummyRecordRecordHandler implements IgnorableXlsRecordHandler { +public class DummyRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { + XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); if (record instanceof LastCellOfRowDummyRecord) { // End of this row LastCellOfRowDummyRecord lcrdr = (LastCellOfRowDummyRecord)record; - xlsReadContext.rowIndex(lcrdr.getRow()); - xlsReadContext.readRowHolder(new ReadRowHolder(lcrdr.getRow(), xlsReadContext.tempRowType(), + xlsReadSheetHolder.setRowIndex(lcrdr.getRow()); + xlsReadContext.readRowHolder(new ReadRowHolder(lcrdr.getRow(), xlsReadSheetHolder.getTempRowType(), xlsReadContext.readSheetHolder().getGlobalConfiguration())); xlsReadContext.analysisEventProcessor().endRow(xlsReadContext); - xlsReadContext.cellMap(new LinkedHashMap()); + xlsReadSheetHolder.setCellMap(new LinkedHashMap()); } else if (record instanceof MissingCellDummyRecord) { MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record; - xlsReadContext.cellMap().put(mcdr.getColumn(), CellData.newEmptyInstance(mcdr.getRow(), mcdr.getColumn())); + xlsReadSheetHolder.getCellMap().put(mcdr.getColumn(), + CellData.newEmptyInstance(mcdr.getRow(), mcdr.getColumn())); } } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java index 9efe988..4b1517b 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java @@ -3,7 +3,7 @@ package com.alibaba.excel.analysis.v03.handlers; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; /** * Record handler diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java index 261b7e1..f04cdb7 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -1,6 +1,7 @@ package com.alibaba.excel.analysis.v03.handlers; import java.math.BigDecimal; +import java.util.Map; import org.apache.poi.hssf.model.HSSFFormulaParser; import org.apache.poi.hssf.record.FormulaRecord; @@ -10,8 +11,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.Cell; import com.alibaba.excel.metadata.CellData; /** @@ -26,13 +28,15 @@ public class FormulaRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { FormulaRecord frec = (FormulaRecord)record; + Map cellMap = xlsReadContext.xlsReadSheetHolder().getCellMap(); CellData tempCellData = new CellData(); tempCellData.setRowIndex(frec.getRow()); tempCellData.setColumnIndex((int)frec.getColumn()); CellType cellType = CellType.forInt(frec.getCachedResultType()); String formulaValue = null; try { - formulaValue = HSSFFormulaParser.toFormulaString(xlsReadContext.hsffWorkbook(), frec.getParsedExpression()); + formulaValue = HSSFFormulaParser.toFormulaString(xlsReadContext.xlsReadWorkbookHolder().getHsffWorkbook(), + frec.getParsedExpression()); } catch (Exception e) { LOGGER.debug("Get formula value error.", e); } @@ -43,26 +47,26 @@ public class FormulaRecordHandler implements IgnorableXlsRecordHandler { // Formula result is a string // This is stored in the next record tempCellData.setType(CellDataTypeEnum.STRING); - xlsReadContext.tempCellData(tempCellData); + xlsReadContext.xlsReadSheetHolder().setTempCellData(tempCellData); break; case NUMERIC: tempCellData.setType(CellDataTypeEnum.NUMBER); tempCellData.setNumberValue(BigDecimal.valueOf(frec.getValue())); - xlsReadContext.cellMap().put((int)frec.getColumn(), tempCellData); + cellMap.put((int)frec.getColumn(), tempCellData); break; case ERROR: tempCellData.setType(CellDataTypeEnum.ERROR); tempCellData.setStringValue(ERROR); - xlsReadContext.cellMap().put((int)frec.getColumn(), tempCellData); + cellMap.put((int)frec.getColumn(), tempCellData); break; case BOOLEAN: tempCellData.setType(CellDataTypeEnum.BOOLEAN); tempCellData.setBooleanValue(frec.getCachedBooleanValue()); - xlsReadContext.cellMap().put((int)frec.getColumn(), tempCellData); + cellMap.put((int)frec.getColumn(), tempCellData); break; default: tempCellData.setType(CellDataTypeEnum.EMPTY); - xlsReadContext.cellMap().put((int)frec.getColumn(), tempCellData); + cellMap.put((int)frec.getColumn(), tempCellData); break; } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java index 08a5a56..de21da8 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java @@ -4,7 +4,7 @@ import org.apache.poi.hssf.record.IndexRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; /** * Record handler diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java index 93259e6..1335ada 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java @@ -4,7 +4,7 @@ import org.apache.poi.hssf.record.LabelRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -17,8 +17,12 @@ public class LabelRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { LabelRecord lrec = (LabelRecord)record; - xlsReadContext.cellMap().put((int)lrec.getColumn(), - CellData.newInstance(lrec.getValue(), lrec.getRow(), (int)lrec.getColumn())); - xlsReadContext.tempRowType(RowTypeEnum.DATA); + String data = lrec.getValue(); + if (data != null && xlsReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) { + data = data.trim(); + } + xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)lrec.getColumn(), + CellData.newInstance(data, lrec.getRow(), (int)lrec.getColumn())); + xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSSTRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java similarity index 50% rename from src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSSTRecordHandler.java rename to src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java index 5e08ff8..7979241 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSSTRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java @@ -1,12 +1,15 @@ package com.alibaba.excel.analysis.v03.handlers; +import java.util.Map; + import org.apache.poi.hssf.record.LabelSSTRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.cache.ReadCache; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.Cell; import com.alibaba.excel.metadata.CellData; /** @@ -14,25 +17,26 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class LabelSSTRecordHandler implements IgnorableXlsRecordHandler { +public class LabelSstRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { LabelSSTRecord lsrec = (LabelSSTRecord)record; ReadCache readCache = xlsReadContext.readWorkbookHolder().getReadCache(); + Map cellMap = xlsReadContext.xlsReadSheetHolder().getCellMap(); if (readCache == null) { - xlsReadContext.cellMap().put((int)lsrec.getColumn(), - CellData.newEmptyInstance(lsrec.getRow(), (int)lsrec.getColumn())); + cellMap.put((int)lsrec.getColumn(), CellData.newEmptyInstance(lsrec.getRow(), (int)lsrec.getColumn())); return; } String data = readCache.get(lsrec.getSSTIndex()); if (data == null) { - xlsReadContext.cellMap().put((int)lsrec.getColumn(), - CellData.newEmptyInstance(lsrec.getRow(), (int)lsrec.getColumn())); + cellMap.put((int)lsrec.getColumn(), CellData.newEmptyInstance(lsrec.getRow(), (int)lsrec.getColumn())); return; } - xlsReadContext.cellMap().put((int)lsrec.getColumn(), - CellData.newInstance(data, lsrec.getRow(), (int)lsrec.getColumn())); - xlsReadContext.tempRowType(RowTypeEnum.DATA); + if (xlsReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) { + data = data.trim(); + } + cellMap.put((int)lsrec.getColumn(), CellData.newInstance(data, lsrec.getRow(), (int)lsrec.getColumn())); + xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java index 255eb98..8c2993d 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java @@ -4,7 +4,7 @@ import org.apache.poi.hssf.record.NoteRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.CellExtra; @@ -18,12 +18,12 @@ public class NoteRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { NoteRecord nr = (NoteRecord)record; - String note = xlsReadContext.objectCacheMap().get(nr.getShapeId()); + String note = xlsReadContext.xlsReadSheetHolder().getObjectCacheMap().get(nr.getShapeId()); CellExtra cellExtra = new CellExtra(); cellExtra.setRowIndex(nr.getRow()); cellExtra.setRowIndex(nr.getColumn()); cellExtra.setNote(note); - xlsReadContext.cellMap().put(nr.getColumn(), cellExtra); - xlsReadContext.tempRowType(RowTypeEnum.EXTRA); + xlsReadContext.xlsReadSheetHolder().getCellMap().put(nr.getColumn(), cellExtra); + xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.EXTRA); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java index 381bacd..5e2fbca 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -7,7 +7,7 @@ import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.constant.BuiltinFormats; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.CellData; @@ -22,12 +22,12 @@ public class NumberRecordHandler implements IgnorableXlsRecordHandler { public void processRecord(XlsReadContext xlsReadContext, Record record) { NumberRecord nr = (NumberRecord)record; CellData cellData = CellData.newInstance(BigDecimal.valueOf(nr.getValue()), nr.getRow(), (int)nr.getColumn()); - Integer dataFormat = xlsReadContext.formatTrackingHSSFListener().getFormatIndex(nr); + Integer dataFormat = xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(nr); cellData.setDataFormat(dataFormat); - cellData.setDataFormatString( - BuiltinFormats.getBuiltinFormat(dataFormat, xlsReadContext.formatTrackingHSSFListener().getFormatString(nr), - xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale())); - xlsReadContext.cellMap().put((int)nr.getColumn(), cellData); - xlsReadContext.tempRowType(RowTypeEnum.DATA); + cellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, + xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(nr), + xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale())); + xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)nr.getColumn(), cellData); + xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.DATA); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java index 5144a73..e8a0cc1 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java @@ -6,7 +6,7 @@ import org.apache.poi.hssf.record.Record; import org.apache.poi.hssf.record.SubRecord; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; /** * Record handler @@ -21,7 +21,7 @@ public class ObjRecordHandler implements IgnorableXlsRecordHandler { if (subRecord instanceof CommonObjectDataSubRecord) { CommonObjectDataSubRecord codsr = (CommonObjectDataSubRecord)subRecord; if (CommonObjectDataSubRecord.OBJECT_TYPE_COMMENT == codsr.getObjectType()) { - xlsReadContext.tempObjectIndex(codsr.getObjectId()); + xlsReadContext.xlsReadSheetHolder().setTempObjectIndex(codsr.getObjectId()); } break; } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java index cc902ef..22ba166 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java @@ -4,7 +4,7 @@ import org.apache.poi.hssf.record.RKRecord; import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.metadata.CellData; /** @@ -17,6 +17,7 @@ public class RkRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { RKRecord re = (RKRecord)record; - xlsReadContext.cellMap().put((int)re.getColumn(), CellData.newEmptyInstance(re.getRow(), (int)re.getColumn())); + xlsReadContext.xlsReadSheetHolder().getCellMap().put((int)re.getColumn(), + CellData.newEmptyInstance(re.getRow(), (int)re.getColumn())); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java index 7f0f01d..c11ff4c 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java @@ -5,7 +5,7 @@ import org.apache.poi.hssf.record.SSTRecord; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.cache.XlsCache; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; /** * Record handler diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java index 63e6953..e4c40ec 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java @@ -6,8 +6,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; /** * Record handler @@ -21,13 +22,14 @@ public class StringRecordHandler implements IgnorableXlsRecordHandler { public void processRecord(XlsReadContext xlsReadContext, Record record) { // String for formula StringRecord srec = (StringRecord)record; - CellData tempCellData = xlsReadContext.tempCellData(); + XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); + CellData tempCellData = xlsReadSheetHolder.getTempCellData(); if (tempCellData == null) { LOGGER.warn("String type formula but no value found."); return; } tempCellData.setStringValue(srec.getString()); - xlsReadContext.cellMap().put(tempCellData.getColumnIndex(), tempCellData); - xlsReadContext.tempCellData(null); + xlsReadSheetHolder.getCellMap().put(tempCellData.getColumnIndex(), tempCellData); + xlsReadSheetHolder.setTempCellData(null); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java index 764b69e..1ee3543 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java @@ -6,7 +6,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; /** * Record handler @@ -19,12 +20,13 @@ public class TextObjectRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { TextObjectRecord tor = (TextObjectRecord)record; - Integer tempObjectIndex = xlsReadContext.tempObjectIndex(); + XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); + Integer tempObjectIndex = xlsReadSheetHolder.getTempObjectIndex(); if (tempObjectIndex == null) { LOGGER.debug("tempObjectIndex is null."); return; } - xlsReadContext.objectCacheMap().put(tempObjectIndex, tor.getStr().getString()); - xlsReadContext.tempObjectIndex(null); + xlsReadSheetHolder.getObjectCacheMap().put(tempObjectIndex, tor.getStr().getString()); + xlsReadSheetHolder.setTempObjectIndex(null); } } diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java index 9f03bcf..8172b65 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java @@ -1,6 +1,7 @@ package com.alibaba.excel.context; import java.io.InputStream; +import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,6 +14,10 @@ import com.alibaba.excel.read.metadata.holder.ReadHolder; import com.alibaba.excel.read.metadata.holder.ReadRowHolder; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; import com.alibaba.excel.read.processor.AnalysisEventProcessor; import com.alibaba.excel.read.processor.DefalutAnalysisEventProcessor; import com.alibaba.excel.support.ExcelTypeEnum; @@ -44,11 +49,20 @@ public class AnalysisContextImpl implements AnalysisContext { */ private AnalysisEventProcessor analysisEventProcessor; - public AnalysisContextImpl(ReadWorkbook readWorkbook) { + public AnalysisContextImpl(ReadWorkbook readWorkbook, ExcelTypeEnum actualExcelType) { if (readWorkbook == null) { throw new IllegalArgumentException("Workbook argument cannot be null"); } - readWorkbookHolder = new ReadWorkbookHolder(readWorkbook); + switch (actualExcelType) { + case XLS: + readWorkbookHolder = new XlsReadWorkbookHolder(readWorkbook); + break; + case XLSX: + readWorkbookHolder = new XlsxReadWorkbookHolder(readWorkbook); + break; + default: + break; + } currentReadHolder = readWorkbookHolder; analysisEventProcessor = new DefalutAnalysisEventProcessor(); if (LOGGER.isDebugEnabled()) { @@ -58,7 +72,16 @@ public class AnalysisContextImpl implements AnalysisContext { @Override public void currentSheet(ReadSheet readSheet) { - readSheetHolder = new ReadSheetHolder(readSheet, readWorkbookHolder); + switch (readWorkbookHolder.getExcelType()) { + case XLS: + readSheetHolder = new XlsReadSheetHolder(readSheet, readWorkbookHolder); + break; + case XLSX: + readSheetHolder = new XlsxReadSheetHolder(readSheet, readWorkbookHolder); + break; + default: + break; + } currentReadHolder = readSheetHolder; if (readWorkbookHolder.getHasReadSheet().contains(readSheetHolder.getSheetNo())) { throw new ExcelAnalysisException("Cannot read sheet repeatedly."); @@ -104,6 +127,26 @@ public class AnalysisContextImpl implements AnalysisContext { return analysisEventProcessor; } + @Override + public List readSheetList() { + return null; + } + + @Override + public void readSheetList(List readSheetList) { + + } + + @Override + public Boolean readAll() { + return null; + } + + @Override + public void readAll(Boolean readAll) { + + } + @Override public Sheet getCurrentSheet() { Sheet sheet = new Sheet(readSheetHolder.getSheetNo() + 1); diff --git a/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java b/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java deleted file mode 100644 index 9487859..0000000 --- a/src/main/java/com/alibaba/excel/context/DefaultXlsReadContext.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.alibaba.excel.context; - -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import org.apache.poi.hssf.record.BoundSheetRecord; - -import com.alibaba.excel.enums.RowTypeEnum; -import com.alibaba.excel.metadata.Cell; -import com.alibaba.excel.metadata.CellData; -import com.alibaba.excel.metadata.CellExtra; -import com.alibaba.excel.read.metadata.ReadSheet; -import com.alibaba.excel.read.metadata.ReadWorkbook; - -/** - * - * A context is the main anchorage point of a ls xls reader. - * - * @author Jiaju Zhuang - */ -public class DefaultXlsReadContext extends AnalysisContextImpl implements XlsReadContext { - private Map cellMap; - private RowTypeEnum rowType; - private Integer rowIndex; - private CellData cellData; - private CellExtra cellExtra; - /** - * Excel 2003 cannot read specific sheet. It can only read sheet by sheet.So when you specify one sheet, you ignore - * the others. - */ - private Boolean ignoreRecord; - - /** - * Bound sheet record - * - * @return - */ - List boundSheetRecordList; - - public DefaultXlsReadContext(ReadWorkbook readWorkbook) { - super(readWorkbook); - cellMap = new LinkedHashMap(); - rowType = RowTypeEnum.EMPTY; - boundSheetRecordList = new ArrayList(); - } - - @Override - public RowTypeEnum rowType() { - return null; - } - - @Override - public void rowType(RowTypeEnum rowType) { - - } - - @Override - public RowTypeEnum tempRowType() { - return null; - } - - @Override - public void tempRowType(RowTypeEnum tempRowType) { - - } - - @Override - public CellData cellData() { - return null; - } - - @Override - public void cellData(CellData cellData) { - - } - - @Override - public CellExtra cellExtra() { - return null; - } - - @Override - public void cellExtra(CellExtra cellExtra) { - - } - - @Override - public Map cellMap() { - return null; - } - - @Override - public void cellMap(Map cellMap) { - - } - - @Override - public Integer rowIndex() { - return null; - } - - @Override - public void rowIndex(Integer rowIndex) { - - } - - @Override - public Boolean ignoreRecord() { - return null; - } - - @Override - public void ignoreRecord(Boolean ignoreRecord) { - - } - - @Override - public void currentSheet0(ReadSheet readSheet) { - currentSheet(readSheet); - cellMap = new LinkedHashMap(); - ignoreRecord = Boolean.FALSE; - rowType = RowTypeEnum.EMPTY; - } -} diff --git a/src/main/java/com/alibaba/excel/context/XlsReadContext.java b/src/main/java/com/alibaba/excel/context/XlsReadContext.java deleted file mode 100644 index 7af83cb..0000000 --- a/src/main/java/com/alibaba/excel/context/XlsReadContext.java +++ /dev/null @@ -1,95 +0,0 @@ -package com.alibaba.excel.context; - -import java.util.List; -import java.util.Map; - -import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; -import org.apache.poi.hssf.record.BoundSheetRecord; -import org.apache.poi.hssf.usermodel.HSSFWorkbook; - -import com.alibaba.excel.enums.RowTypeEnum; -import com.alibaba.excel.metadata.Cell; -import com.alibaba.excel.metadata.CellData; -import com.alibaba.excel.metadata.CellExtra; -import com.alibaba.excel.read.metadata.ReadSheet; - -/** - * - * A context is the main anchorage point of a ls xls reader. - * - * @author Jiaju Zhuang - */ -public interface XlsReadContext extends AnalysisContext { - - RowTypeEnum tempRowType(); - - void tempRowType(RowTypeEnum tempRowType); - - CellData cellData(); - - void cellData(CellData cellData); - - CellExtra cellExtra(); - - void cellExtra(CellExtra cellExtra); - - Map cellMap(); - - void cellMap(Map cellMap); - - Integer rowIndex(); - - void rowIndex(Integer rowIndex); - - Boolean ignoreRecord(); - - void ignoreRecord(Boolean ignoreRecord); - - /** - * Select the current table - * - * @param readSheet - * sheet to read - */ - void currentSheet0(ReadSheet readSheet); - - FormatTrackingHSSFListener formatTrackingHSSFListener(); - - HSSFWorkbook hsffWorkbook(); - - List boundSheetRecordList(); - - void boundSheetRecordList(List boundSheetRecordList); - - /** - * Actual data - * - * @return - */ - List readSheetDataList(); - - /** - * Actual data - * - * @return - */ - void readSheetDataList(List readSheetDataList); - - Boolean needReadSheet(); - - void needReadSheet(Boolean needReadSheet); - - Integer readSheetIndex(); - - void readSheetIndex(Integer readSheetIndex); - - CellData tempCellData(); - - void tempCellData(CellData tempCellData); - - Integer tempObjectIndex(); - - void tempObjectIndex(Integer tempObjectIndex); - - Map objectCacheMap(); -} diff --git a/src/main/java/com/alibaba/excel/context/xls/DefaultXlsReadContext.java b/src/main/java/com/alibaba/excel/context/xls/DefaultXlsReadContext.java new file mode 100644 index 0000000..698bf6a --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/xls/DefaultXlsReadContext.java @@ -0,0 +1,30 @@ +package com.alibaba.excel.context.xls; + +import com.alibaba.excel.context.AnalysisContextImpl; +import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * + * A context is the main anchorage point of a ls xls reader. + * + * @author Jiaju Zhuang + */ +public class DefaultXlsReadContext extends AnalysisContextImpl implements XlsReadContext { + + public DefaultXlsReadContext(ReadWorkbook readWorkbook, ExcelTypeEnum actualExcelType) { + super(readWorkbook, actualExcelType); + } + + @Override + public XlsReadWorkbookHolder xlsReadWorkbookHolder() { + return (XlsReadWorkbookHolder)readWorkbookHolder(); + } + + @Override + public XlsReadSheetHolder xlsReadSheetHolder() { + return (XlsReadSheetHolder)readSheetHolder(); + } +} diff --git a/src/main/java/com/alibaba/excel/context/xls/XlsReadContext.java b/src/main/java/com/alibaba/excel/context/xls/XlsReadContext.java new file mode 100644 index 0000000..4d1bcdb --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/xls/XlsReadContext.java @@ -0,0 +1,26 @@ +package com.alibaba.excel.context.xls; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; + +/** + * A context is the main anchorage point of a ls xls reader. + * + * @author Jiaju Zhuang + **/ +public interface XlsReadContext extends AnalysisContext { + /** + * All information about the workbook you are currently working on. + * + * @return Current workbook holder + */ + XlsReadWorkbookHolder xlsReadWorkbookHolder(); + + /** + * All information about the sheet you are currently working on. + * + * @return Current sheet holder + */ + XlsReadSheetHolder xlsReadSheetHolder(); +} diff --git a/src/main/java/com/alibaba/excel/context/xlsx/DefaultXlsxReadContext.java b/src/main/java/com/alibaba/excel/context/xlsx/DefaultXlsxReadContext.java new file mode 100644 index 0000000..5c9d638 --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/xlsx/DefaultXlsxReadContext.java @@ -0,0 +1,30 @@ +package com.alibaba.excel.context.xlsx; + +import com.alibaba.excel.context.AnalysisContextImpl; +import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; +import com.alibaba.excel.support.ExcelTypeEnum; + +/** + * + * A context is the main anchorage point of a ls xls reader. + * + * @author Jiaju Zhuang + */ +public class DefaultXlsxReadContext extends AnalysisContextImpl implements XlsxReadContext { + + public DefaultXlsxReadContext(ReadWorkbook readWorkbook, ExcelTypeEnum actualExcelType) { + super(readWorkbook, actualExcelType); + } + + @Override + public XlsxReadWorkbookHolder xlsxReadWorkbookHolder() { + return (XlsxReadWorkbookHolder)readWorkbookHolder(); + } + + @Override + public XlsxReadSheetHolder xlsxReadSheetHolder() { + return (XlsxReadSheetHolder)readSheetHolder(); + } +} diff --git a/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java b/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java new file mode 100644 index 0000000..924cafe --- /dev/null +++ b/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java @@ -0,0 +1,28 @@ +package com.alibaba.excel.context.xlsx; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; + +/** + * A context is the main anchorage point of a ls xlsx reader. + * + * @author Jiaju Zhuang + **/ +public interface XlsxReadContext extends AnalysisContext { + /** + * All information about the workbook you are currently working on. + * + * @return Current workbook holder + */ + XlsxReadWorkbookHolder xlsxReadWorkbookHolder(); + + /** + * All information about the sheet you are currently working on. + * + * @return Current sheet holder + */ + XlsxReadSheetHolder xlsxReadSheetHolder(); +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java index b97395e..1c1b242 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java @@ -4,6 +4,7 @@ import java.io.BufferedInputStream; import java.io.File; import java.io.InputStream; import java.util.HashSet; +import java.util.List; import java.util.Set; import javax.xml.parsers.SAXParserFactory; @@ -20,6 +21,7 @@ import com.alibaba.excel.enums.ExtraReadEnum; import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.support.ExcelTypeEnum; @@ -86,23 +88,25 @@ public class ReadWorkbookHolder extends AbstractReadHolder { * Whether the encryption */ private String password; - /** - * SAXParserFactory used when reading xlsx. - *

- * The default will automatically find. - *

- * Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl" - * - * @see SAXParserFactory#newInstance() - * @see SAXParserFactory#newInstance(String, ClassLoader) - */ - private String xlsxSAXParserFactoryName; /** * Read some additional fields. None are read by default. * * @see ExtraReadEnum */ private Set extraReadSet; + /** + * Actual sheet data + */ + private List actualSheetDataList; + /** + * Parameter sheet data + */ + private List parametersheetDataList; + /** + * Read all + */ + private Boolean readAll; + /** * The default is all excel objects.if true , you can use {@link com.alibaba.excel.annotation.ExcelIgnore} ignore a * field. if false , you must use {@link com.alibaba.excel.annotation.ExcelProperty} to use a filed. @@ -122,14 +126,6 @@ public class ReadWorkbookHolder extends AbstractReadHolder { * Prevent repeating sheet */ private Set hasReadSheet; - /** - * Package - */ - private OPCPackage opcPackage; - /** - * File System - */ - private POIFSFileSystem poifsFileSystem; public ReadWorkbookHolder(ReadWorkbook readWorkbook) { super(readWorkbook, null, readWorkbook.getConvertAllFiled()); @@ -184,7 +180,6 @@ public class ReadWorkbookHolder extends AbstractReadHolder { } else { this.defaultReturnMap = readWorkbook.getDefaultReturnMap(); } - this.xlsxSAXParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName(); if (readWorkbook.getExtraReadSet() == null) { this.extraReadSet = new HashSet(); } else { @@ -306,44 +301,44 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.defaultReturnMap = defaultReturnMap; } - public OPCPackage getOpcPackage() { - return opcPackage; + public String getPassword() { + return password; } - public void setOpcPackage(OPCPackage opcPackage) { - this.opcPackage = opcPackage; + public void setPassword(String password) { + this.password = password; } - public POIFSFileSystem getPoifsFileSystem() { - return poifsFileSystem; + public Set getExtraReadSet() { + return extraReadSet; } - public void setPoifsFileSystem(POIFSFileSystem poifsFileSystem) { - this.poifsFileSystem = poifsFileSystem; + public void setExtraReadSet(Set extraReadSet) { + this.extraReadSet = extraReadSet; } - public String getPassword() { - return password; + public List getActualSheetDataList() { + return actualSheetDataList; } - public void setPassword(String password) { - this.password = password; + public void setActualSheetDataList(List actualSheetDataList) { + this.actualSheetDataList = actualSheetDataList; } - public String getXlsxSAXParserFactoryName() { - return xlsxSAXParserFactoryName; + public List getParametersheetDataList() { + return parametersheetDataList; } - public void setXlsxSAXParserFactoryName(String xlsxSAXParserFactoryName) { - this.xlsxSAXParserFactoryName = xlsxSAXParserFactoryName; + public void setParametersheetDataList(List parametersheetDataList) { + this.parametersheetDataList = parametersheetDataList; } - public Set getExtraReadSet() { - return extraReadSet; + public Boolean getReadAll() { + return readAll; } - public void setExtraReadSet(Set extraReadSet) { - this.extraReadSet = extraReadSet; + public void setReadAll(Boolean readAll) { + this.readAll = readAll; } @Override diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java new file mode 100644 index 0000000..a77a8d3 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java @@ -0,0 +1,112 @@ +package com.alibaba.excel.read.metadata.holder.xls; + +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.Cell; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; + +/** + * sheet holder + * + * @author Jiaju Zhuang + */ +public class XlsReadSheetHolder extends ReadSheetHolder { + /** + * Row type.Temporary storage, last set in ReadRowHolder. + */ + private RowTypeEnum tempRowType; + /** + * Data storage of the current row. + */ + private Map cellMap; + /** + * Index of the current row. + */ + private Integer rowIndex; + /** + * Ignore record. + */ + private Boolean ignoreRecord; + /** + * Temp Cell Data. + */ + private CellData tempCellData; + /** + * Temp object index. + */ + private Integer tempObjectIndex; + /** + * Temp object index. + */ + private Map objectCacheMap; + + public XlsReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { + super(readSheet, readWorkbookHolder); + cellMap = new LinkedHashMap(); + ignoreRecord = Boolean.FALSE; + tempRowType = RowTypeEnum.EMPTY; + objectCacheMap = new HashMap(16); + } + + public RowTypeEnum getTempRowType() { + return tempRowType; + } + + public void setTempRowType(RowTypeEnum tempRowType) { + this.tempRowType = tempRowType; + } + + public Map getCellMap() { + return cellMap; + } + + public void setCellMap(Map cellMap) { + this.cellMap = cellMap; + } + + public Integer getRowIndex() { + return rowIndex; + } + + public void setRowIndex(Integer rowIndex) { + this.rowIndex = rowIndex; + } + + public Boolean getIgnoreRecord() { + return ignoreRecord; + } + + public void setIgnoreRecord(Boolean ignoreRecord) { + this.ignoreRecord = ignoreRecord; + } + + public CellData getTempCellData() { + return tempCellData; + } + + public void setTempCellData(CellData tempCellData) { + this.tempCellData = tempCellData; + } + + public Integer getTempObjectIndex() { + return tempObjectIndex; + } + + public void setTempObjectIndex(Integer tempObjectIndex) { + this.tempObjectIndex = tempObjectIndex; + } + + public Map getObjectCacheMap() { + return objectCacheMap; + } + + public void setObjectCacheMap(Map objectCacheMap) { + this.objectCacheMap = objectCacheMap; + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java new file mode 100644 index 0000000..c4b698c --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java @@ -0,0 +1,95 @@ +package com.alibaba.excel.read.metadata.holder.xls; + +import java.util.List; + +import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; +import org.apache.poi.hssf.record.BoundSheetRecord; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.apache.poi.poifs.filesystem.POIFSFileSystem; + +import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; + +/** + * Workbook holder + * + * @author Jiaju Zhuang + */ +public class XlsReadWorkbookHolder extends ReadWorkbookHolder { + /** + * File System + */ + private POIFSFileSystem poifsFileSystem; + /** + * Format tracking HSSFListener + */ + private FormatTrackingHSSFListener formatTrackingHSSFListener; + /** + * HSSFWorkbook + */ + private HSSFWorkbook hsffWorkbook; + /** + * Bound sheet record list. + */ + private List boundSheetRecordList; + /** + * Need read sheet. + */ + private Boolean needReadSheet; + /** + * Sheet Index + */ + private Integer readSheetIndex; + + public XlsReadWorkbookHolder(ReadWorkbook readWorkbook) { + super(readWorkbook); + } + + public POIFSFileSystem getPoifsFileSystem() { + return poifsFileSystem; + } + + public void setPoifsFileSystem(POIFSFileSystem poifsFileSystem) { + this.poifsFileSystem = poifsFileSystem; + } + + public FormatTrackingHSSFListener getFormatTrackingHSSFListener() { + return formatTrackingHSSFListener; + } + + public void setFormatTrackingHSSFListener(FormatTrackingHSSFListener formatTrackingHSSFListener) { + this.formatTrackingHSSFListener = formatTrackingHSSFListener; + } + + public HSSFWorkbook getHsffWorkbook() { + return hsffWorkbook; + } + + public void setHsffWorkbook(HSSFWorkbook hsffWorkbook) { + this.hsffWorkbook = hsffWorkbook; + } + + public List getBoundSheetRecordList() { + return boundSheetRecordList; + } + + public void setBoundSheetRecordList(List boundSheetRecordList) { + this.boundSheetRecordList = boundSheetRecordList; + } + + public Boolean getNeedReadSheet() { + return needReadSheet; + } + + public void setNeedReadSheet(Boolean needReadSheet) { + this.needReadSheet = needReadSheet; + } + + public Integer getReadSheetIndex() { + return readSheetIndex; + } + + public void setReadSheetIndex(Integer readSheetIndex) { + this.readSheetIndex = readSheetIndex; + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java new file mode 100644 index 0000000..b7439c3 --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java @@ -0,0 +1,16 @@ +package com.alibaba.excel.read.metadata.holder.xlsx; + +import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; + +/** + * sheet holder + * + * @author Jiaju Zhuang + */ +public class XlsxReadSheetHolder extends ReadSheetHolder { + public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { + super(readSheet, readWorkbookHolder); + } +} diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java new file mode 100644 index 0000000..34ec6ad --- /dev/null +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java @@ -0,0 +1,52 @@ +package com.alibaba.excel.read.metadata.holder.xlsx; + +import javax.xml.parsers.SAXParserFactory; + +import org.apache.poi.openxml4j.opc.OPCPackage; + +import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; + +/** + * Workbook holder + * + * @author Jiaju Zhuang + */ +public class XlsxReadWorkbookHolder extends ReadWorkbookHolder { + /** + * Package + */ + private OPCPackage opcPackage; + /** + * SAXParserFactory used when reading xlsx. + *

+ * The default will automatically find. + *

+ * Please pass in the name of a class ,like : "com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl" + * + * @see SAXParserFactory#newInstance() + * @see SAXParserFactory#newInstance(String, ClassLoader) + */ + private String saxParserFactoryName; + + public XlsxReadWorkbookHolder(ReadWorkbook readWorkbook) { + super(readWorkbook); + this.saxParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName(); + } + + public OPCPackage getOpcPackage() { + return opcPackage; + } + + public void setOpcPackage(OPCPackage opcPackage) { + this.opcPackage = opcPackage; + } + + public String getSaxParserFactoryName() { + return saxParserFactoryName; + } + + public void setSaxParserFactoryName(String saxParserFactoryName) { + this.saxParserFactoryName = saxParserFactoryName; + } +} diff --git a/src/main/java/com/alibaba/excel/util/SheetUtils.java b/src/main/java/com/alibaba/excel/util/SheetUtils.java index 398fe5a..492789c 100644 --- a/src/main/java/com/alibaba/excel/util/SheetUtils.java +++ b/src/main/java/com/alibaba/excel/util/SheetUtils.java @@ -3,7 +3,7 @@ package com.alibaba.excel.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.excel.context.XlsReadContext; +import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.read.metadata.ReadSheet; /** From 88de089c1068cf4f92c4b419bf0bb8494e6c8f6f Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Thu, 2 Jan 2020 21:30:47 +0800 Subject: [PATCH 11/38] =?UTF-8?q?=E5=A1=AB=E5=85=85=E6=97=B6=E5=80=99?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=A0=B9=E6=8D=AE`sheetName`=E5=AE=9A?= =?UTF-8?q?=E4=BD=8D`sheet`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../v07/handlers/DefaultCellHandler.java | 6 +- .../handlers/ProcessResultCellHandler.java | 5 +- .../excel/context/WriteContextImpl.java | 68 +++++++++++------- .../com/alibaba/excel/util/PositionUtils.java | 25 +++++++ .../metadata/holder/WriteSheetHolder.java | 6 +- .../metadata/holder/WriteWorkbookHolder.java | 25 +++++-- .../test/core/fill/FillDataTest.java | 25 +++++++ src/test/resources/fill/byName.xls | Bin 0 -> 28160 bytes src/test/resources/fill/byName.xlsx | Bin 0 -> 11489 bytes update.md | 4 ++ 11 files changed, 126 insertions(+), 40 deletions(-) create mode 100644 src/test/resources/fill/byName.xls create mode 100644 src/test/resources/fill/byName.xlsx diff --git a/pom.xml b/pom.xml index 415b45a..844f70c 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.1.4 + 2.1.5 jar easyexcel diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java index e0b9c41..e53c3cc 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -36,7 +36,7 @@ import com.alibaba.excel.util.PositionUtils; public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder { private final AnalysisContext analysisContext; private Deque currentTagDeque = new LinkedList(); - private int curCol; + private int curCol = -1; private Map curRowContent = new LinkedHashMap(); private CellData currentCellData; private StringBuilder dataStringBuilder; @@ -55,6 +55,7 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder @Override public void clearResult() { curRowContent = new LinkedHashMap(); + curCol=-1; } @Override @@ -68,7 +69,8 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder currentTagDeque.push(name); // start a cell if (CELL_TAG.equals(name)) { - curCol = PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.POSITION)); + curCol = PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.POSITION),curCol); + // t="s" ,it's means String // t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml' diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java index 9581646..c854242 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java @@ -20,6 +20,7 @@ import com.alibaba.excel.util.PositionUtils; public class ProcessResultCellHandler implements XlsxCellHandler { private AnalysisContext analysisContext; private XlsxRowResultHolder rowResultHandler; + private int currentRow = -1; public ProcessResultCellHandler(AnalysisContext analysisContext, XlsxRowResultHolder rowResultHandler) { this.analysisContext = analysisContext; @@ -33,9 +34,9 @@ public class ProcessResultCellHandler implements XlsxCellHandler { @Override public void startHandle(String name, Attributes attributes) { + currentRow = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION),currentRow); analysisContext.readRowHolder( - new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION)), - analysisContext.readSheetHolder().getGlobalConfiguration())); + new ReadRowHolder(currentRow, analysisContext.readSheetHolder().getGlobalConfiguration())); } @Override diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index a07ad4c..890bef2 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -103,37 +103,44 @@ public class WriteContextImpl implements WriteContext { */ @Override public void currentSheet(WriteSheet writeSheet, WriteTypeEnum writeType) { - if (writeSheet == null) { - throw new IllegalArgumentException("Sheet argument cannot be null"); + boolean illegalArgument = + writeSheet == null || (writeSheet.getSheetNo() == null && StringUtils.isEmpty(writeSheet.getSheetName())); + if (illegalArgument) { + throw new IllegalArgumentException("Sheet name and Sheet number can not be empty."); } - if (writeSheet.getSheetNo() == null || writeSheet.getSheetNo() <= 0) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Sheet number is null"); - } - writeSheet.setSheetNo(0); - } - if (writeWorkbookHolder.getHasBeenInitializedSheet().containsKey(writeSheet.getSheetNo())) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Sheet:{} is already existed", writeSheet.getSheetNo()); - } - writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheet().get(writeSheet.getSheetNo()); - writeSheetHolder.setNewInitialization(Boolean.FALSE); - writeTableHolder = null; - currentWriteHolder = writeSheetHolder; - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("CurrentConfiguration is writeSheetHolder"); - } + if (selectSheetFromCache(writeSheet)) { return; } initCurrentSheetHolder(writeSheet); - WriteHandlerUtils.beforeSheetCreate(this); // Initialization current sheet initSheet(writeType); } + private boolean selectSheetFromCache(WriteSheet writeSheet) { + writeSheetHolder = null; + if (writeSheet.getSheetNo() != null) { + writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().get(writeSheet.getSheetNo()); + } + if (writeSheetHolder == null && !StringUtils.isEmpty(writeSheet.getSheetName())) { + writeSheetHolder = writeWorkbookHolder.getHasBeenInitializedSheetNameMap().get(writeSheet.getSheetName()); + } + if (writeSheetHolder == null) { + return false; + } + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Sheet:{} is already existed", writeSheet.getSheetNo()); + } + writeSheetHolder.setNewInitialization(Boolean.FALSE); + writeTableHolder = null; + currentWriteHolder = writeSheetHolder; + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("CurrentConfiguration is writeSheetHolder"); + } + return true; + } + private void initCurrentSheetHolder(WriteSheet writeSheet) { writeSheetHolder = new WriteSheetHolder(writeSheet, writeWorkbookHolder); - writeWorkbookHolder.getHasBeenInitializedSheet().put(writeSheet.getSheetNo(), writeSheetHolder); writeTableHolder = null; currentWriteHolder = writeSheetHolder; if (LOGGER.isDebugEnabled()) { @@ -142,15 +149,26 @@ public class WriteContextImpl implements WriteContext { } private void initSheet(WriteTypeEnum writeType) { + WriteHandlerUtils.beforeSheetCreate(this); Sheet currentSheet; try { - currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); - writeSheetHolder - .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo())); + if (writeSheetHolder.getSheetNo() != null) { + currentSheet = writeWorkbookHolder.getWorkbook().getSheetAt(writeSheetHolder.getSheetNo()); + writeSheetHolder + .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheetAt(writeSheetHolder.getSheetNo())); + } else { + // sheet name must not null + currentSheet = writeWorkbookHolder.getWorkbook().getSheet(writeSheetHolder.getSheetName()); + writeSheetHolder + .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheet(writeSheetHolder.getSheetName())); + } } catch (Exception e) { if (LOGGER.isDebugEnabled()) { LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo()); } + if (StringUtils.isEmpty(writeSheetHolder.getSheetName())) { + writeSheetHolder.setSheetName(writeSheetHolder.getSheetNo().toString()); + } currentSheet = WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName()); writeSheetHolder.setCachedSheet(currentSheet); } @@ -160,6 +178,8 @@ public class WriteContextImpl implements WriteContext { // Initialization head initHead(writeSheetHolder.excelWriteHeadProperty()); } + writeWorkbookHolder.getHasBeenInitializedSheetIndexMap().put(writeSheetHolder.getSheetNo(), writeSheetHolder); + writeWorkbookHolder.getHasBeenInitializedSheetNameMap().put(writeSheetHolder.getSheetName(), writeSheetHolder); } public void initHead(ExcelWriteHeadProperty excelWriteHeadProperty) { diff --git a/src/main/java/com/alibaba/excel/util/PositionUtils.java b/src/main/java/com/alibaba/excel/util/PositionUtils.java index f135e47..b85018f 100644 --- a/src/main/java/com/alibaba/excel/util/PositionUtils.java +++ b/src/main/java/com/alibaba/excel/util/PositionUtils.java @@ -14,6 +14,16 @@ public class PositionUtils { } return row; } + public static int getRowByRowTagt(String rowTagt,int before) { + int row ; + if (rowTagt != null) { + row = Integer.parseInt(rowTagt) - 1; + return row; + }else { + return before + 1; + } + + } public static int getRow(String currentCellIndex) { int row = 0; @@ -35,4 +45,19 @@ public class PositionUtils { } return col - 1; } + + public static int getCol(String currentCellIndex,int before) { + int col = 0; + if (currentCellIndex != null) { + + char[] currentIndex = currentCellIndex.replaceAll("[0-9]", "").toCharArray(); + for (int i = 0; i < currentIndex.length; i++) { + col += (currentIndex[i] - '@') * Math.pow(26, (currentIndex.length - i - 1)); + } + return col - 1; + }else { + return before +1; + } + } + } diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java index 90030f4..b74db29 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java @@ -68,11 +68,7 @@ public class WriteSheetHolder extends AbstractWriteHolder { super(writeSheet, writeWorkbookHolder, writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled()); this.writeSheet = writeSheet; this.sheetNo = writeSheet.getSheetNo(); - if (writeSheet.getSheetName() == null) { - this.sheetName = writeSheet.getSheetNo().toString(); - } else { - this.sheetName = writeSheet.getSheetName(); - } + this.sheetName = writeSheet.getSheetName(); this.parentWriteWorkbookHolder = writeWorkbookHolder; this.hasBeenInitializedTable = new HashMap(); if (writeWorkbookHolder.getTempTemplateInputStream() != null) { diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java index c8f7555..be557eb 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteWorkbookHolder.java @@ -92,7 +92,11 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { /** * prevent duplicate creation of sheet objects */ - private Map hasBeenInitializedSheet; + private Map hasBeenInitializedSheetIndexMap; + /** + * prevent duplicate creation of sheet objects + */ + private Map hasBeenInitializedSheetNameMap; /** * Whether the encryption */ @@ -148,7 +152,8 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { } else { this.mandatoryUseInputStream = writeWorkbook.getMandatoryUseInputStream(); } - this.hasBeenInitializedSheet = new HashMap(); + this.hasBeenInitializedSheetIndexMap = new HashMap(); + this.hasBeenInitializedSheetNameMap = new HashMap(); this.password = writeWorkbook.getPassword(); if (writeWorkbook.getInMemory() == null) { this.inMemory = Boolean.FALSE; @@ -197,12 +202,20 @@ public class WriteWorkbookHolder extends AbstractWriteHolder { this.cachedWorkbook = cachedWorkbook; } - public Map getHasBeenInitializedSheet() { - return hasBeenInitializedSheet; + public Map getHasBeenInitializedSheetIndexMap() { + return hasBeenInitializedSheetIndexMap; + } + + public void setHasBeenInitializedSheetIndexMap(Map hasBeenInitializedSheetIndexMap) { + this.hasBeenInitializedSheetIndexMap = hasBeenInitializedSheetIndexMap; + } + + public Map getHasBeenInitializedSheetNameMap() { + return hasBeenInitializedSheetNameMap; } - public void setHasBeenInitializedSheet(Map hasBeenInitializedSheet) { - this.hasBeenInitializedSheet = hasBeenInitializedSheet; + public void setHasBeenInitializedSheetNameMap(Map hasBeenInitializedSheetNameMap) { + this.hasBeenInitializedSheetNameMap = hasBeenInitializedSheetNameMap; } public WriteWorkbook getWriteWorkbook() { diff --git a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java index 04a8bd1..fe02163 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java @@ -39,6 +39,10 @@ public class FillDataTest { private static File horizontalFillTemplate07; private static File fileHorizontal03; private static File horizontalFillTemplate03; + private static File byName07; + private static File byName03; + private static File byNameTemplate07; + private static File byNameTemplate03; @BeforeClass public static void init() { @@ -54,6 +58,10 @@ public class FillDataTest { horizontalFillTemplate07 = TestFileUtil.readFile("fill" + File.separator + "horizontal.xlsx"); fileHorizontal03 = TestFileUtil.createNewFile("fillHorizontal03.xls"); horizontalFillTemplate03 = TestFileUtil.readFile("fill" + File.separator + "horizontal.xls"); + byName07 = TestFileUtil.createNewFile("byName07.xlsx"); + byNameTemplate07 = TestFileUtil.readFile("fill" + File.separator + "byName.xlsx"); + byName03 = TestFileUtil.createNewFile("byName03.xls"); + byNameTemplate03 = TestFileUtil.readFile("fill" + File.separator + "byName.xls"); } @Test @@ -86,6 +94,23 @@ public class FillDataTest { horizontalFill(fileHorizontal03, horizontalFillTemplate03); } + @Test + public void t07ByNameFill07() { + byNameFill(byName07, byNameTemplate07); + } + + @Test + public void t08ByNameFill03() { + byNameFill(byName03, byNameTemplate03); + } + + private void byNameFill(File file, File template) { + FillData fillData = new FillData(); + fillData.setName("张三"); + fillData.setNumber(5.2); + EasyExcel.write(file, FillData.class).withTemplate(template).sheet("Sheet2").doFill(fillData); + } + private void horizontalFill(File file, File template) { ExcelWriter excelWriter = EasyExcel.write(file).withTemplate(template).build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); diff --git a/src/test/resources/fill/byName.xls b/src/test/resources/fill/byName.xls new file mode 100644 index 0000000000000000000000000000000000000000..e07fd503eea2a3a933f7413e1486bdcc569e6a00 GIT binary patch literal 28160 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 ARsaA1 literal 0 HcmV?d00001 diff --git a/src/test/resources/fill/byName.xlsx b/src/test/resources/fill/byName.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..327e0557ac60ccee12309a7c44c2659436dad2ed GIT binary patch literal 11489 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 a{*_4NrJ+HD`Z Date: Thu, 2 Jan 2020 21:49:28 +0800 Subject: [PATCH 12/38] =?UTF-8?q?=E5=A1=AB=E5=85=85=E6=97=B6=E5=80=99?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E6=A0=B9=E6=8D=AE`sheetName`=E5=AE=9A?= =?UTF-8?q?=E4=BD=8D`sheet`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/excel/context/WriteContextImpl.java | 6 ++---- .../excel/write/metadata/holder/WriteSheetHolder.java | 7 ++++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index 890bef2..df4840d 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -103,10 +103,8 @@ public class WriteContextImpl implements WriteContext { */ @Override public void currentSheet(WriteSheet writeSheet, WriteTypeEnum writeType) { - boolean illegalArgument = - writeSheet == null || (writeSheet.getSheetNo() == null && StringUtils.isEmpty(writeSheet.getSheetName())); - if (illegalArgument) { - throw new IllegalArgumentException("Sheet name and Sheet number can not be empty."); + if (writeSheet == null) { + throw new IllegalArgumentException("Sheet argument cannot be null"); } if (selectSheetFromCache(writeSheet)) { return; diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java index b74db29..56fc7e4 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/WriteSheetHolder.java @@ -10,6 +10,7 @@ import org.apache.poi.xssf.usermodel.XSSFSheet; import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.enums.WriteLastRowTypeEnum; +import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.write.metadata.WriteSheet; /** @@ -67,7 +68,11 @@ public class WriteSheetHolder extends AbstractWriteHolder { public WriteSheetHolder(WriteSheet writeSheet, WriteWorkbookHolder writeWorkbookHolder) { super(writeSheet, writeWorkbookHolder, writeWorkbookHolder.getWriteWorkbook().getConvertAllFiled()); this.writeSheet = writeSheet; - this.sheetNo = writeSheet.getSheetNo(); + if (writeSheet.getSheetNo() == null && StringUtils.isEmpty(writeSheet.getSheetName())) { + this.sheetNo = 0; + } else { + this.sheetNo = writeSheet.getSheetNo(); + } this.sheetName = writeSheet.getSheetName(); this.parentWriteWorkbookHolder = writeWorkbookHolder; this.hasBeenInitializedTable = new HashMap(); From c6f21608abaf933b880e180a4ed6ee6c1d3f7109 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Fri, 3 Jan 2020 20:08:18 +0800 Subject: [PATCH 13/38] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A1=AB=E5=85=85?= =?UTF-8?q?=E5=8F=AA=E6=9C=89`sheetName`=E4=BC=9A=E6=8A=9B=E5=BC=82?= =?UTF-8?q?=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + pom.xml | 2 +- .../excel/context/WriteContextImpl.java | 25 +++++++++++++------ update.md | 3 +++ 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 1251ebd..b142b9d 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ easyexcel [QQ群: 662022184](//shang.qq.com/wpa/qunwpa?idkey=53d9d821b0833e3c14670f007488a61e300f00ff4f1b81fd950590d90dd80f80) [钉钉群: 21960511](https://qr.dingtalk.com/action/joingroup?code=v1,k1,cchz6k12ci9B08NNqhNRFGXocNVHrZtW0kaOtTKg/Rk=&_dt_no_comment=1&origin=11) [官方网站: https://alibaba-easyexcel.github.io/](https://alibaba-easyexcel.github.io/) +#### 因为公司不方便用QQ,所以建议加钉钉群 # JAVA解析Excel工具easyexcel Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便 diff --git a/pom.xml b/pom.xml index 844f70c..fe46977 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.1.5 + 2.1.6 jar easyexcel diff --git a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java index df4840d..e79453c 100644 --- a/src/main/java/com/alibaba/excel/context/WriteContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/WriteContextImpl.java @@ -161,14 +161,10 @@ public class WriteContextImpl implements WriteContext { .setCachedSheet(writeWorkbookHolder.getCachedWorkbook().getSheet(writeSheetHolder.getSheetName())); } } catch (Exception e) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo()); - } - if (StringUtils.isEmpty(writeSheetHolder.getSheetName())) { - writeSheetHolder.setSheetName(writeSheetHolder.getSheetNo().toString()); - } - currentSheet = WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName()); - writeSheetHolder.setCachedSheet(currentSheet); + currentSheet = createSheet(); + } + if (currentSheet == null) { + currentSheet = createSheet(); } writeSheetHolder.setSheet(currentSheet); WriteHandlerUtils.afterSheetCreate(this); @@ -180,6 +176,19 @@ public class WriteContextImpl implements WriteContext { writeWorkbookHolder.getHasBeenInitializedSheetNameMap().put(writeSheetHolder.getSheetName(), writeSheetHolder); } + private Sheet createSheet() { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Can not find sheet:{} ,now create it", writeSheetHolder.getSheetNo()); + } + if (StringUtils.isEmpty(writeSheetHolder.getSheetName())) { + writeSheetHolder.setSheetName(writeSheetHolder.getSheetNo().toString()); + } + Sheet currentSheet = + WorkBookUtil.createSheet(writeWorkbookHolder.getWorkbook(), writeSheetHolder.getSheetName()); + writeSheetHolder.setCachedSheet(currentSheet); + return currentSheet; + } + public void initHead(ExcelWriteHeadProperty excelWriteHeadProperty) { if (!currentWriteHolder.needHead() || !currentWriteHolder.excelWriteHeadProperty().hasHead()) { return; diff --git a/update.md b/update.md index 35ecf49..4625810 100644 --- a/update.md +++ b/update.md @@ -1,3 +1,6 @@ +# 2.1.6 +* 修复填充只有`sheetName`会抛异常 + # 2.1.5 * 修复部分xlsx没有行号读取异常 * 填充时候支持根据`sheetName`定位`sheet` From 482c99076a1095c117b470367ff9542e64745111 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Fri, 3 Jan 2020 20:08:45 +0800 Subject: [PATCH 14/38] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=A1=AB=E5=85=85?= =?UTF-8?q?=E5=8F=AA=E6=9C=89`sheetName`=E4=BC=9A=E6=8A=9B=E5=BC=82?= =?UTF-8?q?=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- update.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/update.md b/update.md index 4625810..864a780 100644 --- a/update.md +++ b/update.md @@ -1,5 +1,5 @@ # 2.1.6 -* 修复填充只有`sheetName`会抛异常 +* 修复写入只有`sheetName`会抛异常 # 2.1.5 * 修复部分xlsx没有行号读取异常 From 1845b6b0a17a033b41edf9bedca3b10e54eaa6e9 Mon Sep 17 00:00:00 2001 From: dota17 Date: Thu, 27 Feb 2020 09:30:25 +0800 Subject: [PATCH 15/38] fix some typos --- .../{NoModleDataListener.java => NoModelDataListener.java} | 6 +++--- .../java/com/alibaba/easyexcel/test/demo/read/ReadTest.java | 4 ++-- .../com/alibaba/easyexcel/test/demo/write/WriteTest.java | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) rename src/test/java/com/alibaba/easyexcel/test/demo/read/{NoModleDataListener.java => NoModelDataListener.java} (92%) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/NoModleDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/NoModelDataListener.java similarity index 92% rename from src/test/java/com/alibaba/easyexcel/test/demo/read/NoModleDataListener.java rename to src/test/java/com/alibaba/easyexcel/test/demo/read/NoModelDataListener.java index 2e77538..ea47c23 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/NoModleDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/NoModelDataListener.java @@ -16,8 +16,8 @@ import com.alibaba.fastjson.JSON; * * @author Jiaju Zhuang */ -public class NoModleDataListener extends AnalysisEventListener> { - private static final Logger LOGGER = LoggerFactory.getLogger(NoModleDataListener.class); +public class NoModelDataListener extends AnalysisEventListener> { + private static final Logger LOGGER = LoggerFactory.getLogger(NoModelDataListener.class); /** * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 */ @@ -40,7 +40,7 @@ public class NoModleDataListener extends AnalysisEventListener Date: Thu, 27 Feb 2020 09:43:53 +0800 Subject: [PATCH 16/38] fix a typo --- .../alibaba/easyexcel/test/demo/read/NoModelDataListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/NoModelDataListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/NoModelDataListener.java index ea47c23..a48d3fc 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/NoModelDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/NoModelDataListener.java @@ -40,7 +40,7 @@ public class NoModelDataListener extends AnalysisEventListener Date: Thu, 27 Feb 2020 21:47:30 +0800 Subject: [PATCH 17/38] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=BD=93Data=E6=98=AFL?= =?UTF-8?q?inkedList=E6=97=B6=EF=BC=8C=E9=9A=8F=E7=9D=80=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E9=87=8F=E5=A2=9E=E5=8A=A0=E6=80=A7=E8=83=BD=E5=8F=98=E5=B7=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 入参为List,当List是LinkedList时,get方法性能很差 --- .../alibaba/excel/write/executor/ExcelWriteAddExecutor.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java index 5b0d8ae..a572fb7 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java @@ -46,9 +46,11 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { } // BeanMap is out of order,so use fieldList List fieldList = new ArrayList(); - for (int relativeRowIndex = 0; relativeRowIndex < data.size(); relativeRowIndex++) { + int relativeRowIndex=0; + for(Object oneRowData : data){ int n = relativeRowIndex + newRowIndex; - addOneRowOfDataToExcel(data.get(relativeRowIndex), n, relativeRowIndex, fieldList); + addOneRowOfDataToExcel(oneRowData, n, relativeRowIndex, fieldList); + relativeRowIndex++; } } From 13ca08e1d8601e23a535ad058e7015c903905cbc Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Sat, 14 Mar 2020 22:24:56 +0800 Subject: [PATCH 18/38] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E6=89=B9=E6=B3=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/analysis/ExcelAnalyserImpl.java | 21 ++-- .../excel/analysis/v07/XlsxCellHandler.java | 45 --------- .../analysis/v07/XlsxHandlerFactory.java | 1 + .../excel/analysis/v07/XlsxRowHandler.java | 81 --------------- .../excel/analysis/v07/XlsxSaxAnalyser.java | 98 ++++++++----------- .../v07/handlers/CountRowCellHandler.java | 26 +---- .../v07/handlers/DefaultCellHandler.java | 17 ---- .../handlers/ProcessResultCellHandler.java | 39 ++------ .../v07/handlers/XlsxCellHandler.java | 29 ++++++ .../sax}/SharedStringsTableHandler.java | 2 +- .../v07/handlers/sax/XlsxRowHandler.java | 58 +++++++++++ .../excel/context/AnalysisContextImpl.java | 4 +- .../excel/context/xlsx/XlsxReadContext.java | 2 - .../holder/xlsx/XlsxReadSheetHolder.java | 3 + .../holder/xlsx/XlsxReadWorkbookHolder.java | 13 +++ ...ava => DefaultAnalysisEventProcessor.java} | 12 ++- .../com/alibaba/excel/util/SheetUtils.java | 18 ++-- 17 files changed, 186 insertions(+), 283 deletions(-) delete mode 100644 src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java delete mode 100644 src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxCellHandler.java rename src/main/java/com/alibaba/excel/analysis/v07/{ => handlers/sax}/SharedStringsTableHandler.java (97%) create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java rename src/main/java/com/alibaba/excel/read/processor/{DefalutAnalysisEventProcessor.java => DefaultAnalysisEventProcessor.java} (96%) diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index 97ee3af..f8d81fa 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -14,9 +14,10 @@ import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.v03.XlsSaxAnalyser; import com.alibaba.excel.analysis.v07.XlsxSaxAnalyser; import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.context.AnalysisContextImpl; import com.alibaba.excel.context.xls.DefaultXlsReadContext; import com.alibaba.excel.context.xls.XlsReadContext; +import com.alibaba.excel.context.xlsx.DefaultXlsxReadContext; +import com.alibaba.excel.context.xlsx.XlsxReadContext; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.read.metadata.ReadSheet; @@ -74,8 +75,9 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { try { decryptedStream = DocumentFactoryHelper .getDecryptedStream(poifsFileSystem.getRoot().getFileSystem(), readWorkbook.getPassword()); - analysisContext = new AnalysisContextImpl(readWorkbook, ExcelTypeEnum.XLSX); - excelReadExecutor = new XlsxSaxAnalyser(analysisContext, decryptedStream); + XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX); + analysisContext = xlsxReadContext; + excelReadExecutor = new XlsxSaxAnalyser(xlsxReadContext, decryptedStream); return; } finally { IOUtils.closeQuietly(decryptedStream); @@ -93,8 +95,9 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { excelReadExecutor = new XlsSaxAnalyser(xlsReadContext); break; case XLSX: - analysisContext = new AnalysisContextImpl(readWorkbook, ExcelTypeEnum.XLSX); - excelReadExecutor = new XlsxSaxAnalyser(analysisContext, null); + XlsxReadContext xlsxReadContext = new DefaultXlsxReadContext(readWorkbook, ExcelTypeEnum.XLSX); + analysisContext = xlsxReadContext; + excelReadExecutor = new XlsxSaxAnalyser(xlsxReadContext, null); break; default: break; @@ -147,16 +150,16 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { } try { if ((readWorkbookHolder instanceof XlsxReadWorkbookHolder) - && ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage() != null) { - ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage().revert(); + && ((XlsxReadWorkbookHolder) readWorkbookHolder).getOpcPackage() != null) { + ((XlsxReadWorkbookHolder) readWorkbookHolder).getOpcPackage().revert(); } } catch (Throwable t) { throwable = t; } try { if ((readWorkbookHolder instanceof XlsReadWorkbookHolder) - && ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem() != null) { - ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem().close(); + && ((XlsReadWorkbookHolder) readWorkbookHolder).getPoifsFileSystem() != null) { + ((XlsReadWorkbookHolder) readWorkbookHolder).getPoifsFileSystem().close(); } } catch (Throwable t) { throwable = t; diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java deleted file mode 100644 index 3068725..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxCellHandler.java +++ /dev/null @@ -1,45 +0,0 @@ -package com.alibaba.excel.analysis.v07; - -import org.xml.sax.Attributes; - -/** - * Cell handler - * - * @author Dan Zheng - */ -public interface XlsxCellHandler { - /** - * Which tags are supported - * - * @param name - * Tag name - * @return Support parsing or not - */ - boolean support(String name); - - /** - * Start handle - * - * @param name - * Tag name - * @param attributes - * Tag attributes - */ - void startHandle(String name, Attributes attributes); - - /** - * End handle - * - * @param name - * Tag name - */ - void endHandle(String name); - - /** - * Set the comment of the cell - * - * @param comment - * cell comment - */ - void handleComments(String comment); -} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java index 82f7d2c..1785036 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java @@ -8,6 +8,7 @@ import org.apache.poi.xssf.model.StylesTable; import com.alibaba.excel.analysis.v07.handlers.CountRowCellHandler; import com.alibaba.excel.analysis.v07.handlers.DefaultCellHandler; import com.alibaba.excel.analysis.v07.handlers.ProcessResultCellHandler; +import com.alibaba.excel.analysis.v07.handlers.XlsxCellHandler; import com.alibaba.excel.context.AnalysisContext; /** diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java deleted file mode 100644 index bc433cf..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowHandler.java +++ /dev/null @@ -1,81 +0,0 @@ -package com.alibaba.excel.analysis.v07; - -import java.util.List; - -import org.apache.poi.ss.util.CellAddress; -import org.apache.poi.xssf.model.CommentsTable; -import org.apache.poi.xssf.model.StylesTable; -import org.apache.poi.xssf.usermodel.XSSFComment; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import com.alibaba.excel.constant.ExcelXmlConstants; -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.util.StringUtils; - -/** - * - * @author jipengfei - */ -public class XlsxRowHandler extends DefaultHandler { - - private List cellHandlers; - private XlsxRowResultHolder rowResultHolder; - private CommentsTable commentsTable; - - public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable, CommentsTable commentsTable) { - this(analysisContext, stylesTable); - this.commentsTable = commentsTable; - } - - public XlsxRowHandler(AnalysisContext analysisContext, StylesTable stylesTable) { - this.cellHandlers = XlsxHandlerFactory.buildCellHandlers(analysisContext, stylesTable); - for (XlsxCellHandler cellHandler : cellHandlers) { - if (cellHandler instanceof XlsxRowResultHolder) { - this.rowResultHolder = (XlsxRowResultHolder)cellHandler; - break; - } - } - } - - @Override - public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { - for (XlsxCellHandler cellHandler : cellHandlers) { - if (cellHandler.support(name)) { - cellHandler.startHandle(name, attributes); - handleComment(cellHandler, attributes.getValue(ExcelXmlConstants.POSITION)); - } - } - } - - @Override - public void endElement(String uri, String localName, String name) throws SAXException { - for (XlsxCellHandler cellHandler : cellHandlers) { - if (cellHandler.support(name)) { - cellHandler.endHandle(name); - } - } - } - - @Override - public void characters(char[] ch, int start, int length) throws SAXException { - if (rowResultHolder != null) { - rowResultHolder.appendCurrentCellValue(ch, start, length); - } - } - - private void handleComment(XlsxCellHandler cellHandler, String address) { - if (StringUtils.isEmpty(address) || null == commentsTable) { - return; - } - XSSFComment xssfComment = commentsTable.getCellComments().get(new CellAddress(address)); - if (null == xssfComment) { - return; - } - String comments = xssfComment.getString().toString(); - if (!StringUtils.isEmpty(comments)) { - cellHandler.handleComments(comments); - } - } -} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java index 374dc45..205b648 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java @@ -16,8 +16,6 @@ import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.openxml4j.opc.PackagePart; import org.apache.poi.xssf.eventusermodel.XSSFReader; -import org.apache.poi.xssf.model.CommentsTable; -import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.usermodel.XSSFRelation; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; @@ -27,45 +25,34 @@ import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import com.alibaba.excel.analysis.ExcelReadExecutor; +import com.alibaba.excel.analysis.v07.handlers.sax.SharedStringsTableHandler; +import com.alibaba.excel.analysis.v07.handlers.sax.XlsxRowHandler; import com.alibaba.excel.cache.ReadCache; -import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.context.xlsx.XlsxReadContext; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.read.metadata.ReadSheet; -import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.util.FileUtils; import com.alibaba.excel.util.SheetUtils; import com.alibaba.excel.util.StringUtils; /** - * * @author jipengfei */ public class XlsxSaxAnalyser implements ExcelReadExecutor { - private AnalysisContext analysisContext; + private XlsxReadContext xlsxReadContext; private List sheetList; private Map sheetMap; - /** - * excel comments - * key: sheetNo - * value: CommentsTanle - */ - private Map commentsTableMap; - - /** - * Current style information - */ - private StylesTable stylesTable; - - public XlsxSaxAnalyser(AnalysisContext analysisContext, InputStream decryptedStream) throws Exception { - this.analysisContext = analysisContext; + public XlsxSaxAnalyser(XlsxReadContext xlsxReadContext, InputStream decryptedStream) throws Exception { + this.xlsxReadContext = xlsxReadContext; // Initialize cache - ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); + XlsxReadWorkbookHolder xlsxReadWorkbookHolder = xlsxReadContext.xlsxReadWorkbookHolder(); - OPCPackage pkg = readOpcPackage(readWorkbookHolder, decryptedStream); - readWorkbookHolder.setOpcPackage(pkg); + OPCPackage pkg = readOpcPackage(xlsxReadWorkbookHolder, decryptedStream); + xlsxReadWorkbookHolder.setOpcPackage(pkg); ArrayList packageParts = pkg.getPartsByContentType(XSSFRelation.SHARED_STRINGS.getContentType()); @@ -73,20 +60,19 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { PackagePart sharedStringsTablePackagePart = packageParts.get(0); // Specify default cache - defaultReadCache(readWorkbookHolder, sharedStringsTablePackagePart); + defaultReadCache(xlsxReadWorkbookHolder, sharedStringsTablePackagePart); // Analysis sharedStringsTable.xml - analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), readWorkbookHolder); + analysisSharedStringsTable(sharedStringsTablePackagePart.getInputStream(), xlsxReadWorkbookHolder); } XSSFReader xssfReader = new XSSFReader(pkg); - analysisUse1904WindowDate(xssfReader, readWorkbookHolder); + analysisUse1904WindowDate(xssfReader, xlsxReadWorkbookHolder); - stylesTable = xssfReader.getStylesTable(); + xlsxReadWorkbookHolder.setStylesTable(xssfReader.getStylesTable()); sheetList = new ArrayList(); sheetMap = new HashMap(); - commentsTableMap = new HashMap(); - XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); + XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator) xssfReader.getSheetsData(); int index = 0; if (!ite.hasNext()) { throw new ExcelAnalysisException("Can not find any sheet!"); @@ -95,23 +81,19 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { InputStream inputStream = ite.next(); sheetList.add(new ReadSheet(index, ite.getSheetName())); sheetMap.put(index, inputStream); - CommentsTable commentsTable = ite.getSheetComments(); - if (null != commentsTable) { - commentsTableMap.put(index, commentsTable); - } index++; } } - private void defaultReadCache(ReadWorkbookHolder readWorkbookHolder, PackagePart sharedStringsTablePackagePart) { - ReadCache readCache = readWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart); - readWorkbookHolder.setReadCache(readCache); - readCache.init(analysisContext); + private void defaultReadCache(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, PackagePart sharedStringsTablePackagePart) { + ReadCache readCache = xlsxReadWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart); + xlsxReadWorkbookHolder.setReadCache(readCache); + readCache.init(xlsxReadContext); } - private void analysisUse1904WindowDate(XSSFReader xssfReader, ReadWorkbookHolder readWorkbookHolder) + private void analysisUse1904WindowDate(XSSFReader xssfReader, XlsxReadWorkbookHolder xlsxReadWorkbookHolder) throws Exception { - if (readWorkbookHolder.globalConfiguration().getUse1904windowing() != null) { + if (xlsxReadWorkbookHolder.globalConfiguration().getUse1904windowing() != null) { return; } InputStream workbookXml = xssfReader.getWorkbookData(); @@ -119,38 +101,38 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { CTWorkbook wb = ctWorkbook.getWorkbook(); CTWorkbookPr prefix = wb.getWorkbookPr(); if (prefix != null && prefix.getDate1904()) { - readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.TRUE); + xlsxReadWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.TRUE); } else { - readWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); + xlsxReadWorkbookHolder.getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); } } private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream, - ReadWorkbookHolder readWorkbookHolder) throws Exception { - ContentHandler handler = new SharedStringsTableHandler(readWorkbookHolder.getReadCache()); + XlsxReadWorkbookHolder xlsxReadWorkbookHolder) throws Exception { + ContentHandler handler = new SharedStringsTableHandler(xlsxReadWorkbookHolder.getReadCache()); parseXmlSource(sharedStringsTableInputStream, handler); - readWorkbookHolder.getReadCache().putFinished(); + xlsxReadWorkbookHolder.getReadCache().putFinished(); } - private OPCPackage readOpcPackage(ReadWorkbookHolder readWorkbookHolder, InputStream decryptedStream) + private OPCPackage readOpcPackage(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, InputStream decryptedStream) throws Exception { - if (decryptedStream == null && readWorkbookHolder.getFile() != null) { - return OPCPackage.open(readWorkbookHolder.getFile()); + if (decryptedStream == null && xlsxReadWorkbookHolder.getFile() != null) { + return OPCPackage.open(xlsxReadWorkbookHolder.getFile()); } - if (readWorkbookHolder.getMandatoryUseInputStream()) { + if (xlsxReadWorkbookHolder.getMandatoryUseInputStream()) { if (decryptedStream != null) { return OPCPackage.open(decryptedStream); } else { - return OPCPackage.open(readWorkbookHolder.getInputStream()); + return OPCPackage.open(xlsxReadWorkbookHolder.getInputStream()); } } File readTempFile = FileUtils.createCacheTmpFile(); - readWorkbookHolder.setTempFile(readTempFile); + xlsxReadWorkbookHolder.setTempFile(readTempFile); File tempFile = new File(readTempFile.getPath(), UUID.randomUUID().toString() + ".xlsx"); if (decryptedStream != null) { FileUtils.writeToFile(tempFile, decryptedStream); } else { - FileUtils.writeToFile(tempFile, readWorkbookHolder.getInputStream()); + FileUtils.writeToFile(tempFile, xlsxReadWorkbookHolder.getInputStream()); } return OPCPackage.open(tempFile, PackageAccess.READ); } @@ -164,7 +146,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { InputSource inputSource = new InputSource(inputStream); try { SAXParserFactory saxFactory; - String xlsxSAXParserFactoryName = analysisContext.readWorkbookHolder().getXlsxSAXParserFactoryName(); + String xlsxSAXParserFactoryName = xlsxReadContext.xlsxReadWorkbookHolder().getSaxParserFactoryName(); if (StringUtils.isEmpty(xlsxSAXParserFactoryName)) { saxFactory = SAXParserFactory.newInstance(); } else { @@ -194,16 +176,14 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { } @Override - public void execute(List readSheetList, Boolean readAll) { + public void execute() { for (ReadSheet readSheet : sheetList) { - readSheet = SheetUtils.match(readSheet, readSheetList, readAll, - analysisContext.readWorkbookHolder().getGlobalConfiguration()); + readSheet = SheetUtils.match(readSheet, xlsxReadContext); if (readSheet != null) { - analysisContext.currentSheet(readSheet); - Integer sheetNo = readSheet.getSheetNo(); - parseXmlSource(sheetMap.get(sheetNo), new XlsxRowHandler(analysisContext, stylesTable, commentsTableMap.get(sheetNo))); + xlsxReadContext.currentSheet(readSheet); + parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(xlsxReadContext)); // The last sheet is read - analysisContext.readSheetHolder().notifyAfterAllAnalysed(analysisContext); + xlsxReadContext.analysisEventProcessor().endSheet(xlsxReadContext); } } } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java index c838aec..dbc0a7e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java @@ -1,12 +1,10 @@ package com.alibaba.excel.analysis.v07.handlers; -import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION; import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION_REF; import org.xml.sax.Attributes; -import com.alibaba.excel.analysis.v07.XlsxCellHandler; -import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.context.xlsx.XlsxReadContext; /** * Cell Handler @@ -15,33 +13,17 @@ import com.alibaba.excel.context.AnalysisContext; */ public class CountRowCellHandler implements XlsxCellHandler { - private final AnalysisContext analysisContext; - - public CountRowCellHandler(AnalysisContext analysisContext) { - this.analysisContext = analysisContext; - } - - @Override - public boolean support(String name) { - return DIMENSION.equals(name); - } @Override - public void startHandle(String name, Attributes attributes) { + public void startHandle(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { String d = attributes.getValue(DIMENSION_REF); String totalStr = d.substring(d.indexOf(":") + 1, d.length()); String c = totalStr.toUpperCase().replaceAll("[A-Z]", ""); - analysisContext.readSheetHolder().setApproximateTotalRowNumber(Integer.parseInt(c)); + xlsxReadContext.readSheetHolder().setApproximateTotalRowNumber(Integer.parseInt(c)); } @Override - public void endHandle(String name) { - - } - - @Override - public void handleComments(String comment) { - + public void endHandle(XlsxReadContext xlsxReadContext, String name) { } } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java index 3a489e1..baa3990 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java @@ -13,12 +13,10 @@ import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map; -import org.apache.poi.xssf.model.StylesTable; import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.apache.poi.xssf.usermodel.XSSFRichTextString; import org.xml.sax.Attributes; -import com.alibaba.excel.analysis.v07.XlsxCellHandler; import com.alibaba.excel.analysis.v07.XlsxRowResultHolder; import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.constant.ExcelXmlConstants; @@ -42,16 +40,6 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder private StringBuilder dataStringBuilder; private StringBuilder formulaStringBuilder; - /** - * Current style information - */ - private StylesTable stylesTable; - - public DefaultCellHandler(AnalysisContext analysisContext, StylesTable stylesTable) { - this.analysisContext = analysisContext; - this.stylesTable = stylesTable; - } - @Override public void clearResult() { curRowContent = new LinkedHashMap(); @@ -157,11 +145,6 @@ public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder } } - @Override - public void handleComments(String comment) { - // analysisContext.readRowHolder().addComments(curCol, comment); - } - @Override public void appendCurrentCellValue(char[] ch, int start, int length) { String currentTag = currentTagDeque.peek(); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java index 32b75ed..51a7123 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java @@ -1,14 +1,10 @@ package com.alibaba.excel.analysis.v07.handlers; -import static com.alibaba.excel.constant.ExcelXmlConstants.ROW_TAG; - import org.xml.sax.Attributes; -import com.alibaba.excel.analysis.v07.XlsxCellHandler; -import com.alibaba.excel.analysis.v07.XlsxRowResultHolder; import com.alibaba.excel.constant.ExcelXmlConstants; -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.read.listener.event.EachRowAnalysisFinishEvent; +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.read.metadata.holder.ReadRowHolder; import com.alibaba.excel.util.PositionUtils; @@ -18,36 +14,17 @@ import com.alibaba.excel.util.PositionUtils; * @author jipengfei */ public class ProcessResultCellHandler implements XlsxCellHandler { - private AnalysisContext analysisContext; - private XlsxRowResultHolder rowResultHandler; - - public ProcessResultCellHandler(AnalysisContext analysisContext, XlsxRowResultHolder rowResultHandler) { - this.analysisContext = analysisContext; - this.rowResultHandler = rowResultHandler; - } - - @Override - public boolean support(String name) { - return ROW_TAG.equals(name); - } @Override - public void startHandle(String name, Attributes attributes) { - analysisContext.readRowHolder( - new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION)), - analysisContext.readSheetHolder().getGlobalConfiguration())); + public void startHandle(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + xlsxReadContext.readRowHolder( + new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION)), RowTypeEnum.DATA, + xlsxReadContext.readSheetHolder().getGlobalConfiguration())); } @Override - public void endHandle(String name) { - analysisContext.readSheetHolder() - .notifyEndOneRow(new EachRowAnalysisFinishEvent(rowResultHandler.getCurRowContent()), analysisContext); - rowResultHandler.clearResult(); - } - - @Override - public void handleComments(String comment) { - + public void endHandle(XlsxReadContext xlsxReadContext, String name) { + xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxCellHandler.java new file mode 100644 index 0000000..3ec2fd8 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxCellHandler.java @@ -0,0 +1,29 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.context.xlsx.XlsxReadContext; + +/** + * Cell handler + * + * @author Dan Zheng + */ +public interface XlsxCellHandler { + /** + * Start handle + * + * @param xlsxReadContext xlsxReadContext + * @param name Tag name + * @param attributes Tag attributes + */ + void startHandle(XlsxReadContext xlsxReadContext, String name, Attributes attributes); + + /** + * End handle + * + * @param xlsxReadContext xlsxReadContext + * @param name Tag name + */ + void endHandle(XlsxReadContext xlsxReadContext, String name); +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/SharedStringsTableHandler.java similarity index 97% rename from src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java rename to src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/SharedStringsTableHandler.java index 5e001ed..ea6ffc5 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/SharedStringsTableHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/SharedStringsTableHandler.java @@ -1,4 +1,4 @@ -package com.alibaba.excel.analysis.v07; +package com.alibaba.excel.analysis.v07.handlers.sax; import org.xml.sax.Attributes; import org.xml.sax.helpers.DefaultHandler; diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java new file mode 100644 index 0000000..90e760a --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java @@ -0,0 +1,58 @@ +package com.alibaba.excel.analysis.v07.handlers.sax; + +import java.util.HashMap; +import java.util.Map; + +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +import com.alibaba.excel.analysis.v07.handlers.CountRowCellHandler; +import com.alibaba.excel.analysis.v07.handlers.ProcessResultCellHandler; +import com.alibaba.excel.analysis.v07.handlers.XlsxCellHandler; +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.context.xlsx.XlsxReadContext; + +/** + * @author jipengfei + */ +public class XlsxRowHandler extends DefaultHandler { + private XlsxReadContext xlsxReadContext; + private static final Map XLSX_CELL_HANDLER_MAP = new HashMap(16); + + static { + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.DIMENSION, new CountRowCellHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.ROW_TAG, new ProcessResultCellHandler()); + } + + public XlsxRowHandler(XlsxReadContext xlsxReadContext) { + this.xlsxReadContext = xlsxReadContext; + } + + @Override + public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { + XlsxCellHandler handler = XLSX_CELL_HANDLER_MAP.get(name); + if (handler == null) { + return; + } + handler.startHandle(xlsxReadContext, name, attributes); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (rowResultHolder != null) { + rowResultHolder.appendCurrentCellValue(ch, start, length); + } + } + + @Override + public void endElement(String uri, String localName, String name) throws SAXException { + XlsxCellHandler handler = XLSX_CELL_HANDLER_MAP.get(name); + if (handler == null) { + return; + } + handler.endHandle(xlsxReadContext, name); + } + + +} diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java index 8172b65..2b5a766 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java @@ -19,7 +19,7 @@ import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; import com.alibaba.excel.read.processor.AnalysisEventProcessor; -import com.alibaba.excel.read.processor.DefalutAnalysisEventProcessor; +import com.alibaba.excel.read.processor.DefaultAnalysisEventProcessor; import com.alibaba.excel.support.ExcelTypeEnum; /** @@ -64,7 +64,7 @@ public class AnalysisContextImpl implements AnalysisContext { break; } currentReadHolder = readWorkbookHolder; - analysisEventProcessor = new DefalutAnalysisEventProcessor(); + analysisEventProcessor = new DefaultAnalysisEventProcessor(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Initialization 'AnalysisContextImpl' complete"); } diff --git a/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java b/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java index 924cafe..58d8123 100644 --- a/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java +++ b/src/main/java/com/alibaba/excel/context/xlsx/XlsxReadContext.java @@ -1,8 +1,6 @@ package com.alibaba.excel.context.xlsx; import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; -import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java index b7439c3..2e1174d 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java @@ -10,6 +10,9 @@ import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; * @author Jiaju Zhuang */ public class XlsxReadSheetHolder extends ReadSheetHolder { + + + public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { super(readSheet, readWorkbookHolder); } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java index 34ec6ad..9542366 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java @@ -3,6 +3,7 @@ package com.alibaba.excel.read.metadata.holder.xlsx; import javax.xml.parsers.SAXParserFactory; import org.apache.poi.openxml4j.opc.OPCPackage; +import org.apache.poi.xssf.model.StylesTable; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; @@ -28,6 +29,10 @@ public class XlsxReadWorkbookHolder extends ReadWorkbookHolder { * @see SAXParserFactory#newInstance(String, ClassLoader) */ private String saxParserFactoryName; + /** + * Current style information + */ + private StylesTable stylesTable; public XlsxReadWorkbookHolder(ReadWorkbook readWorkbook) { super(readWorkbook); @@ -49,4 +54,12 @@ public class XlsxReadWorkbookHolder extends ReadWorkbookHolder { public void setSaxParserFactoryName(String saxParserFactoryName) { this.saxParserFactoryName = saxParserFactoryName; } + + public StylesTable getStylesTable() { + return stylesTable; + } + + public void setStylesTable(StylesTable stylesTable) { + this.stylesTable = stylesTable; + } } diff --git a/src/main/java/com/alibaba/excel/read/processor/DefalutAnalysisEventProcessor.java b/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java similarity index 96% rename from src/main/java/com/alibaba/excel/read/processor/DefalutAnalysisEventProcessor.java rename to src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java index e673913..6b5b0af 100644 --- a/src/main/java/com/alibaba/excel/read/processor/DefalutAnalysisEventProcessor.java +++ b/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java @@ -25,12 +25,11 @@ import com.alibaba.excel.util.StringUtils; * * @author jipengfei */ -public class DefalutAnalysisEventProcessor implements AnalysisEventProcessor { - private static final Logger LOGGER = LoggerFactory.getLogger(DefalutAnalysisEventProcessor.class); +public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor { + private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAnalysisEventProcessor.class); @Override public void endRow(AnalysisContext analysisContext) { - switch (analysisContext.readRowHolder().getRowType()) { case EMPTY: if (LOGGER.isDebugEnabled()) { @@ -61,11 +60,14 @@ public class DefalutAnalysisEventProcessor implements AnalysisEventProcessor { } } - private void dealExtra(AnalysisContext analysisContext) {} + private void dealExtra(AnalysisContext analysisContext) { + + + } private void dealData(AnalysisContext analysisContext) { ReadRowHolder readRowHolder = analysisContext.readRowHolder(); - Map cellDataMap = (Map)readRowHolder.getCellMap(); + Map cellDataMap = (Map) readRowHolder.getCellMap(); readRowHolder.setCurrentRowAnalysisResult(cellDataMap); int rowIndex = readRowHolder.getRowIndex(); int currentHeadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber(); diff --git a/src/main/java/com/alibaba/excel/util/SheetUtils.java b/src/main/java/com/alibaba/excel/util/SheetUtils.java index 492789c..fb2c59e 100644 --- a/src/main/java/com/alibaba/excel/util/SheetUtils.java +++ b/src/main/java/com/alibaba/excel/util/SheetUtils.java @@ -3,7 +3,7 @@ package com.alibaba.excel.util; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.excel.context.xls.XlsReadContext; +import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.metadata.ReadSheet; /** @@ -14,21 +14,21 @@ import com.alibaba.excel.read.metadata.ReadSheet; public class SheetUtils { private static final Logger LOGGER = LoggerFactory.getLogger(SheetUtils.class); - private SheetUtils() {} + private SheetUtils() { + } /** * Match the parameters to the actual sheet * - * @param readSheet - * actual sheet - * @param xlsReadContext + * @param readSheet actual sheet + * @param analysisContext * @return */ - public static ReadSheet match(ReadSheet readSheet, XlsReadContext xlsReadContext) { - if (xlsReadContext.readAll()) { + public static ReadSheet match(ReadSheet readSheet, AnalysisContext analysisContext) { + if (analysisContext.readAll()) { return readSheet; } - for (ReadSheet parameterReadSheet : xlsReadContext.readSheetList()) { + for (ReadSheet parameterReadSheet : analysisContext.readSheetList()) { if (parameterReadSheet == null) { continue; } @@ -45,7 +45,7 @@ public class SheetUtils { if (!StringUtils.isEmpty(parameterSheetName)) { boolean autoTrim = (parameterReadSheet.getAutoTrim() != null && parameterReadSheet.getAutoTrim()) || (parameterReadSheet.getAutoTrim() == null - && xlsReadContext.readWorkbookHolder().getGlobalConfiguration().getAutoTrim()); + && analysisContext.readWorkbookHolder().getGlobalConfiguration().getAutoTrim()); if (autoTrim) { parameterSheetName = parameterSheetName.trim(); } From e63190976af92983c9e3e1de6c065628bc26b3b7 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Sun, 15 Mar 2020 04:06:04 +0800 Subject: [PATCH 19/38] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E8=AF=BB=E5=8F=96=E6=89=B9=E6=B3=A8=E3=80=81?= =?UTF-8?q?=E8=B6=85=E9=93=BE=E6=8E=A5=E3=80=81=E5=90=88=E5=B9=B6=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=A0=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/analysis/ExcelAnalyserImpl.java | 10 +- .../analysis/v03/XlsListSheetListener.java | 1 + .../excel/analysis/v03/XlsRecordHandler.java | 8 + .../excel/analysis/v03/XlsSaxAnalyser.java | 15 +- .../handlers/AbstractXlsRecordHandler.java | 19 ++ .../v03/handlers/BlankRecordHandler.java | 2 +- .../v03/handlers/BofRecordHandler.java | 9 +- .../v03/handlers/BoolErrRecordHandler.java | 2 +- .../v03/handlers/BoundSheetRecordHandler.java | 2 +- .../v03/handlers/DummyRecordHandler.java | 4 +- .../v03/handlers/EofRecordHandler.java | 2 +- .../v03/handlers/FormulaRecordHandler.java | 4 +- .../v03/handlers/HyperlinkRecordHandler.java | 30 ++++ .../v03/handlers/IndexRecordHandler.java | 2 +- .../v03/handlers/LabelRecordHandler.java | 2 +- .../v03/handlers/LabelSstRecordHandler.java | 2 +- .../v03/handlers/MergeCellsRecordHandler.java | 35 ++++ .../v03/handlers/NoteRecordHandler.java | 20 ++- .../v03/handlers/NumberRecordHandler.java | 2 +- .../v03/handlers/ObjRecordHandler.java | 2 +- .../v03/handlers/RkRecordHandler.java | 2 +- .../v03/handlers/SstRecordHandler.java | 2 +- .../v03/handlers/StringRecordHandler.java | 2 +- .../v03/handlers/TextObjectRecordHandler.java | 8 +- .../analysis/v07/XlsxHandlerFactory.java | 28 --- .../analysis/v07/XlsxRowResultHolder.java | 33 ---- .../excel/analysis/v07/XlsxSaxAnalyser.java | 42 ++++- .../handlers/AbstractCellValueTagHandler.java | 64 +++++++ .../v07/handlers/AbstractXlsxTagHandler.java | 32 ++++ .../v07/handlers/CellFormulaTagHandler.java | 32 ++++ .../CellInlineStringValueTagHandler.java | 23 +++ .../analysis/v07/handlers/CellTagHandler.java | 53 ++++++ .../v07/handlers/CellValueTagHandler.java | 34 ++++ ...wCellHandler.java => CountTagHandler.java} | 9 +- .../v07/handlers/DefaultCellHandler.java | 169 ------------------ .../v07/handlers/HyperlinkTagHandler.java | 35 ++++ .../v07/handlers/MergeCellTagHandler.java | 34 ++++ .../handlers/ProcessResultCellHandler.java | 30 ---- .../analysis/v07/handlers/RowTagHandler.java | 35 ++++ .../v07/handlers/XlsxCellHandler.java | 29 --- .../analysis/v07/handlers/XlsxTagHandler.java | 53 ++++++ .../v07/handlers/sax/XlsxRowHandler.java | 46 +++-- .../excel/constant/ExcelXmlConstants.java | 15 ++ .../excel/context/AnalysisContext.java | 14 -- .../excel/context/AnalysisContextImpl.java | 10 -- .../excel/enums/CellExtraTypeEnum.java | 21 +++ .../alibaba/excel/enums/ExtraReadEnum.java | 13 -- .../com/alibaba/excel/enums/RowTypeEnum.java | 4 - .../AbstractIgnoreExceptionReadListener.java | 12 ++ .../excel/event/AnalysisEventListener.java | 12 ++ .../com/alibaba/excel/metadata/CellExtra.java | 113 +++++++++++- .../read/builder/ExcelReaderBuilder.java | 37 +++- .../excel/read/listener/ReadListener.java | 11 ++ .../excel/read/metadata/ReadWorkbook.java | 10 +- .../read/metadata/holder/ReadRowHolder.java | 4 +- .../read/metadata/holder/ReadSheetHolder.java | 56 +++++- .../metadata/holder/ReadWorkbookHolder.java | 32 ++-- .../holder/xls/XlsReadSheetHolder.java | 40 ----- .../holder/xls/XlsReadWorkbookHolder.java | 18 +- .../holder/xlsx/XlsxReadSheetHolder.java | 54 +++++- .../holder/xlsx/XlsxReadWorkbookHolder.java | 2 + .../processor/AnalysisEventProcessor.java | 7 + .../DefaultAnalysisEventProcessor.java | 70 ++++---- .../com/alibaba/excel/util/SheetUtils.java | 14 +- .../easyexcel/test/core/extra/ExtraData.java | 14 ++ .../test/core/extra/ExtraDataListener.java | 55 ++++++ .../test/core/extra/ExtraDataTest.java | 44 +++++ .../easyexcel/test/temp/Lock2Test.java | 6 + .../easyexcel/test/temp/read/CommentTest.java | 2 +- src/test/resources/demo/demo.xlsx | Bin 12291 -> 10173 bytes src/test/resources/extra/extra.xls | Bin 0 -> 19968 bytes src/test/resources/extra/extra.xlsx | Bin 0 -> 12045 bytes update.md | 4 +- 73 files changed, 1147 insertions(+), 515 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/AbstractXlsRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java delete mode 100644 src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java delete mode 100644 src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractXlsxTagHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/CellFormulaTagHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java rename src/main/java/com/alibaba/excel/analysis/v07/handlers/{CountRowCellHandler.java => CountTagHandler.java} (68%) delete mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/MergeCellTagHandler.java delete mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java delete mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxCellHandler.java create mode 100644 src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java create mode 100644 src/main/java/com/alibaba/excel/enums/CellExtraTypeEnum.java delete mode 100644 src/main/java/com/alibaba/excel/enums/ExtraReadEnum.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraData.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataListener.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataTest.java create mode 100644 src/test/resources/extra/extra.xls create mode 100644 src/test/resources/extra/extra.xlsx diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index f8d81fa..4546c4b 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -110,7 +110,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { if (!readAll && CollectionUtils.isEmpty(readSheetList)) { throw new IllegalArgumentException("Specify at least one read sheet."); } - analysisContext.readWorkbookHolder().setParametersheetDataList(readSheetList); + analysisContext.readWorkbookHolder().setParameterSheetDataList(readSheetList); analysisContext.readWorkbookHolder().setReadAll(readAll); try { excelReadExecutor.execute(); @@ -150,16 +150,16 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { } try { if ((readWorkbookHolder instanceof XlsxReadWorkbookHolder) - && ((XlsxReadWorkbookHolder) readWorkbookHolder).getOpcPackage() != null) { - ((XlsxReadWorkbookHolder) readWorkbookHolder).getOpcPackage().revert(); + && ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage() != null) { + ((XlsxReadWorkbookHolder)readWorkbookHolder).getOpcPackage().revert(); } } catch (Throwable t) { throwable = t; } try { if ((readWorkbookHolder instanceof XlsReadWorkbookHolder) - && ((XlsReadWorkbookHolder) readWorkbookHolder).getPoifsFileSystem() != null) { - ((XlsReadWorkbookHolder) readWorkbookHolder).getPoifsFileSystem().close(); + && ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem() != null) { + ((XlsReadWorkbookHolder)readWorkbookHolder).getPoifsFileSystem().close(); } } catch (Throwable t) { throwable = t; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java index 31d2db8..cfdc6be 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsListSheetListener.java @@ -35,6 +35,7 @@ public class XlsListSheetListener implements HSSFListener { public XlsListSheetListener(XlsReadContext xlsReadContext) { this.xlsReadContext = xlsReadContext; + xlsReadContext.xlsReadWorkbookHolder().setNeedReadSheet(Boolean.FALSE); } @Override diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java index dea327f..3b4fa7c 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java @@ -10,6 +10,14 @@ import com.alibaba.excel.context.xls.XlsReadContext; * @author Dan Zheng */ public interface XlsRecordHandler { + /** + * Whether to support + * + * @param xlsReadContext + * @param record + */ + boolean support(XlsReadContext xlsReadContext, Record record); + /** * Processing record * diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index c90f655..a94a7d3 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -18,9 +18,11 @@ import org.apache.poi.hssf.record.BoolErrRecord; import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.EOFRecord; import org.apache.poi.hssf.record.FormulaRecord; +import org.apache.poi.hssf.record.HyperlinkRecord; import org.apache.poi.hssf.record.IndexRecord; import org.apache.poi.hssf.record.LabelRecord; import org.apache.poi.hssf.record.LabelSSTRecord; +import org.apache.poi.hssf.record.MergeCellsRecord; import org.apache.poi.hssf.record.NoteRecord; import org.apache.poi.hssf.record.NumberRecord; import org.apache.poi.hssf.record.ObjRecord; @@ -40,9 +42,11 @@ import com.alibaba.excel.analysis.v03.handlers.BoundSheetRecordHandler; import com.alibaba.excel.analysis.v03.handlers.DummyRecordHandler; import com.alibaba.excel.analysis.v03.handlers.EofRecordHandler; import com.alibaba.excel.analysis.v03.handlers.FormulaRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.HyperlinkRecordHandler; import com.alibaba.excel.analysis.v03.handlers.IndexRecordHandler; import com.alibaba.excel.analysis.v03.handlers.LabelRecordHandler; import com.alibaba.excel.analysis.v03.handlers.LabelSstRecordHandler; +import com.alibaba.excel.analysis.v03.handlers.MergeCellsRecordHandler; import com.alibaba.excel.analysis.v03.handlers.NoteRecordHandler; import com.alibaba.excel.analysis.v03.handlers.NumberRecordHandler; import com.alibaba.excel.analysis.v03.handlers.ObjRecordHandler; @@ -84,9 +88,11 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { XLS_RECORD_HANDLER_MAP.put(DUMMY_RECORD_SID, new DummyRecordHandler()); XLS_RECORD_HANDLER_MAP.put(EOFRecord.sid, new EofRecordHandler()); XLS_RECORD_HANDLER_MAP.put(FormulaRecord.sid, new FormulaRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(HyperlinkRecord.sid, new HyperlinkRecordHandler()); XLS_RECORD_HANDLER_MAP.put(IndexRecord.sid, new IndexRecordHandler()); XLS_RECORD_HANDLER_MAP.put(LabelRecord.sid, new LabelRecordHandler()); XLS_RECORD_HANDLER_MAP.put(LabelSSTRecord.sid, new LabelSstRecordHandler()); + XLS_RECORD_HANDLER_MAP.put(MergeCellsRecord.sid, new MergeCellsRecordHandler()); XLS_RECORD_HANDLER_MAP.put(NoteRecord.sid, new NoteRecordHandler()); XLS_RECORD_HANDLER_MAP.put(NumberRecord.sid, new NumberRecordHandler()); XLS_RECORD_HANDLER_MAP.put(ObjRecord.sid, new ObjRecordHandler()); @@ -117,7 +123,7 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { EventWorkbookBuilder.SheetRecordCollectingListener workbookBuildingListener = new EventWorkbookBuilder.SheetRecordCollectingListener( xlsReadWorkbookHolder.getFormatTrackingHSSFListener()); - xlsReadWorkbookHolder.setHsffWorkbook(workbookBuildingListener.getStubHSSFWorkbook()); + xlsReadWorkbookHolder.setHssfWorkbook(workbookBuildingListener.getStubHSSFWorkbook()); HSSFEventFactory factory = new HSSFEventFactory(); HSSFRequest request = new HSSFRequest(); request.addListenerForAllRecords(xlsReadWorkbookHolder.getFormatTrackingHSSFListener()); @@ -139,10 +145,15 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { if (handler == null) { return; } - if ((handler instanceof IgnorableXlsRecordHandler) && xlsReadContext.xlsReadSheetHolder().getIgnoreRecord()) { + boolean ignoreRecord = (handler instanceof IgnorableXlsRecordHandler) + && xlsReadContext.xlsReadSheetHolder() != null && xlsReadContext.xlsReadSheetHolder().getIgnoreRecord(); + if (ignoreRecord) { // No need to read the current sheet return; } + if (!handler.support(xlsReadContext, record)) { + return; + } handler.processRecord(xlsReadContext, record); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/AbstractXlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/AbstractXlsRecordHandler.java new file mode 100644 index 0000000..93b3d1a --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/AbstractXlsRecordHandler.java @@ -0,0 +1,19 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.XlsRecordHandler; +import com.alibaba.excel.context.xls.XlsReadContext; + +/** + * Abstract xls record handler + * + * @author Jiaju Zhuang + **/ +public abstract class AbstractXlsRecordHandler implements XlsRecordHandler { + + @Override + public boolean support(XlsReadContext xlsReadContext, Record record) { + return true; + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java index 372a44c..e6290eb 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BlankRecordHandler.java @@ -12,7 +12,7 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class BlankRecordHandler implements IgnorableXlsRecordHandler { +public class BlankRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java index 59870ba..973d83e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -7,11 +7,9 @@ import org.apache.poi.hssf.record.BOFRecord; import org.apache.poi.hssf.record.BoundSheetRecord; import org.apache.poi.hssf.record.Record; -import com.alibaba.excel.analysis.v03.XlsRecordHandler; import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.read.metadata.ReadSheet; -import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; import com.alibaba.excel.util.SheetUtils; @@ -20,7 +18,7 @@ import com.alibaba.excel.util.SheetUtils; * * @author Dan Zheng */ -public class BofRecordHandler implements XlsRecordHandler { +public class BofRecordHandler extends AbstractXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { @@ -29,7 +27,6 @@ public class BofRecordHandler implements XlsRecordHandler { return; } XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder(); - XlsReadSheetHolder XlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); // Init read sheet Data initReadSheetDataList(xlsReadWorkbookHolder); Integer readSheetIndex = xlsReadWorkbookHolder.getReadSheetIndex(); @@ -43,9 +40,9 @@ public class BofRecordHandler implements XlsRecordHandler { readSheet = SheetUtils.match(readSheet, xlsReadContext); if (readSheet != null) { xlsReadContext.currentSheet(readSheet); - XlsReadSheetHolder.setIgnoreRecord(Boolean.FALSE); + xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.FALSE); } else { - XlsReadSheetHolder.setIgnoreRecord(Boolean.TRUE); + xlsReadContext.xlsReadSheetHolder().setIgnoreRecord(Boolean.TRUE); } // Go read the next one xlsReadWorkbookHolder.setReadSheetIndex(xlsReadWorkbookHolder.getReadSheetIndex() + 1); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java index 60e7233..8d43521 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoolErrRecordHandler.java @@ -13,7 +13,7 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class BoolErrRecordHandler implements IgnorableXlsRecordHandler { +public class BoolErrRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java index 96e7b33..685dcc6 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BoundSheetRecordHandler.java @@ -11,7 +11,7 @@ import com.alibaba.excel.context.xls.XlsReadContext; * * @author Dan Zheng */ -public class BoundSheetRecordHandler implements IgnorableXlsRecordHandler { +public class BoundSheetRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java index 15a68dc..ab41d29 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java @@ -18,7 +18,7 @@ import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; * * @author Dan Zheng */ -public class DummyRecordHandler implements IgnorableXlsRecordHandler { +public class DummyRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { XlsReadSheetHolder xlsReadSheetHolder = xlsReadContext.xlsReadSheetHolder(); @@ -27,7 +27,7 @@ public class DummyRecordHandler implements IgnorableXlsRecordHandler { LastCellOfRowDummyRecord lcrdr = (LastCellOfRowDummyRecord)record; xlsReadSheetHolder.setRowIndex(lcrdr.getRow()); xlsReadContext.readRowHolder(new ReadRowHolder(lcrdr.getRow(), xlsReadSheetHolder.getTempRowType(), - xlsReadContext.readSheetHolder().getGlobalConfiguration())); + xlsReadContext.readSheetHolder().getGlobalConfiguration(), xlsReadSheetHolder.getCellMap())); xlsReadContext.analysisEventProcessor().endRow(xlsReadContext); xlsReadSheetHolder.setCellMap(new LinkedHashMap()); } else if (record instanceof MissingCellDummyRecord) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java index 4b1517b..0ca7313 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/EofRecordHandler.java @@ -10,7 +10,7 @@ import com.alibaba.excel.context.xls.XlsReadContext; * * @author Dan Zheng */ -public class EofRecordHandler implements IgnorableXlsRecordHandler { +public class EofRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java index f04cdb7..004d9c6 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -21,7 +21,7 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class FormulaRecordHandler implements IgnorableXlsRecordHandler { +public class FormulaRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { private static final Logger LOGGER = LoggerFactory.getLogger(FormulaRecordHandler.class); private static final String ERROR = "#VALUE!"; @@ -35,7 +35,7 @@ public class FormulaRecordHandler implements IgnorableXlsRecordHandler { CellType cellType = CellType.forInt(frec.getCachedResultType()); String formulaValue = null; try { - formulaValue = HSSFFormulaParser.toFormulaString(xlsReadContext.xlsReadWorkbookHolder().getHsffWorkbook(), + formulaValue = HSSFFormulaParser.toFormulaString(xlsReadContext.xlsReadWorkbookHolder().getHssfWorkbook(), frec.getParsedExpression()); } catch (Exception e) { LOGGER.debug("Get formula value error.", e); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java new file mode 100644 index 0000000..915abf6 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java @@ -0,0 +1,30 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.HyperlinkRecord; +import org.apache.poi.hssf.record.Record; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.xls.XlsReadContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; +import com.alibaba.excel.metadata.CellExtra; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class HyperlinkRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { + @Override + public boolean support(XlsReadContext xlsReadContext, Record record) { + return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.HYPERLINK); + } + + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + HyperlinkRecord hr = (HyperlinkRecord)record; + CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.HYPERLINK, hr.getAddress(), hr.getFirstRow(), + hr.getFirstColumn(), hr.getLastRow(), hr.getLastColumn()); + xlsReadContext.xlsReadSheetHolder().setCellExtra(cellExtra); + xlsReadContext.analysisEventProcessor().extra(xlsReadContext); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java index de21da8..b95812e 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/IndexRecordHandler.java @@ -11,7 +11,7 @@ import com.alibaba.excel.context.xls.XlsReadContext; * * @author Jiaju Zhuang */ -public class IndexRecordHandler implements IgnorableXlsRecordHandler { +public class IndexRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { if (xlsReadContext.readSheetHolder() == null) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java index 1335ada..4f63ab0 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelRecordHandler.java @@ -13,7 +13,7 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class LabelRecordHandler implements IgnorableXlsRecordHandler { +public class LabelRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { LabelRecord lrec = (LabelRecord)record; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java index 7979241..7fb5cd0 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/LabelSstRecordHandler.java @@ -17,7 +17,7 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class LabelSstRecordHandler implements IgnorableXlsRecordHandler { +public class LabelSstRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java new file mode 100644 index 0000000..4689f2b --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java @@ -0,0 +1,35 @@ +package com.alibaba.excel.analysis.v03.handlers; + +import org.apache.poi.hssf.record.MergeCellsRecord; +import org.apache.poi.hssf.record.Record; +import org.apache.poi.ss.util.CellRangeAddress; + +import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.context.xls.XlsReadContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; +import com.alibaba.excel.metadata.CellExtra; + +/** + * Record handler + * + * @author Dan Zheng + */ +public class MergeCellsRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { + + @Override + public boolean support(XlsReadContext xlsReadContext, Record record) { + return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.MERGE); + } + + @Override + public void processRecord(XlsReadContext xlsReadContext, Record record) { + MergeCellsRecord mcr = (MergeCellsRecord)record; + for (int i = 0; i < mcr.getNumAreas(); i++) { + CellRangeAddress cellRangeAddress = mcr.getAreaAt(i); + CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.MERGE, null, cellRangeAddress.getFirstRow(), + cellRangeAddress.getFirstColumn(), cellRangeAddress.getLastRow(), cellRangeAddress.getLastColumn()); + xlsReadContext.xlsReadSheetHolder().setCellExtra(cellExtra); + xlsReadContext.analysisEventProcessor().extra(xlsReadContext); + } + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java index 8c2993d..6b6d803 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NoteRecordHandler.java @@ -5,7 +5,7 @@ import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.xls.XlsReadContext; -import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.metadata.CellExtra; /** @@ -13,17 +13,19 @@ import com.alibaba.excel.metadata.CellExtra; * * @author Dan Zheng */ -public class NoteRecordHandler implements IgnorableXlsRecordHandler { +public class NoteRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { + + @Override + public boolean support(XlsReadContext xlsReadContext, Record record) { + return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT); + } @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { NoteRecord nr = (NoteRecord)record; - String note = xlsReadContext.xlsReadSheetHolder().getObjectCacheMap().get(nr.getShapeId()); - CellExtra cellExtra = new CellExtra(); - cellExtra.setRowIndex(nr.getRow()); - cellExtra.setRowIndex(nr.getColumn()); - cellExtra.setNote(note); - xlsReadContext.xlsReadSheetHolder().getCellMap().put(nr.getColumn(), cellExtra); - xlsReadContext.xlsReadSheetHolder().setTempRowType(RowTypeEnum.EXTRA); + String text = xlsReadContext.xlsReadSheetHolder().getObjectCacheMap().get(nr.getShapeId()); + CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.COMMENT, text, nr.getRow(), nr.getColumn()); + xlsReadContext.xlsReadSheetHolder().setCellExtra(cellExtra); + xlsReadContext.analysisEventProcessor().extra(xlsReadContext); } } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java index 5e2fbca..5060809 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/NumberRecordHandler.java @@ -16,7 +16,7 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class NumberRecordHandler implements IgnorableXlsRecordHandler { +public class NumberRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java index e8a0cc1..97bcd20 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/ObjRecordHandler.java @@ -13,7 +13,7 @@ import com.alibaba.excel.context.xls.XlsReadContext; * * @author Jiaju Zhuang */ -public class ObjRecordHandler implements IgnorableXlsRecordHandler { +public class ObjRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { ObjRecord or = (ObjRecord)record; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java index 22ba166..d8317b3 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/RkRecordHandler.java @@ -12,7 +12,7 @@ import com.alibaba.excel.metadata.CellData; * * @author Dan Zheng */ -public class RkRecordHandler implements IgnorableXlsRecordHandler { +public class RkRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java index c11ff4c..35727b6 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/SstRecordHandler.java @@ -12,7 +12,7 @@ import com.alibaba.excel.context.xls.XlsReadContext; * * @author Dan Zheng */ -public class SstRecordHandler implements IgnorableXlsRecordHandler { +public class SstRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { xlsReadContext.readWorkbookHolder().setReadCache(new XlsCache((SSTRecord)record)); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java index e4c40ec..3b95cfd 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/StringRecordHandler.java @@ -15,7 +15,7 @@ import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; * * @author Dan Zheng */ -public class StringRecordHandler implements IgnorableXlsRecordHandler { +public class StringRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { private static final Logger LOGGER = LoggerFactory.getLogger(StringRecordHandler.class); @Override diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java index 1ee3543..949498f 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/TextObjectRecordHandler.java @@ -7,6 +7,7 @@ import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.xls.XlsReadContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; /** @@ -14,9 +15,14 @@ import com.alibaba.excel.read.metadata.holder.xls.XlsReadSheetHolder; * * @author Jiaju Zhuang */ -public class TextObjectRecordHandler implements IgnorableXlsRecordHandler { +public class TextObjectRecordHandler extends AbstractXlsRecordHandler implements IgnorableXlsRecordHandler { private static final Logger LOGGER = LoggerFactory.getLogger(TextObjectRecordHandler.class); + @Override + public boolean support(XlsReadContext xlsReadContext, Record record) { + return xlsReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT); + } + @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { TextObjectRecord tor = (TextObjectRecord)record; diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java deleted file mode 100644 index 1785036..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxHandlerFactory.java +++ /dev/null @@ -1,28 +0,0 @@ -package com.alibaba.excel.analysis.v07; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.poi.xssf.model.StylesTable; - -import com.alibaba.excel.analysis.v07.handlers.CountRowCellHandler; -import com.alibaba.excel.analysis.v07.handlers.DefaultCellHandler; -import com.alibaba.excel.analysis.v07.handlers.ProcessResultCellHandler; -import com.alibaba.excel.analysis.v07.handlers.XlsxCellHandler; -import com.alibaba.excel.context.AnalysisContext; - -/** - * Build handler - * - * @author Dan Zheng - */ -public class XlsxHandlerFactory { - public static List buildCellHandlers(AnalysisContext analysisContext, StylesTable stylesTable) { - List result = new ArrayList(); - result.add(new CountRowCellHandler(analysisContext)); - DefaultCellHandler defaultCellHandler = new DefaultCellHandler(analysisContext, stylesTable); - result.add(defaultCellHandler); - result.add(new ProcessResultCellHandler(analysisContext, defaultCellHandler)); - return result; - } -} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java deleted file mode 100644 index d13da73..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxRowResultHolder.java +++ /dev/null @@ -1,33 +0,0 @@ -package com.alibaba.excel.analysis.v07; - -import java.util.Map; - -import com.alibaba.excel.metadata.CellData; - -/** - * Result holder - * - * @author jipengfei - */ -public interface XlsxRowResultHolder { - /** - * Clear Result - */ - void clearResult(); - - /** - * Append current 'cellValue' - * - * @param ch - * @param start - * @param length - */ - void appendCurrentCellValue(char[] ch, int start, int length); - - /** - * Get row content - * - * @return - */ - Map getCurRowContent(); -} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java index 205b648..a0a9af0 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/XlsxSaxAnalyser.java @@ -15,7 +15,10 @@ import javax.xml.parsers.SAXParserFactory; import org.apache.poi.openxml4j.opc.OPCPackage; import org.apache.poi.openxml4j.opc.PackageAccess; import org.apache.poi.openxml4j.opc.PackagePart; +import org.apache.poi.ss.util.CellAddress; import org.apache.poi.xssf.eventusermodel.XSSFReader; +import org.apache.poi.xssf.model.CommentsTable; +import org.apache.poi.xssf.usermodel.XSSFComment; import org.apache.poi.xssf.usermodel.XSSFRelation; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbook; import org.openxmlformats.schemas.spreadsheetml.x2006.main.CTWorkbookPr; @@ -29,7 +32,9 @@ import com.alibaba.excel.analysis.v07.handlers.sax.SharedStringsTableHandler; import com.alibaba.excel.analysis.v07.handlers.sax.XlsxRowHandler; import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.metadata.CellExtra; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadWorkbookHolder; import com.alibaba.excel.util.CollectionUtils; @@ -45,6 +50,10 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { private XlsxReadContext xlsxReadContext; private List sheetList; private Map sheetMap; + /** + * excel comments key: sheetNo value: CommentsTable + */ + private Map commentsTableMap; public XlsxSaxAnalyser(XlsxReadContext xlsxReadContext, InputStream decryptedStream) throws Exception { this.xlsxReadContext = xlsxReadContext; @@ -72,7 +81,8 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { xlsxReadWorkbookHolder.setStylesTable(xssfReader.getStylesTable()); sheetList = new ArrayList(); sheetMap = new HashMap(); - XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator) xssfReader.getSheetsData(); + commentsTableMap = new HashMap(); + XSSFReader.SheetIterator ite = (XSSFReader.SheetIterator)xssfReader.getSheetsData(); int index = 0; if (!ite.hasNext()) { throw new ExcelAnalysisException("Can not find any sheet!"); @@ -81,11 +91,18 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { InputStream inputStream = ite.next(); sheetList.add(new ReadSheet(index, ite.getSheetName())); sheetMap.put(index, inputStream); + if (xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) { + CommentsTable commentsTable = ite.getSheetComments(); + if (null != commentsTable) { + commentsTableMap.put(index, commentsTable); + } + } index++; } } - private void defaultReadCache(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, PackagePart sharedStringsTablePackagePart) { + private void defaultReadCache(XlsxReadWorkbookHolder xlsxReadWorkbookHolder, + PackagePart sharedStringsTablePackagePart) { ReadCache readCache = xlsxReadWorkbookHolder.getReadCacheSelector().readCache(sharedStringsTablePackagePart); xlsxReadWorkbookHolder.setReadCache(readCache); readCache.init(xlsxReadContext); @@ -108,7 +125,7 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { } private void analysisSharedStringsTable(InputStream sharedStringsTableInputStream, - XlsxReadWorkbookHolder xlsxReadWorkbookHolder) throws Exception { + XlsxReadWorkbookHolder xlsxReadWorkbookHolder) throws Exception { ContentHandler handler = new SharedStringsTableHandler(xlsxReadWorkbookHolder.getReadCache()); parseXmlSource(sharedStringsTableInputStream, handler); xlsxReadWorkbookHolder.getReadCache().putFinished(); @@ -182,9 +199,28 @@ public class XlsxSaxAnalyser implements ExcelReadExecutor { if (readSheet != null) { xlsxReadContext.currentSheet(readSheet); parseXmlSource(sheetMap.get(readSheet.getSheetNo()), new XlsxRowHandler(xlsxReadContext)); + // Read comments + readComments(readSheet); // The last sheet is read xlsxReadContext.analysisEventProcessor().endSheet(xlsxReadContext); } } } + + private void readComments(ReadSheet readSheet) { + if (!xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.COMMENT)) { + return; + } + CommentsTable commentsTable = commentsTableMap.get(readSheet.getSheetNo()); + if (commentsTable == null) { + return; + } + Map cellComments = commentsTable.getCellComments(); + for (XSSFComment xssfComment : cellComments.values()) { + CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.COMMENT, xssfComment.getString().toString(), + xssfComment.getRow(), xssfComment.getColumn()); + xlsxReadContext.readSheetHolder().setCellExtra(cellExtra); + xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext); + } + } } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java new file mode 100644 index 0000000..0c60d66 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java @@ -0,0 +1,64 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import java.math.BigDecimal; + +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; +import com.alibaba.excel.util.BooleanUtils; + +/** + * Cell Value Handler + * + * @author jipengfei + */ +public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler { + + @Override + public void endElement(XlsxReadContext xlsxReadContext, String name) { + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + CellData tempCellData = xlsxReadSheetHolder.getTempCellData(); + StringBuilder tempData = xlsxReadSheetHolder.getTempData(); + CellDataTypeEnum oldType = tempCellData.getType(); + switch (oldType) { + case DIRECT_STRING: + case STRING: + case ERROR: + tempCellData.setStringValue(tempData.toString()); + break; + case BOOLEAN: + tempCellData.setBooleanValue(BooleanUtils.valueOf(tempData.toString())); + break; + case NUMBER: + case EMPTY: + tempCellData.setType(CellDataTypeEnum.NUMBER); + tempCellData.setNumberValue(new BigDecimal(tempData.toString())); + break; + default: + throw new IllegalStateException("Cannot set values now"); + } + + // set string value + setStringValue(xlsxReadContext); + + if (tempCellData.getStringValue() != null + && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) { + tempCellData.setStringValue(tempCellData.getStringValue()); + } + + tempCellData.checkEmpty(); + xlsxReadSheetHolder.getCellMap().put(xlsxReadSheetHolder.getColumnIndex(), tempCellData); + } + + @Override + public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) { + xlsxReadContext.xlsxReadSheetHolder().getTempData().append(ch, start, length); + } + + /** + * Set string value. + */ + protected abstract void setStringValue(XlsxReadContext xlsxReadContext); + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractXlsxTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractXlsxTagHandler.java new file mode 100644 index 0000000..169fe00 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractXlsxTagHandler.java @@ -0,0 +1,32 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.context.xlsx.XlsxReadContext; + +/** + * Abstract tag handler + * + * @author Jiaju Zhuang + */ +public abstract class AbstractXlsxTagHandler implements XlsxTagHandler { + @Override + public boolean support(XlsxReadContext xlsxReadContext) { + return true; + } + + @Override + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + + } + + @Override + public void endElement(XlsxReadContext xlsxReadContext, String name) { + + } + + @Override + public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) { + + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellFormulaTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellFormulaTagHandler.java new file mode 100644 index 0000000..e153a3b --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellFormulaTagHandler.java @@ -0,0 +1,32 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; + +/** + * Cell Handler + * + * @author jipengfei + */ +public class CellFormulaTagHandler extends AbstractXlsxTagHandler { + + @Override + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + xlsxReadSheetHolder.getTempCellData().setFormula(Boolean.TRUE); + xlsxReadSheetHolder.setTempFormula(new StringBuilder()); + } + + @Override + public void endElement(XlsxReadContext xlsxReadContext, String name) { + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + xlsxReadSheetHolder.getTempCellData().setFormulaValue(xlsxReadSheetHolder.getTempFormula().toString()); + } + + @Override + public void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length) { + xlsxReadContext.xlsxReadSheetHolder().getTempFormula().append(ch, start, length); + } +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java new file mode 100644 index 0000000..277348a --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellInlineStringValueTagHandler.java @@ -0,0 +1,23 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import org.apache.poi.xssf.usermodel.XSSFRichTextString; + +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.metadata.CellData; + +/** + * Cell inline string value handler + * + * @author jipengfei + */ +public class CellInlineStringValueTagHandler extends AbstractCellValueTagHandler { + + @Override + protected void setStringValue(XlsxReadContext xlsxReadContext) { + // This is a special form of string + CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData(); + XSSFRichTextString richTextString = new XSSFRichTextString(tempCellData.getStringValue()); + tempCellData.setStringValue(richTextString.toString()); + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java new file mode 100644 index 0000000..8ef0786 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java @@ -0,0 +1,53 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_DATA_FORMAT_TAG; +import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TYPE_TAG; + +import org.apache.poi.xssf.usermodel.XSSFCellStyle; +import org.xml.sax.Attributes; + +import com.alibaba.excel.constant.BuiltinFormats; +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; +import com.alibaba.excel.util.PositionUtils; + +/** + * Cell Handler + * + * @author jipengfei + */ +public class CellTagHandler extends AbstractXlsxTagHandler { + + @Override + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); + xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.POSITION))); + + // t="s" ,it's means String + // t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml' + // t="inlineStr" ,it's means String + // t="b" ,it's means Boolean + // t="e" ,it's means Error + // t="n" ,it's means Number + // t is null ,it's means Empty or Number + CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(CELL_VALUE_TYPE_TAG)); + xlsxReadSheetHolder.setTempCellData(new CellData(type)); + xlsxReadSheetHolder.setTempData(new StringBuilder()); + + // Put in data transformation information + String dateFormatIndex = attributes.getValue(CELL_DATA_FORMAT_TAG); + if (dateFormatIndex != null) { + int dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); + XSSFCellStyle xssfCellStyle = + xlsxReadContext.xlsxReadWorkbookHolder().getStylesTable().getStyleAt(dateFormatIndexInteger); + int dataFormat = xssfCellStyle.getDataFormat(); + xlsxReadSheetHolder.getTempCellData().setDataFormat(dataFormat); + xlsxReadSheetHolder.getTempCellData().setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, + xssfCellStyle.getDataFormatString(), xlsxReadSheetHolder.getGlobalConfiguration().getLocale())); + } + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java new file mode 100644 index 0000000..09c9264 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellValueTagHandler.java @@ -0,0 +1,34 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.CellDataTypeEnum; +import com.alibaba.excel.metadata.CellData; + +/** + * Cell Value Handler + * + * @author jipengfei + */ +public class CellValueTagHandler extends AbstractCellValueTagHandler { + + @Override + protected void setStringValue(XlsxReadContext xlsxReadContext) { + // Have to go "sharedStrings.xml" and get it + CellData tempCellData = xlsxReadContext.xlsxReadSheetHolder().getTempCellData(); + switch (tempCellData.getType()) { + case STRING: + String stringValue = xlsxReadContext.readWorkbookHolder().getReadCache() + .get(Integer.valueOf(tempCellData.getStringValue())); + if (stringValue != null && xlsxReadContext.currentReadHolder().globalConfiguration().getAutoTrim()) { + stringValue = stringValue.trim(); + } + tempCellData.setStringValue(stringValue); + break; + case DIRECT_STRING: + tempCellData.setType(CellDataTypeEnum.STRING); + break; + default: + } + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java similarity index 68% rename from src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java rename to src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java index dbc0a7e..c1eb323 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountRowCellHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java @@ -11,19 +11,14 @@ import com.alibaba.excel.context.xlsx.XlsxReadContext; * * @author jipengfei */ -public class CountRowCellHandler implements XlsxCellHandler { - +public class CountTagHandler extends AbstractXlsxTagHandler { @Override - public void startHandle(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { String d = attributes.getValue(DIMENSION_REF); String totalStr = d.substring(d.indexOf(":") + 1, d.length()); String c = totalStr.toUpperCase().replaceAll("[A-Z]", ""); xlsxReadContext.readSheetHolder().setApproximateTotalRowNumber(Integer.parseInt(c)); } - @Override - public void endHandle(XlsxReadContext xlsxReadContext, String name) { - } - } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java deleted file mode 100644 index baa3990..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/DefaultCellHandler.java +++ /dev/null @@ -1,169 +0,0 @@ -package com.alibaba.excel.analysis.v07.handlers; - -import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_DATA_FORMAT_TAG; -import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_FORMULA_TAG; -import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG; -import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_TAG; -import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TAG; -import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TYPE_TAG; - -import java.math.BigDecimal; -import java.util.Deque; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.Map; - -import org.apache.poi.xssf.usermodel.XSSFCellStyle; -import org.apache.poi.xssf.usermodel.XSSFRichTextString; -import org.xml.sax.Attributes; - -import com.alibaba.excel.analysis.v07.XlsxRowResultHolder; -import com.alibaba.excel.constant.BuiltinFormats; -import com.alibaba.excel.constant.ExcelXmlConstants; -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.enums.CellDataTypeEnum; -import com.alibaba.excel.metadata.CellData; -import com.alibaba.excel.util.BooleanUtils; -import com.alibaba.excel.util.PositionUtils; - -/** - * Cell Handler - * - * @author jipengfei - */ -public class DefaultCellHandler implements XlsxCellHandler, XlsxRowResultHolder { - private final AnalysisContext analysisContext; - private Deque currentTagDeque = new LinkedList(); - private int curCol; - private Map curRowContent = new LinkedHashMap(); - private CellData currentCellData; - private StringBuilder dataStringBuilder; - private StringBuilder formulaStringBuilder; - - @Override - public void clearResult() { - curRowContent = new LinkedHashMap(); - } - - @Override - public boolean support(String name) { - return CELL_VALUE_TAG.equals(name) || CELL_FORMULA_TAG.equals(name) || CELL_INLINE_STRING_VALUE_TAG.equals(name) - || CELL_TAG.equals(name); - } - - @Override - public void startHandle(String name, Attributes attributes) { - currentTagDeque.push(name); - // start a cell - if (CELL_TAG.equals(name)) { - curCol = PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.POSITION)); - - // t="s" ,it's means String - // t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml' - // t="inlineStr" ,it's means String - // t="b" ,it's means Boolean - // t="e" ,it's means Error - // t="n" ,it's means Number - // t is null ,it's means Empty or Number - CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(CELL_VALUE_TYPE_TAG)); - currentCellData = new CellData(type); - dataStringBuilder = new StringBuilder(); - - // Put in data transformation information - String dateFormatIndex = attributes.getValue(CELL_DATA_FORMAT_TAG); - if (dateFormatIndex != null) { - int dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); - XSSFCellStyle xssfCellStyle = stylesTable.getStyleAt(dateFormatIndexInteger); - int dataFormat = xssfCellStyle.getDataFormat(); - currentCellData.setDataFormat(dataFormat); - currentCellData.setDataFormatString( - BuiltinFormats.getBuiltinFormat(dataFormat, xssfCellStyle.getDataFormatString(), - analysisContext.readSheetHolder().getGlobalConfiguration().getLocale())); - } - } - // cell is formula - if (CELL_FORMULA_TAG.equals(name)) { - currentCellData.setFormula(Boolean.TRUE); - formulaStringBuilder = new StringBuilder(); - } - } - - @Override - public void endHandle(String name) { - currentTagDeque.pop(); - // cell is formula - if (CELL_FORMULA_TAG.equals(name)) { - currentCellData.setFormulaValue(formulaStringBuilder.toString()); - return; - } - if (CELL_VALUE_TAG.equals(name) || CELL_INLINE_STRING_VALUE_TAG.equals(name)) { - CellDataTypeEnum oldType = currentCellData.getType(); - switch (oldType) { - case DIRECT_STRING: - case STRING: - case ERROR: - currentCellData.setStringValue(dataStringBuilder.toString()); - break; - case BOOLEAN: - currentCellData.setBooleanValue(BooleanUtils.valueOf(dataStringBuilder.toString())); - break; - case NUMBER: - case EMPTY: - currentCellData.setType(CellDataTypeEnum.NUMBER); - currentCellData.setNumberValue(new BigDecimal(dataStringBuilder.toString())); - break; - default: - throw new IllegalStateException("Cannot set values now"); - } - - if (CELL_VALUE_TAG.equals(name)) { - // Have to go "sharedStrings.xml" and get it - if (currentCellData.getType() == CellDataTypeEnum.STRING) { - String stringValue = analysisContext.readWorkbookHolder().getReadCache() - .get(Integer.valueOf(currentCellData.getStringValue())); - if (stringValue != null - && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) { - stringValue = stringValue.trim(); - } - currentCellData.setStringValue(stringValue); - } else if (currentCellData.getType() == CellDataTypeEnum.DIRECT_STRING) { - currentCellData.setType(CellDataTypeEnum.STRING); - } - } - // This is a special form of string - if (CELL_INLINE_STRING_VALUE_TAG.equals(name)) { - XSSFRichTextString richTextString = new XSSFRichTextString(currentCellData.getStringValue()); - String stringValue = richTextString.toString(); - if (stringValue != null && analysisContext.currentReadHolder().globalConfiguration().getAutoTrim()) { - stringValue = stringValue.trim(); - } - currentCellData.setStringValue(stringValue); - } - - currentCellData.checkEmpty(); - curRowContent.put(curCol, currentCellData); - } - } - - @Override - public void appendCurrentCellValue(char[] ch, int start, int length) { - String currentTag = currentTagDeque.peek(); - if (currentTag == null) { - return; - } - if (CELL_FORMULA_TAG.equals(currentTag)) { - formulaStringBuilder.append(ch, start, length); - return; - } - if (!CELL_VALUE_TAG.equals(currentTag) && !CELL_INLINE_STRING_VALUE_TAG.equals(currentTag)) { - return; - } - dataStringBuilder.append(ch, start, length); - } - - @Override - public Map getCurRowContent() { - return curRowContent; - } - -} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java new file mode 100644 index 0000000..ee0154e --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/HyperlinkTagHandler.java @@ -0,0 +1,35 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; +import com.alibaba.excel.metadata.CellExtra; +import com.alibaba.excel.util.StringUtils; + +/** + * Cell Handler + * + * @author Jiaju Zhuang + */ +public class HyperlinkTagHandler extends AbstractXlsxTagHandler { + + @Override + public boolean support(XlsxReadContext xlsxReadContext) { + return xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.HYPERLINK); + } + + @Override + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + String ref = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_REF); + String location = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_LOCATION); + if (StringUtils.isEmpty(ref)) { + return; + } + CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.HYPERLINK, location, ref); + xlsxReadContext.readSheetHolder().setCellExtra(cellExtra); + xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext); + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/MergeCellTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/MergeCellTagHandler.java new file mode 100644 index 0000000..8b0fa04 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/MergeCellTagHandler.java @@ -0,0 +1,34 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; +import com.alibaba.excel.metadata.CellExtra; +import com.alibaba.excel.util.StringUtils; + +/** + * Cell Handler + * + * @author Jiaju Zhuang + */ +public class MergeCellTagHandler extends AbstractXlsxTagHandler { + + @Override + public boolean support(XlsxReadContext xlsxReadContext) { + return xlsxReadContext.readWorkbookHolder().getExtraReadSet().contains(CellExtraTypeEnum.MERGE); + } + + @Override + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + String ref = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_REF); + if (StringUtils.isEmpty(ref)) { + return; + } + CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.MERGE, null, ref); + xlsxReadContext.readSheetHolder().setCellExtra(cellExtra); + xlsxReadContext.analysisEventProcessor().extra(xlsxReadContext); + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java deleted file mode 100644 index 51a7123..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/ProcessResultCellHandler.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.alibaba.excel.analysis.v07.handlers; - -import org.xml.sax.Attributes; - -import com.alibaba.excel.constant.ExcelXmlConstants; -import com.alibaba.excel.context.xlsx.XlsxReadContext; -import com.alibaba.excel.enums.RowTypeEnum; -import com.alibaba.excel.read.metadata.holder.ReadRowHolder; -import com.alibaba.excel.util.PositionUtils; - -/** - * Cell Handler - * - * @author jipengfei - */ -public class ProcessResultCellHandler implements XlsxCellHandler { - - @Override - public void startHandle(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { - xlsxReadContext.readRowHolder( - new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION)), RowTypeEnum.DATA, - xlsxReadContext.readSheetHolder().getGlobalConfiguration())); - } - - @Override - public void endHandle(XlsxReadContext xlsxReadContext, String name) { - xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); - } - -} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java new file mode 100644 index 0000000..372a0a7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java @@ -0,0 +1,35 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import java.util.LinkedHashMap; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.context.xlsx.XlsxReadContext; +import com.alibaba.excel.enums.RowTypeEnum; +import com.alibaba.excel.metadata.Cell; +import com.alibaba.excel.read.metadata.holder.ReadRowHolder; +import com.alibaba.excel.util.PositionUtils; + +/** + * Cell Handler + * + * @author jipengfei + */ +public class RowTagHandler extends AbstractXlsxTagHandler { + + @Override + public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { + xlsxReadContext.readRowHolder( + new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION)), + RowTypeEnum.DATA, xlsxReadContext.readSheetHolder().getGlobalConfiguration(), null)); + } + + @Override + public void endElement(XlsxReadContext xlsxReadContext, String name) { + xlsxReadContext.readRowHolder().setCellMap(xlsxReadContext.xlsxReadSheetHolder().getCellMap()); + xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); + xlsxReadContext.xlsxReadSheetHolder().setCellMap(new LinkedHashMap()); + } + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxCellHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxCellHandler.java deleted file mode 100644 index 3ec2fd8..0000000 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxCellHandler.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.alibaba.excel.analysis.v07.handlers; - -import org.xml.sax.Attributes; - -import com.alibaba.excel.context.xlsx.XlsxReadContext; - -/** - * Cell handler - * - * @author Dan Zheng - */ -public interface XlsxCellHandler { - /** - * Start handle - * - * @param xlsxReadContext xlsxReadContext - * @param name Tag name - * @param attributes Tag attributes - */ - void startHandle(XlsxReadContext xlsxReadContext, String name, Attributes attributes); - - /** - * End handle - * - * @param xlsxReadContext xlsxReadContext - * @param name Tag name - */ - void endHandle(XlsxReadContext xlsxReadContext, String name); -} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java new file mode 100644 index 0000000..3bd353a --- /dev/null +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java @@ -0,0 +1,53 @@ +package com.alibaba.excel.analysis.v07.handlers; + +import org.xml.sax.Attributes; + +import com.alibaba.excel.context.xlsx.XlsxReadContext; + +/** + * Tag handler + * + * @author Dan Zheng + */ +public interface XlsxTagHandler { + + /** + * Whether to support + * + * @param xlsxReadContext + */ + boolean support(XlsxReadContext xlsxReadContext); + + /** + * Start handle + * + * @param xlsxReadContext + * xlsxReadContext + * @param name + * Tag name + * @param attributes + * Tag attributes + */ + void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes); + + /** + * End handle + * + * @param xlsxReadContext + * xlsxReadContext + * @param name + * Tag name + */ + void endElement(XlsxReadContext xlsxReadContext, String name); + + /** + * Read data + * + * @param xlsxReadContext + * @param ch + * @param start + * @param length + */ + void characters(XlsxReadContext xlsxReadContext, char[] ch, int start, int length); + +} diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java index 90e760a..0a4adb4 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java @@ -7,9 +7,15 @@ import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; -import com.alibaba.excel.analysis.v07.handlers.CountRowCellHandler; -import com.alibaba.excel.analysis.v07.handlers.ProcessResultCellHandler; -import com.alibaba.excel.analysis.v07.handlers.XlsxCellHandler; +import com.alibaba.excel.analysis.v07.handlers.CellFormulaTagHandler; +import com.alibaba.excel.analysis.v07.handlers.CellInlineStringValueTagHandler; +import com.alibaba.excel.analysis.v07.handlers.CellTagHandler; +import com.alibaba.excel.analysis.v07.handlers.CellValueTagHandler; +import com.alibaba.excel.analysis.v07.handlers.CountTagHandler; +import com.alibaba.excel.analysis.v07.handlers.HyperlinkTagHandler; +import com.alibaba.excel.analysis.v07.handlers.MergeCellTagHandler; +import com.alibaba.excel.analysis.v07.handlers.RowTagHandler; +import com.alibaba.excel.analysis.v07.handlers.XlsxTagHandler; import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.context.xlsx.XlsxReadContext; @@ -18,11 +24,18 @@ import com.alibaba.excel.context.xlsx.XlsxReadContext; */ public class XlsxRowHandler extends DefaultHandler { private XlsxReadContext xlsxReadContext; - private static final Map XLSX_CELL_HANDLER_MAP = new HashMap(16); + private static final Map XLSX_CELL_HANDLER_MAP = new HashMap(16); static { - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.DIMENSION, new CountRowCellHandler()); - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.ROW_TAG, new ProcessResultCellHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_FORMULA_TAG, new CellFormulaTagHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG, + new CellInlineStringValueTagHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_TAG, new CellTagHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_VALUE_TAG, new CellValueTagHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.DIMENSION, new CountTagHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.HYPERLINK_TAG, new HyperlinkTagHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.MERGE_CELL_TAG, new MergeCellTagHandler()); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.ROW_TAG, new RowTagHandler()); } public XlsxRowHandler(XlsxReadContext xlsxReadContext) { @@ -31,28 +44,35 @@ public class XlsxRowHandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { - XlsxCellHandler handler = XLSX_CELL_HANDLER_MAP.get(name); + XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(name); if (handler == null) { return; } - handler.startHandle(xlsxReadContext, name, attributes); + xlsxReadContext.xlsxReadSheetHolder().getTagDeque().push(name); + handler.startElement(xlsxReadContext, name, attributes); } @Override public void characters(char[] ch, int start, int length) throws SAXException { - if (rowResultHolder != null) { - rowResultHolder.appendCurrentCellValue(ch, start, length); + String currentTag = xlsxReadContext.xlsxReadSheetHolder().getTagDeque().peek(); + if (currentTag == null) { + return; } + XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(currentTag); + if (handler == null) { + return; + } + handler.characters(xlsxReadContext, ch, start, length); } @Override public void endElement(String uri, String localName, String name) throws SAXException { - XlsxCellHandler handler = XLSX_CELL_HANDLER_MAP.get(name); + XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(name); if (handler == null) { return; } - handler.endHandle(xlsxReadContext, name); + handler.endElement(xlsxReadContext, name); + xlsxReadContext.xlsxReadSheetHolder().getTagDeque().pop(); } - } diff --git a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java index f01a33b..5cb6662 100644 --- a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java +++ b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java @@ -22,4 +22,19 @@ public class ExcelXmlConstants { */ public static final String CELL_INLINE_STRING_VALUE_TAG = "t"; + public static final String MERGE_CELL_TAG = "mergeCell"; + public static final String HYPERLINK_TAG = "hyperlink"; + + /** + * Cell range split + */ + public static final String CELL_RANGE_SPLIT = ":"; + /** + * ref attribute + */ + public static final String ATTRIBUTE_REF = "ref"; + /** + * location attribute + */ + public static final String ATTRIBUTE_LOCATION = "location"; } diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java index b441459..684fb6e 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContext.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -92,20 +92,6 @@ public interface AnalysisContext { */ void readSheetList(List readSheetList); - /** - * Read all sheets - * - * @return - */ - Boolean readAll(); - - /** - * Read all sheets - * - * @return - */ - void readAll(Boolean readAll); - /** * get current sheet * diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java index 2b5a766..ab27e87 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContextImpl.java @@ -137,16 +137,6 @@ public class AnalysisContextImpl implements AnalysisContext { } - @Override - public Boolean readAll() { - return null; - } - - @Override - public void readAll(Boolean readAll) { - - } - @Override public Sheet getCurrentSheet() { Sheet sheet = new Sheet(readSheetHolder.getSheetNo() + 1); diff --git a/src/main/java/com/alibaba/excel/enums/CellExtraTypeEnum.java b/src/main/java/com/alibaba/excel/enums/CellExtraTypeEnum.java new file mode 100644 index 0000000..1c13b7c --- /dev/null +++ b/src/main/java/com/alibaba/excel/enums/CellExtraTypeEnum.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.enums; + +/** + * Extra data type + * + * @author Jiaju Zhuang + **/ +public enum CellExtraTypeEnum { + /** + * Comment + */ + COMMENT, + /** + * Hyperlink + */ + HYPERLINK, + /** + * Merge + */ + MERGE,; +} diff --git a/src/main/java/com/alibaba/excel/enums/ExtraReadEnum.java b/src/main/java/com/alibaba/excel/enums/ExtraReadEnum.java deleted file mode 100644 index 2dee2bf..0000000 --- a/src/main/java/com/alibaba/excel/enums/ExtraReadEnum.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.alibaba.excel.enums; - -/** - * Read some extra data - * - * @author Jiaju Zhuang - **/ -public enum ExtraReadEnum { - /** - * Read the comment - */ - COMMENT,; -} diff --git a/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java b/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java index 75dfc67..e371cbd 100644 --- a/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java +++ b/src/main/java/com/alibaba/excel/enums/RowTypeEnum.java @@ -10,10 +10,6 @@ public enum RowTypeEnum { * data */ DATA, - /** - * extra - */ - EXTRA, /** * empty */ diff --git a/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java b/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java index 22a95f0..1e93397 100644 --- a/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java +++ b/src/main/java/com/alibaba/excel/event/AbstractIgnoreExceptionReadListener.java @@ -1,6 +1,7 @@ package com.alibaba.excel.event; import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.metadata.CellExtra; import com.alibaba.excel.read.listener.ReadListener; /** @@ -20,6 +21,17 @@ public abstract class AbstractIgnoreExceptionReadListener implements ReadList @Override public void onException(Exception exception, AnalysisContext context) {} + /** + * The current method is called when extra information is returned + * + * @param extra + * extra information + * @param context + * analysis context + */ + @Override + public void extra(CellExtra extra, AnalysisContext context) {} + @Override public boolean hasNext(AnalysisContext context) { return true; diff --git a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java index 176bd79..4b1b802 100644 --- a/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java +++ b/src/main/java/com/alibaba/excel/event/AnalysisEventListener.java @@ -4,6 +4,7 @@ import java.util.Map; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.CellExtra; import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.util.ConverterUtils; @@ -27,6 +28,17 @@ public abstract class AnalysisEventListener implements ReadListener { */ public void invokeHeadMap(Map headMap, AnalysisContext context) {} + /** + * The current method is called when extra information is returned + * + * @param extra + * extra information + * @param context + * analysis context + */ + @Override + public void extra(CellExtra extra, AnalysisContext context) {} + /** * All listeners receive this method when any one Listener does an error report. If an exception is thrown here, the * entire read will terminate. diff --git a/src/main/java/com/alibaba/excel/metadata/CellExtra.java b/src/main/java/com/alibaba/excel/metadata/CellExtra.java index 3570eb9..3a9c2b3 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellExtra.java +++ b/src/main/java/com/alibaba/excel/metadata/CellExtra.java @@ -1,18 +1,121 @@ package com.alibaba.excel.metadata; +import org.apache.poi.ss.util.CellReference; + +import com.alibaba.excel.constant.ExcelXmlConstants; +import com.alibaba.excel.enums.CellExtraTypeEnum; + /** * Cell extra information. * * @author Jiaju Zhuang */ public class CellExtra extends AbstractCell { - private String note; + /** + * Cell extra type + */ + private CellExtraTypeEnum type; + /** + * Cell extra data + */ + private String text; + /** + * First row index,if this object is an interval + */ + private Integer firstRowIndex; + /** + * First column index,if this object is an interval + */ + private Integer firstColumnIndex; + /** + * Last row index,if this object is an interval + */ + private Integer lastRowIndex; + /** + * Last column index,if this object is an interval + */ + private Integer lastColumnIndex; + + public CellExtra(CellExtraTypeEnum type, String text, String range) { + super(); + this.type = type; + this.text = text; + String[] ranges = range.split(ExcelXmlConstants.CELL_RANGE_SPLIT); + CellReference first = new CellReference(ranges[0]); + CellReference last = first; + this.firstRowIndex = first.getRow(); + this.firstColumnIndex = (int)first.getCol(); + setRowIndex(this.firstRowIndex); + setColumnIndex(this.firstColumnIndex); + if (ranges.length > 1) { + last = new CellReference(ranges[1]); + } + this.lastRowIndex = last.getRow(); + this.lastColumnIndex = (int)last.getCol(); + } + + public CellExtra(CellExtraTypeEnum type, String text, Integer rowIndex, Integer columnIndex) { + this(type, text, rowIndex, columnIndex, rowIndex, columnIndex); + } + + public CellExtra(CellExtraTypeEnum type, String text, Integer firstRowIndex, Integer firstColumnIndex, + Integer lastRowIndex, Integer lastColumnIndex) { + super(); + setRowIndex(firstRowIndex); + setColumnIndex(firstColumnIndex); + this.type = type; + this.text = text; + this.firstRowIndex = firstRowIndex; + this.firstColumnIndex = firstColumnIndex; + this.lastRowIndex = lastRowIndex; + this.lastColumnIndex = lastColumnIndex; + } + + public CellExtraTypeEnum getType() { + return type; + } + + public void setType(CellExtraTypeEnum type) { + this.type = type; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public Integer getFirstRowIndex() { + return firstRowIndex; + } + + public void setFirstRowIndex(Integer firstRowIndex) { + this.firstRowIndex = firstRowIndex; + } + + public Integer getFirstColumnIndex() { + return firstColumnIndex; + } + + public void setFirstColumnIndex(Integer firstColumnIndex) { + this.firstColumnIndex = firstColumnIndex; + } + + public Integer getLastRowIndex() { + return lastRowIndex; + } + + public void setLastRowIndex(Integer lastRowIndex) { + this.lastRowIndex = lastRowIndex; + } - public String getNote() { - return note; + public Integer getLastColumnIndex() { + return lastColumnIndex; } - public void setNote(String note) { - this.note = note; + public void setLastColumnIndex(Integer lastColumnIndex) { + this.lastColumnIndex = lastColumnIndex; } } diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java index ae3b79c..342d943 100644 --- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java +++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java @@ -2,6 +2,8 @@ package com.alibaba.excel.read.builder; import java.io.File; import java.io.InputStream; +import java.util.HashSet; +import java.util.List; import javax.xml.parsers.SAXParserFactory; @@ -9,9 +11,10 @@ import com.alibaba.excel.ExcelReader; import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.event.SyncReadListener; import com.alibaba.excel.read.listener.ModelBuildEventListener; -import com.alibaba.excel.read.listener.ReadListener; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.support.ExcelTypeEnum; @@ -158,6 +161,21 @@ public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder()); + } + readWorkbook.getExtraReadSet().add(extraType); + return this; + } + /** * Whether to use the default listener, which is used by default. *

@@ -175,11 +193,24 @@ public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder List doReadAllSync() { ExcelReader excelReader = build(); + SyncReadListener syncReadListener = new SyncReadListener(); + registerReadListener(syncReadListener); excelReader.readAll(); excelReader.finish(); - return excelReader; + return (List)syncReadListener.getList(); } public ExcelReaderSheetBuilder sheet() { diff --git a/src/main/java/com/alibaba/excel/read/listener/ReadListener.java b/src/main/java/com/alibaba/excel/read/listener/ReadListener.java index 142c531..f1d341f 100644 --- a/src/main/java/com/alibaba/excel/read/listener/ReadListener.java +++ b/src/main/java/com/alibaba/excel/read/listener/ReadListener.java @@ -5,6 +5,7 @@ import java.util.Map; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.Listener; import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.CellExtra; /** * Interface to listen for read results @@ -40,6 +41,16 @@ public interface ReadListener extends Listener { */ void invoke(T data, AnalysisContext context); + /** + * The current method is called when extra information is returned + * + * @param extra + * extra information + * @param context + * analysis context + */ + void extra(CellExtra extra, AnalysisContext context); + /** * if have something to do after all analysis * diff --git a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java index c08ab18..c9e4db9 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java +++ b/src/main/java/com/alibaba/excel/read/metadata/ReadWorkbook.java @@ -9,7 +9,7 @@ import javax.xml.parsers.SAXParserFactory; import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.enums.ExtraReadEnum; +import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.read.listener.ModelBuildEventListener; import com.alibaba.excel.support.ExcelTypeEnum; @@ -88,9 +88,9 @@ public class ReadWorkbook extends ReadBasicParameter { /** * Read some additional fields. None are read by default. * - * @see ExtraReadEnum + * @see CellExtraTypeEnum */ - private Set extraReadSet; + private Set extraReadSet; /** * The default is all excel objects.Default is true. *

@@ -221,11 +221,11 @@ public class ReadWorkbook extends ReadBasicParameter { this.useDefaultListener = useDefaultListener; } - public Set getExtraReadSet() { + public Set getExtraReadSet() { return extraReadSet; } - public void setExtraReadSet(Set extraReadSet) { + public void setExtraReadSet(Set extraReadSet) { this.extraReadSet = extraReadSet; } } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java index da74509..d81df87 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadRowHolder.java @@ -35,10 +35,12 @@ public class ReadRowHolder implements Holder { */ private GlobalConfiguration globalConfiguration; - public ReadRowHolder(Integer rowIndex, RowTypeEnum rowType, GlobalConfiguration globalConfiguration) { + public ReadRowHolder(Integer rowIndex, RowTypeEnum rowType, GlobalConfiguration globalConfiguration, + Map cellMap) { this.rowIndex = rowIndex; this.rowType = rowType; this.globalConfiguration = globalConfiguration; + this.cellMap = cellMap; } public GlobalConfiguration getGlobalConfiguration() { diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java index 84dd4c4..87185dc 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadSheetHolder.java @@ -1,6 +1,12 @@ package com.alibaba.excel.read.metadata.holder; +import java.util.LinkedHashMap; +import java.util.Map; + import com.alibaba.excel.enums.HolderEnum; +import com.alibaba.excel.metadata.Cell; +import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.CellExtra; import com.alibaba.excel.read.metadata.ReadSheet; /** @@ -29,6 +35,22 @@ public class ReadSheetHolder extends AbstractReadHolder { * Gets the total number of rows , data may be inaccurate */ private Integer approximateTotalRowNumber; + /** + * Data storage of the current row. + */ + private Map cellMap; + /** + * Data storage of the current extra cell. + */ + private CellExtra cellExtra; + /** + * Index of the current row. + */ + private Integer rowIndex; + /** + * Current CellData + */ + private CellData tempCellData; public ReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { super(readSheet, readWorkbookHolder, readWorkbookHolder.getReadWorkbook().getConvertAllFiled()); @@ -36,6 +58,7 @@ public class ReadSheetHolder extends AbstractReadHolder { this.parentReadWorkbookHolder = readWorkbookHolder; this.sheetNo = readSheet.getSheetNo(); this.sheetName = readSheet.getSheetName(); + this.cellMap = new LinkedHashMap(); } public ReadSheet getReadSheet() { @@ -71,7 +94,6 @@ public class ReadSheetHolder extends AbstractReadHolder { } /** - * * Approximate total number of rows * * @return @@ -95,6 +117,38 @@ public class ReadSheetHolder extends AbstractReadHolder { this.approximateTotalRowNumber = approximateTotalRowNumber; } + public Map getCellMap() { + return cellMap; + } + + public void setCellMap(Map cellMap) { + this.cellMap = cellMap; + } + + public Integer getRowIndex() { + return rowIndex; + } + + public void setRowIndex(Integer rowIndex) { + this.rowIndex = rowIndex; + } + + public CellData getTempCellData() { + return tempCellData; + } + + public void setTempCellData(CellData tempCellData) { + this.tempCellData = tempCellData; + } + + public CellExtra getCellExtra() { + return cellExtra; + } + + public void setCellExtra(CellExtra cellExtra) { + this.cellExtra = cellExtra; + } + @Override public HolderEnum holderType() { return HolderEnum.SHEET; diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java index 1c1b242..7ad8972 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java @@ -7,17 +7,12 @@ import java.util.HashSet; import java.util.List; import java.util.Set; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.poi.openxml4j.opc.OPCPackage; -import org.apache.poi.poifs.filesystem.POIFSFileSystem; - import com.alibaba.excel.cache.ReadCache; import com.alibaba.excel.cache.selector.EternalReadCacheSelector; import com.alibaba.excel.cache.selector.ReadCacheSelector; import com.alibaba.excel.cache.selector.SimpleReadCacheSelector; import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.enums.ExtraReadEnum; +import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.enums.HolderEnum; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.excel.exception.ExcelAnalysisException; @@ -91,9 +86,9 @@ public class ReadWorkbookHolder extends AbstractReadHolder { /** * Read some additional fields. None are read by default. * - * @see ExtraReadEnum + * @see CellExtraTypeEnum */ - private Set extraReadSet; + private Set extraReadSet; /** * Actual sheet data */ @@ -101,7 +96,7 @@ public class ReadWorkbookHolder extends AbstractReadHolder { /** * Parameter sheet data */ - private List parametersheetDataList; + private List parameterSheetDataList; /** * Read all */ @@ -152,11 +147,6 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.autoCloseStream = readWorkbook.getAutoCloseStream(); } - this.excelType = readWorkbook.getExcelType(); - - if (ExcelTypeEnum.XLS == excelType && getGlobalConfiguration().getUse1904windowing() == null) { - getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); - } this.customObject = readWorkbook.getCustomObject(); if (readWorkbook.getIgnoreEmptyRow() == null) { this.ignoreEmptyRow = Boolean.TRUE; @@ -181,7 +171,7 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.defaultReturnMap = readWorkbook.getDefaultReturnMap(); } if (readWorkbook.getExtraReadSet() == null) { - this.extraReadSet = new HashSet(); + this.extraReadSet = new HashSet(); } else { this.extraReadSet = readWorkbook.getExtraReadSet(); } @@ -309,11 +299,11 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.password = password; } - public Set getExtraReadSet() { + public Set getExtraReadSet() { return extraReadSet; } - public void setExtraReadSet(Set extraReadSet) { + public void setExtraReadSet(Set extraReadSet) { this.extraReadSet = extraReadSet; } @@ -325,12 +315,12 @@ public class ReadWorkbookHolder extends AbstractReadHolder { this.actualSheetDataList = actualSheetDataList; } - public List getParametersheetDataList() { - return parametersheetDataList; + public List getParameterSheetDataList() { + return parameterSheetDataList; } - public void setParametersheetDataList(List parametersheetDataList) { - this.parametersheetDataList = parametersheetDataList; + public void setParameterSheetDataList(List parameterSheetDataList) { + this.parameterSheetDataList = parameterSheetDataList; } public Boolean getReadAll() { diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java index a77a8d3..d0171ff 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadSheetHolder.java @@ -1,12 +1,9 @@ package com.alibaba.excel.read.metadata.holder.xls; import java.util.HashMap; -import java.util.LinkedHashMap; import java.util.Map; import com.alibaba.excel.enums.RowTypeEnum; -import com.alibaba.excel.metadata.Cell; -import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; @@ -21,22 +18,10 @@ public class XlsReadSheetHolder extends ReadSheetHolder { * Row type.Temporary storage, last set in ReadRowHolder. */ private RowTypeEnum tempRowType; - /** - * Data storage of the current row. - */ - private Map cellMap; - /** - * Index of the current row. - */ - private Integer rowIndex; /** * Ignore record. */ private Boolean ignoreRecord; - /** - * Temp Cell Data. - */ - private CellData tempCellData; /** * Temp object index. */ @@ -48,7 +33,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder { public XlsReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { super(readSheet, readWorkbookHolder); - cellMap = new LinkedHashMap(); ignoreRecord = Boolean.FALSE; tempRowType = RowTypeEnum.EMPTY; objectCacheMap = new HashMap(16); @@ -62,22 +46,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder { this.tempRowType = tempRowType; } - public Map getCellMap() { - return cellMap; - } - - public void setCellMap(Map cellMap) { - this.cellMap = cellMap; - } - - public Integer getRowIndex() { - return rowIndex; - } - - public void setRowIndex(Integer rowIndex) { - this.rowIndex = rowIndex; - } - public Boolean getIgnoreRecord() { return ignoreRecord; } @@ -86,14 +54,6 @@ public class XlsReadSheetHolder extends ReadSheetHolder { this.ignoreRecord = ignoreRecord; } - public CellData getTempCellData() { - return tempCellData; - } - - public void setTempCellData(CellData tempCellData) { - this.tempCellData = tempCellData; - } - public Integer getTempObjectIndex() { return tempObjectIndex; } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java index c4b698c..70c1c03 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xls/XlsReadWorkbookHolder.java @@ -1,5 +1,6 @@ package com.alibaba.excel.read.metadata.holder.xls; +import java.util.ArrayList; import java.util.List; import org.apache.poi.hssf.eventusermodel.FormatTrackingHSSFListener; @@ -9,6 +10,7 @@ import org.apache.poi.poifs.filesystem.POIFSFileSystem; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; +import com.alibaba.excel.support.ExcelTypeEnum; /** * Workbook holder @@ -27,7 +29,7 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder { /** * HSSFWorkbook */ - private HSSFWorkbook hsffWorkbook; + private HSSFWorkbook hssfWorkbook; /** * Bound sheet record list. */ @@ -43,6 +45,12 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder { public XlsReadWorkbookHolder(ReadWorkbook readWorkbook) { super(readWorkbook); + this.boundSheetRecordList = new ArrayList(); + this.needReadSheet = Boolean.TRUE; + setExcelType(ExcelTypeEnum.XLS); + if (getGlobalConfiguration().getUse1904windowing() == null) { + getGlobalConfiguration().setUse1904windowing(Boolean.FALSE); + } } public POIFSFileSystem getPoifsFileSystem() { @@ -61,12 +69,12 @@ public class XlsReadWorkbookHolder extends ReadWorkbookHolder { this.formatTrackingHSSFListener = formatTrackingHSSFListener; } - public HSSFWorkbook getHsffWorkbook() { - return hsffWorkbook; + public HSSFWorkbook getHssfWorkbook() { + return hssfWorkbook; } - public void setHsffWorkbook(HSSFWorkbook hsffWorkbook) { - this.hsffWorkbook = hsffWorkbook; + public void setHssfWorkbook(HSSFWorkbook hssfWorkbook) { + this.hssfWorkbook = hssfWorkbook; } public List getBoundSheetRecordList() { diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java index 2e1174d..46b9281 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadSheetHolder.java @@ -1,5 +1,8 @@ package com.alibaba.excel.read.metadata.holder.xlsx; +import java.util.Deque; +import java.util.LinkedList; + import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.holder.ReadSheetHolder; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; @@ -10,10 +13,57 @@ import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; * @author Jiaju Zhuang */ public class XlsxReadSheetHolder extends ReadSheetHolder { - - + /** + * Record the label of the current operation to prevent NPE. + */ + private Deque tagDeque; + /** + * Current Column + */ + private Integer columnIndex; + /** + * Data for current label. + */ + private StringBuilder tempData; + /** + * Formula for current label. + */ + private StringBuilder tempFormula; public XlsxReadSheetHolder(ReadSheet readSheet, ReadWorkbookHolder readWorkbookHolder) { super(readSheet, readWorkbookHolder); + this.tagDeque = new LinkedList(); + } + + public Deque getTagDeque() { + return tagDeque; + } + + public void setTagDeque(Deque tagDeque) { + this.tagDeque = tagDeque; + } + + public Integer getColumnIndex() { + return columnIndex; + } + + public void setColumnIndex(Integer columnIndex) { + this.columnIndex = columnIndex; + } + + public StringBuilder getTempData() { + return tempData; + } + + public void setTempData(StringBuilder tempData) { + this.tempData = tempData; + } + + public StringBuilder getTempFormula() { + return tempFormula; + } + + public void setTempFormula(StringBuilder tempFormula) { + this.tempFormula = tempFormula; } } diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java index 9542366..066131d 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/xlsx/XlsxReadWorkbookHolder.java @@ -7,6 +7,7 @@ import org.apache.poi.xssf.model.StylesTable; import com.alibaba.excel.read.metadata.ReadWorkbook; import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; +import com.alibaba.excel.support.ExcelTypeEnum; /** * Workbook holder @@ -37,6 +38,7 @@ public class XlsxReadWorkbookHolder extends ReadWorkbookHolder { public XlsxReadWorkbookHolder(ReadWorkbook readWorkbook) { super(readWorkbook); this.saxParserFactoryName = readWorkbook.getXlsxSAXParserFactoryName(); + setExcelType(ExcelTypeEnum.XLSX); } public OPCPackage getOpcPackage() { diff --git a/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java b/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java index cd48538..360ae97 100644 --- a/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java +++ b/src/main/java/com/alibaba/excel/read/processor/AnalysisEventProcessor.java @@ -9,6 +9,13 @@ import com.alibaba.excel.context.AnalysisContext; * @author jipengfei */ public interface AnalysisEventProcessor { + /** + * Read extra information + * + * @param analysisContext + */ + void extra(AnalysisContext analysisContext); + /** * End row * diff --git a/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java b/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java index 6b5b0af..ddd1950 100644 --- a/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java +++ b/src/main/java/com/alibaba/excel/read/processor/DefaultAnalysisEventProcessor.java @@ -9,6 +9,7 @@ import org.slf4j.LoggerFactory; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.enums.HeadKindEnum; +import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.metadata.CellData; @@ -28,29 +29,22 @@ import com.alibaba.excel.util.StringUtils; public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor { private static final Logger LOGGER = LoggerFactory.getLogger(DefaultAnalysisEventProcessor.class); + @Override + public void extra(AnalysisContext analysisContext) { + dealExtra(analysisContext); + } + @Override public void endRow(AnalysisContext analysisContext) { - switch (analysisContext.readRowHolder().getRowType()) { - case EMPTY: - if (LOGGER.isDebugEnabled()) { - LOGGER.warn("Empty row!"); - } - if (analysisContext.readWorkbookHolder().getIgnoreEmptyRow()) { - return; - } - // Need to continue to notify invoke. - dealData(analysisContext); - break; - case DATA: - dealData(analysisContext); - break; - case EXTRA: - dealExtra(analysisContext); - break; - default: - throw new ExcelAnalysisException("Wrong row type."); + if (RowTypeEnum.EMPTY.equals(analysisContext.readRowHolder().getRowType())) { + if (LOGGER.isDebugEnabled()) { + LOGGER.warn("Empty row!"); + } + if (analysisContext.readWorkbookHolder().getIgnoreEmptyRow()) { + return; + } } - + dealData(analysisContext); } @Override @@ -61,13 +55,34 @@ public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor { } private void dealExtra(AnalysisContext analysisContext) { + for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) { + try { + readListener.extra(analysisContext.readSheetHolder().getCellExtra(), analysisContext); + } catch (Exception e) { + onException(analysisContext, e); + break; + } + if (!readListener.hasNext(analysisContext)) { + throw new ExcelAnalysisStopException(); + } + } + } - + private void onException(AnalysisContext analysisContext, Exception e) { + for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) { + try { + readListenerException.onException(e, analysisContext); + } catch (RuntimeException re) { + throw re; + } catch (Exception e1) { + throw new ExcelAnalysisException(e1.getMessage(), e1); + } + } } private void dealData(AnalysisContext analysisContext) { ReadRowHolder readRowHolder = analysisContext.readRowHolder(); - Map cellDataMap = (Map) readRowHolder.getCellMap(); + Map cellDataMap = (Map)readRowHolder.getCellMap(); readRowHolder.setCurrentRowAnalysisResult(cellDataMap); int rowIndex = readRowHolder.getRowIndex(); int currentHeadRowNumber = analysisContext.readSheetHolder().getHeadRowNumber(); @@ -78,7 +93,6 @@ public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor { if (!isData && currentHeadRowNumber == rowIndex + 1) { buildHead(analysisContext, cellDataMap); } - // Now is data for (ReadListener readListener : analysisContext.currentReadHolder().readListenerList()) { try { @@ -88,15 +102,7 @@ public class DefaultAnalysisEventProcessor implements AnalysisEventProcessor { readListener.invokeHead(cellDataMap, analysisContext); } } catch (Exception e) { - for (ReadListener readListenerException : analysisContext.currentReadHolder().readListenerList()) { - try { - readListenerException.onException(e, analysisContext); - } catch (RuntimeException re) { - throw re; - } catch (Exception e1) { - throw new ExcelAnalysisException(e1.getMessage(), e1); - } - } + onException(analysisContext, e); break; } if (!readListener.hasNext(analysisContext)) { diff --git a/src/main/java/com/alibaba/excel/util/SheetUtils.java b/src/main/java/com/alibaba/excel/util/SheetUtils.java index fb2c59e..c2c727c 100644 --- a/src/main/java/com/alibaba/excel/util/SheetUtils.java +++ b/src/main/java/com/alibaba/excel/util/SheetUtils.java @@ -5,6 +5,7 @@ import org.slf4j.LoggerFactory; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.read.metadata.ReadSheet; +import com.alibaba.excel.read.metadata.holder.ReadWorkbookHolder; /** * Sheet utils @@ -14,21 +15,22 @@ import com.alibaba.excel.read.metadata.ReadSheet; public class SheetUtils { private static final Logger LOGGER = LoggerFactory.getLogger(SheetUtils.class); - private SheetUtils() { - } + private SheetUtils() {} /** * Match the parameters to the actual sheet * - * @param readSheet actual sheet + * @param readSheet + * actual sheet * @param analysisContext * @return */ public static ReadSheet match(ReadSheet readSheet, AnalysisContext analysisContext) { - if (analysisContext.readAll()) { + ReadWorkbookHolder readWorkbookHolder = analysisContext.readWorkbookHolder(); + if (readWorkbookHolder.getReadAll()) { return readSheet; } - for (ReadSheet parameterReadSheet : analysisContext.readSheetList()) { + for (ReadSheet parameterReadSheet : readWorkbookHolder.getParameterSheetDataList()) { if (parameterReadSheet == null) { continue; } @@ -45,7 +47,7 @@ public class SheetUtils { if (!StringUtils.isEmpty(parameterSheetName)) { boolean autoTrim = (parameterReadSheet.getAutoTrim() != null && parameterReadSheet.getAutoTrim()) || (parameterReadSheet.getAutoTrim() == null - && analysisContext.readWorkbookHolder().getGlobalConfiguration().getAutoTrim()); + && analysisContext.readWorkbookHolder().getGlobalConfiguration().getAutoTrim()); if (autoTrim) { parameterSheetName = parameterSheetName.trim(); } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraData.java b/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraData.java new file mode 100644 index 0000000..61822fa --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.core.extra; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class ExtraData { + + private String row1; + + private String row2; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataListener.java new file mode 100644 index 0000000..9039ab0 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataListener.java @@ -0,0 +1,55 @@ +package com.alibaba.easyexcel.test.core.extra; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.CellExtra; +import com.alibaba.fastjson.JSON; + +/** + * @author Jiaju Zhuang + */ +public class ExtraDataListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(ExtraData.class); + + @Override + public void invoke(ExtraData data, AnalysisContext context) {} + + @Override + public void doAfterAllAnalysed(AnalysisContext context) {} + + @Override + public void extra(CellExtra extra, AnalysisContext context) { + LOGGER.info("extra data:{}", JSON.toJSONString(extra)); + switch (extra.getType()) { + case COMMENT: + Assert.assertEquals("批注的内容", extra.getText()); + Assert.assertEquals(4, (int)extra.getRowIndex()); + Assert.assertEquals(0, (int)extra.getColumnIndex()); + break; + case HYPERLINK: + if ("Sheet1!A1".equals(extra.getText())) { + Assert.assertEquals(1, (int)extra.getRowIndex()); + Assert.assertEquals(0, (int)extra.getColumnIndex()); + } else if ("Sheet2!A1".equals(extra.getText())) { + Assert.assertEquals(2, (int)extra.getFirstRowIndex()); + Assert.assertEquals(0, (int)extra.getFirstColumnIndex()); + Assert.assertEquals(3, (int)extra.getLastRowIndex()); + Assert.assertEquals(1, (int)extra.getLastColumnIndex()); + } else { + Assert.fail("Unknown hyperlink!"); + } + break; + case MERGE: + Assert.assertEquals(5, (int)extra.getFirstRowIndex()); + Assert.assertEquals(0, (int)extra.getFirstColumnIndex()); + Assert.assertEquals(6, (int)extra.getLastRowIndex()); + Assert.assertEquals(1, (int)extra.getLastColumnIndex()); + break; + default: + } + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataTest.java new file mode 100644 index 0000000..cf7418d --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/core/extra/ExtraDataTest.java @@ -0,0 +1,44 @@ +package com.alibaba.easyexcel.test.core.extra; + +import java.io.File; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.easyexcel.test.util.TestFileUtil; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.enums.CellExtraTypeEnum; + +/** + * + * @author Jiaju Zhuang + */ +public class ExtraDataTest { + private static final Logger LOGGER = LoggerFactory.getLogger(ExtraDataTest.class); + private static File file03; + private static File file07; + + @BeforeClass + public static void init() { + file03 = TestFileUtil.readFile("extra" + File.separator + "extra.xls"); + file07 = TestFileUtil.readFile("extra" + File.separator + "extra.xlsx"); + } + + @Test + public void t01Read07() { + read(file07); + } + + @Test + public void t02Read03() { + read(file03); + } + + private void read(File file) { + EasyExcel.read(file, ExtraData.class, new ExtraDataListener()).extraRead(CellExtraTypeEnum.COMMENT) + .extraRead(CellExtraTypeEnum.HYPERLINK).extraRead(CellExtraTypeEnum.MERGE).sheet().doRead(); + } + +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java index ece5aa0..30325d1 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java @@ -3,6 +3,7 @@ package com.alibaba.easyexcel.test.temp; import java.io.File; import java.util.List; +import org.apache.poi.hssf.util.CellReference; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; @@ -31,6 +32,11 @@ public class Lock2Test { } } + @Test + public void testc() throws Exception { + LOGGER.info("reslut:{}", JSON.toJSONString(new CellReference("B3"))); + } + @Test public void simpleRead() { // 写法1: diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java index bcb1d99..21e0d9c 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java @@ -25,7 +25,7 @@ public class CommentTest { @Test public void comment() throws Exception { File file = new File("D:\\test\\comment.xls"); - List> datas = EasyExcel.read(file).sheet(0).doReadSync(); + List> datas = EasyExcel.read(file).doReadAllSync(); for (Map data : datas) { LOGGER.info("数据:{}", JSON.toJSONString(data.get(0))); } diff --git a/src/test/resources/demo/demo.xlsx b/src/test/resources/demo/demo.xlsx index 48d3f87abd209ef857fe68ace222647bf9254ab7..662bb971758c6b080d73ef14103731501d635c7b 100644 GIT binary patch literal 10173 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 diff --git a/src/test/resources/extra/extra.xls b/src/test/resources/extra/extra.xls new file mode 100644 index 0000000000000000000000000000000000000000..89f389beda341657656eec9d513f776412f4a59d GIT binary patch literal 19968 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 3.4.0(jdk6) * 修复xls 用Map接收时多次接收会是同一个对象的bug * 修复浮点型数据导入到excel 会丢失精度的bug -* 新增支持接收批注 +* 新增支持读取批注、超链接、合并单元格 * 如果是`RuntimeException`则不再封装对象 +* 新增`CellData`可以获取行列号 # 2.1.4 From 71b9c53b6dd49605d2083e654a406a0cd473fed7 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Sun, 15 Mar 2020 17:48:54 +0800 Subject: [PATCH 20/38] =?UTF-8?q?*=20=E6=8F=90=E5=8D=87=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E7=AD=96=E7=95=A5=E6=95=88=E7=8E=87=20*=20=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E9=83=A8=E5=88=86=E6=AF=94=E8=BE=83=E7=89=B9=E6=AE=8A=E7=9A=84?= =?UTF-8?q?excel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v03/handlers/HyperlinkRecordHandler.java | 2 +- .../v03/handlers/MergeCellsRecordHandler.java | 2 +- .../analysis/v07/handlers/CellTagHandler.java | 9 +- .../v07/handlers/CountTagHandler.java | 5 +- .../analysis/v07/handlers/RowTagHandler.java | 2 +- .../v07/handlers/sax/XlsxRowHandler.java | 41 +++-- .../write/style/ContentFontStyle.java | 89 ++++++++++ .../write/style/ContentLoopMerge.java | 31 ++++ .../annotation/write/style/ContentStyle.java | 159 ++++++++++++++++++ .../annotation/write/style/HeadFontStyle.java | 89 ++++++++++ .../annotation/write/style/HeadStyle.java | 159 ++++++++++++++++++ .../write/style/OnceAbsoluteMerge.java | 45 +++++ .../excel/constant/ExcelXmlConstants.java | 43 +++-- .../com/alibaba/excel/metadata/CellExtra.java | 14 +- .../AbstractCellWriteHandler.java} | 30 +--- .../handler/AbstractRowWriteHandler.java | 31 ++++ .../handler/AbstractSheetWriteHandler.java | 21 +++ .../handler/AbstractWorkbookWriteHandler.java | 26 +++ .../excel/write/merge/LoopMergeStrategy.java | 52 +++--- .../merge/OnceAbsoluteMergeStrategy.java | 31 ++-- .../easyexcel/test/temp/Lock2Test.java | 50 ++++++ update.md | 4 + 22 files changed, 835 insertions(+), 100 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java create mode 100644 src/main/java/com/alibaba/excel/annotation/write/style/ContentLoopMerge.java create mode 100644 src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java create mode 100644 src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java create mode 100644 src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java create mode 100644 src/main/java/com/alibaba/excel/annotation/write/style/OnceAbsoluteMerge.java rename src/main/java/com/alibaba/excel/write/{merge/AbstractMergeStrategy.java => handler/AbstractCellWriteHandler.java} (58%) create mode 100644 src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java create mode 100644 src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java create mode 100644 src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java index 915abf6..99c3a80 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/HyperlinkRecordHandler.java @@ -23,7 +23,7 @@ public class HyperlinkRecordHandler extends AbstractXlsRecordHandler implements public void processRecord(XlsReadContext xlsReadContext, Record record) { HyperlinkRecord hr = (HyperlinkRecord)record; CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.HYPERLINK, hr.getAddress(), hr.getFirstRow(), - hr.getFirstColumn(), hr.getLastRow(), hr.getLastColumn()); + hr.getLastRow(), hr.getFirstColumn(), hr.getLastColumn()); xlsReadContext.xlsReadSheetHolder().setCellExtra(cellExtra); xlsReadContext.analysisEventProcessor().extra(xlsReadContext); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java index 4689f2b..f9bf472 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/MergeCellsRecordHandler.java @@ -27,7 +27,7 @@ public class MergeCellsRecordHandler extends AbstractXlsRecordHandler implements for (int i = 0; i < mcr.getNumAreas(); i++) { CellRangeAddress cellRangeAddress = mcr.getAreaAt(i); CellExtra cellExtra = new CellExtra(CellExtraTypeEnum.MERGE, null, cellRangeAddress.getFirstRow(), - cellRangeAddress.getFirstColumn(), cellRangeAddress.getLastRow(), cellRangeAddress.getLastColumn()); + cellRangeAddress.getLastRow(), cellRangeAddress.getFirstColumn(), cellRangeAddress.getLastColumn()); xlsReadContext.xlsReadSheetHolder().setCellExtra(cellExtra); xlsReadContext.analysisEventProcessor().extra(xlsReadContext); } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java index 8ef0786..7ba521d 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java @@ -1,8 +1,5 @@ package com.alibaba.excel.analysis.v07.handlers; -import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_DATA_FORMAT_TAG; -import static com.alibaba.excel.constant.ExcelXmlConstants.CELL_VALUE_TYPE_TAG; - import org.apache.poi.xssf.usermodel.XSSFCellStyle; import org.xml.sax.Attributes; @@ -24,7 +21,7 @@ public class CellTagHandler extends AbstractXlsxTagHandler { @Override public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); - xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.POSITION))); + xlsxReadSheetHolder.setColumnIndex(PositionUtils.getCol(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R))); // t="s" ,it's means String // t="str" ,it's means String,but does not need to be read in the 'sharedStrings.xml' @@ -33,12 +30,12 @@ public class CellTagHandler extends AbstractXlsxTagHandler { // t="e" ,it's means Error // t="n" ,it's means Number // t is null ,it's means Empty or Number - CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(CELL_VALUE_TYPE_TAG)); + CellDataTypeEnum type = CellDataTypeEnum.buildFromCellType(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_T)); xlsxReadSheetHolder.setTempCellData(new CellData(type)); xlsxReadSheetHolder.setTempData(new StringBuilder()); // Put in data transformation information - String dateFormatIndex = attributes.getValue(CELL_DATA_FORMAT_TAG); + String dateFormatIndex = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_S); if (dateFormatIndex != null) { int dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); XSSFCellStyle xssfCellStyle = diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java index c1eb323..823bafb 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CountTagHandler.java @@ -1,9 +1,8 @@ package com.alibaba.excel.analysis.v07.handlers; -import static com.alibaba.excel.constant.ExcelXmlConstants.DIMENSION_REF; - import org.xml.sax.Attributes; +import com.alibaba.excel.constant.ExcelXmlConstants; import com.alibaba.excel.context.xlsx.XlsxReadContext; /** @@ -15,7 +14,7 @@ public class CountTagHandler extends AbstractXlsxTagHandler { @Override public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { - String d = attributes.getValue(DIMENSION_REF); + String d = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_REF); String totalStr = d.substring(d.indexOf(":") + 1, d.length()); String c = totalStr.toUpperCase().replaceAll("[A-Z]", ""); xlsxReadContext.readSheetHolder().setApproximateTotalRowNumber(Integer.parseInt(c)); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java index 372a0a7..ee33266 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java @@ -21,7 +21,7 @@ public class RowTagHandler extends AbstractXlsxTagHandler { @Override public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { xlsxReadContext.readRowHolder( - new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.POSITION)), + new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R)), RowTypeEnum.DATA, xlsxReadContext.readSheetHolder().getGlobalConfiguration(), null)); } diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java index 0a4adb4..65eaa6a 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/sax/XlsxRowHandler.java @@ -24,18 +24,33 @@ import com.alibaba.excel.context.xlsx.XlsxReadContext; */ public class XlsxRowHandler extends DefaultHandler { private XlsxReadContext xlsxReadContext; - private static final Map XLSX_CELL_HANDLER_MAP = new HashMap(16); + private static final Map XLSX_CELL_HANDLER_MAP = new HashMap(32); static { - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_FORMULA_TAG, new CellFormulaTagHandler()); - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG, - new CellInlineStringValueTagHandler()); - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_TAG, new CellTagHandler()); - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_VALUE_TAG, new CellValueTagHandler()); - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.DIMENSION, new CountTagHandler()); - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.HYPERLINK_TAG, new HyperlinkTagHandler()); - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.MERGE_CELL_TAG, new MergeCellTagHandler()); - XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.ROW_TAG, new RowTagHandler()); + CellFormulaTagHandler cellFormulaTagHandler = new CellFormulaTagHandler(); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_FORMULA_TAG, cellFormulaTagHandler); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_FORMULA_TAG, cellFormulaTagHandler); + CellInlineStringValueTagHandler cellInlineStringValueTagHandler = new CellInlineStringValueTagHandler(); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_INLINE_STRING_VALUE_TAG, cellInlineStringValueTagHandler); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_INLINE_STRING_VALUE_TAG, cellInlineStringValueTagHandler); + CellTagHandler cellTagHandler = new CellTagHandler(); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_TAG, cellTagHandler); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_TAG, cellTagHandler); + CellValueTagHandler cellValueTagHandler = new CellValueTagHandler(); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.CELL_VALUE_TAG, cellValueTagHandler); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_CELL_VALUE_TAG, cellValueTagHandler); + CountTagHandler countTagHandler = new CountTagHandler(); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.DIMENSION_TAG, countTagHandler); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_DIMENSION_TAG, countTagHandler); + HyperlinkTagHandler hyperlinkTagHandler = new HyperlinkTagHandler(); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.HYPERLINK_TAG, hyperlinkTagHandler); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_HYPERLINK_TAG, hyperlinkTagHandler); + MergeCellTagHandler mergeCellTagHandler = new MergeCellTagHandler(); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.MERGE_CELL_TAG, mergeCellTagHandler); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_MERGE_CELL_TAG, mergeCellTagHandler); + RowTagHandler rowTagHandler = new RowTagHandler(); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.ROW_TAG, rowTagHandler); + XLSX_CELL_HANDLER_MAP.put(ExcelXmlConstants.X_ROW_TAG, rowTagHandler); } public XlsxRowHandler(XlsxReadContext xlsxReadContext) { @@ -45,7 +60,7 @@ public class XlsxRowHandler extends DefaultHandler { @Override public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(name); - if (handler == null) { + if (handler == null || !handler.support(xlsxReadContext)) { return; } xlsxReadContext.xlsxReadSheetHolder().getTagDeque().push(name); @@ -59,7 +74,7 @@ public class XlsxRowHandler extends DefaultHandler { return; } XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(currentTag); - if (handler == null) { + if (handler == null || !handler.support(xlsxReadContext)) { return; } handler.characters(xlsxReadContext, ch, start, length); @@ -68,7 +83,7 @@ public class XlsxRowHandler extends DefaultHandler { @Override public void endElement(String uri, String localName, String name) throws SAXException { XlsxTagHandler handler = XLSX_CELL_HANDLER_MAP.get(name); - if (handler == null) { + if (handler == null || !handler.support(xlsxReadContext)) { return; } handler.endElement(xlsxReadContext, name); diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java new file mode 100644 index 0000000..cb8d3c5 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java @@ -0,0 +1,89 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.poi.common.usermodel.fonts.FontCharset; +import org.apache.poi.hssf.usermodel.HSSFPalette; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; + +/** + * Custom content styles. + * + * @author Jiaju Zhuang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ContentFontStyle { + + /** + * The name for the font (i.e. Arial) + */ + String fontName(); + + /** + * Height in the familiar unit of measure - points + */ + short fontHeightInPoints() default -1; + + /** + * Whether to use italics or not + */ + boolean italic() default false; + + /** + * Whether to use a strikeout horizontal line through the text or not + */ + boolean strikeout() default false; + + /** + * The color for the font + * + * @see Font#COLOR_NORMAL + * @see Font#COLOR_RED + * @see HSSFPalette#getColor(short) + * @see IndexedColors + */ + short color() default -1; + + /** + * Set normal,super or subscript. + * + * @see Font#SS_NONE + * @see Font#SS_SUPER + * @see Font#SS_SUB + */ + short typeOffset() default -1; + + /** + * set type of text underlining to use + * + * @see Font#U_NONE + * @see Font#U_SINGLE + * @see Font#U_DOUBLE + * @see Font#U_SINGLE_ACCOUNTING + * @see Font#U_DOUBLE_ACCOUNTING + */ + + byte underline() default -1; + + /** + * Set character-set to use. + * + * @see FontCharset + * @see Font#ANSI_CHARSET + * @see Font#DEFAULT_CHARSET + * @see Font#SYMBOL_CHARSET + */ + int charset() default -1; + + /** + * Bold + */ + boolean bold() default false; +} diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentLoopMerge.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentLoopMerge.java new file mode 100644 index 0000000..af7bcec --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentLoopMerge.java @@ -0,0 +1,31 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * The regions of the loop merge + * + * @author Jiaju Zhuang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ContentLoopMerge { + /** + * Each row + * + * @return + */ + int eachRow() default -1; + + /** + * Extend column + * + * @return + */ + int columnExtend() default 1; +} diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java new file mode 100644 index 0000000..1cece9b --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java @@ -0,0 +1,159 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.BuiltinFormats; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IgnoredErrorType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; + +/** + * Custom content styles + * + * @author Jiaju Zhuang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface ContentStyle { + /** + * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}. + */ + short dataFormat(); + + /** + * Set the cell's using this style to be hidden + */ + boolean hidden(); + + /** + * Set the cell's using this style to be locked + */ + boolean locked(); + + /** + * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which + * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see + * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel + */ + boolean quotePrefix(); + + /** + * Set the type of horizontal alignment for the cell + */ + HorizontalAlignment horizontalAlignment(); + + /** + * Set whether the text should be wrapped. Setting this flag to true make all content visible within a + * cell by displaying it on multiple lines + * + */ + boolean wrapped(); + + /** + * Set the type of vertical alignment for the cell + */ + VerticalAlignment verticalAlignment(); + + /** + * Set the degree of rotation for the text in the cell. + * + * Note: HSSF uses values from -90 to 90 degrees, whereas XSSF uses values from 0 to 180 degrees. The + * implementations of this method will map between these two value-ranges accordingly, however the corresponding + * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is + * applied to. + */ + short rotation(); + + /** + * Set the number of spaces to indent the text in the cell + */ + short indent(); + + /** + * Set the type of border to use for the left border of the cell + */ + BorderStyle borderLeft(); + + /** + * Set the type of border to use for the right border of the cell + */ + BorderStyle borderRight(); + + /** + * Set the type of border to use for the top border of the cell + */ + BorderStyle borderTop(); + + /** + * Set the type of border to use for the bottom border of the cell + */ + BorderStyle borderBottom(); + + /** + * Set the color to use for the left border + * + * @see IndexedColors + */ + short leftBorderColor(); + + /** + * Set the color to use for the right border + * + * @see IndexedColors + * + */ + short rightBorderColor(); + + /** + * Set the color to use for the top border + * + * @see IndexedColors + * + */ + short topBorderColor(); + + /** + * Set the color to use for the bottom border + * + * @see IndexedColors + * + */ + short bottomBorderColor(); + + /** + * Setting to one fills the cell with the foreground color... No idea about other values + * + * @see FillPatternType#SOLID_FOREGROUND + */ + FillPatternType fillPatternType(); + + /** + * Set the background fill color. + * + * @see IndexedColors + * + */ + short fillBackgroundColor(); + + /** + * Set the foreground fill color Note: Ensure Foreground color is set prior to background color. + * + * @see IndexedColors + * + */ + short fillForegroundColor(); + + /** + * Controls if the Cell should be auto-sized to shrink to fit if the text is too long + */ + boolean shrinkToFit(); + +} diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java new file mode 100644 index 0000000..907a44b --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java @@ -0,0 +1,89 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.poi.common.usermodel.fonts.FontCharset; +import org.apache.poi.hssf.usermodel.HSSFPalette; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; + +/** + * Custom header styles. + * + * @author Jiaju Zhuang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface HeadFontStyle { + + /** + * The name for the font (i.e. Arial) + */ + String fontName(); + + /** + * Height in the familiar unit of measure - points + */ + short fontHeightInPoints() default -1; + + /** + * Whether to use italics or not + */ + boolean italic() default false; + + /** + * Whether to use a strikeout horizontal line through the text or not + */ + boolean strikeout() default false; + + /** + * The color for the font + * + * @see Font#COLOR_NORMAL + * @see Font#COLOR_RED + * @see HSSFPalette#getColor(short) + * @see IndexedColors + */ + short color() default -1; + + /** + * Set normal,super or subscript. + * + * @see Font#SS_NONE + * @see Font#SS_SUPER + * @see Font#SS_SUB + */ + short typeOffset() default -1; + + /** + * set type of text underlining to use + * + * @see Font#U_NONE + * @see Font#U_SINGLE + * @see Font#U_DOUBLE + * @see Font#U_SINGLE_ACCOUNTING + * @see Font#U_DOUBLE_ACCOUNTING + */ + + byte underline() default -1; + + /** + * Set character-set to use. + * + * @see FontCharset + * @see Font#ANSI_CHARSET + * @see Font#DEFAULT_CHARSET + * @see Font#SYMBOL_CHARSET + */ + int charset() default -1; + + /** + * Bold + */ + boolean bold() default false; +} diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java new file mode 100644 index 0000000..10252a7 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java @@ -0,0 +1,159 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.BuiltinFormats; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IgnoredErrorType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; + +/** + * Custom header styles + * + * @author Jiaju Zhuang + */ +@Target({ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface HeadStyle { + /** + * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}. + */ + short dataFormat() default -1; + + /** + * Set the cell's using this style to be hidden + */ + boolean hidden() default false; + + /** + * Set the cell's using this style to be locked + */ + boolean locked() default false; + + /** + * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which + * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see + * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel + */ + boolean quotePrefix() default false; + + /** + * Set the type of horizontal alignment for the cell + */ + HorizontalAlignment horizontalAlignment(); + + /** + * Set whether the text should be wrapped. Setting this flag to true make all content visible within a + * cell by displaying it on multiple lines + * + */ + boolean wrapped() default false; + + /** + * Set the type of vertical alignment for the cell + */ + VerticalAlignment verticalAlignment(); + + /** + * Set the degree of rotation for the text in the cell. + * + * Note: HSSF uses values from -90 to 90 degrees, whereas XSSF uses values from 0 to 180 degrees. The + * implementations of this method will map between these two value-ranges accordingly, however the corresponding + * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is + * applied to. + */ + short rotation() default -1; + + /** + * Set the number of spaces to indent the text in the cell + */ + short indent() default -1; + + /** + * Set the type of border to use for the left border of the cell + */ + BorderStyle borderLeft(); + + /** + * Set the type of border to use for the right border of the cell + */ + BorderStyle borderRight(); + + /** + * Set the type of border to use for the top border of the cell + */ + BorderStyle borderTop(); + + /** + * Set the type of border to use for the bottom border of the cell + */ + BorderStyle borderBottom(); + + /** + * Set the color to use for the left border + * + * @see IndexedColors + */ + short leftBorderColor() default -1; + + /** + * Set the color to use for the right border + * + * @see IndexedColors + * + */ + short rightBorderColor() default -1; + + /** + * Set the color to use for the top border + * + * @see IndexedColors + * + */ + short topBorderColor() default -1; + + /** + * Set the color to use for the bottom border + * + * @see IndexedColors + * + */ + short bottomBorderColor() default -1; + + /** + * Setting to one fills the cell with the foreground color... No idea about other values + * + * @see FillPatternType#SOLID_FOREGROUND + */ + FillPatternType fillPatternType(); + + /** + * Set the background fill color. + * + * @see IndexedColors + * + */ + short fillBackgroundColor() default -1; + + /** + * Set the foreground fill color Note: Ensure Foreground color is set prior to background color. + * + * @see IndexedColors + * + */ + short fillForegroundColor() default -1; + + /** + * Controls if the Cell should be auto-sized to shrink to fit if the text is too long + */ + boolean shrinkToFit() default false; + +} diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/OnceAbsoluteMerge.java b/src/main/java/com/alibaba/excel/annotation/write/style/OnceAbsoluteMerge.java new file mode 100644 index 0000000..6c3a148 --- /dev/null +++ b/src/main/java/com/alibaba/excel/annotation/write/style/OnceAbsoluteMerge.java @@ -0,0 +1,45 @@ +package com.alibaba.excel.annotation.write.style; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Inherited; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Merge the cells once + * + * @author Jiaju Zhuang + */ +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface OnceAbsoluteMerge { + /** + * First row + * + * @return + */ + int firstRowIndex() default -1; + + /** + * Last row + * + * @return + */ + int lastRowIndex() default -1; + + /** + * First column + * + * @return + */ + int firstColumnIndex() default -1; + + /** + * Last row + * + * @return + */ + int lastColumnIndex() default -1; +} diff --git a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java index 5cb6662..38c2005 100644 --- a/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java +++ b/src/main/java/com/alibaba/excel/constant/ExcelXmlConstants.java @@ -4,37 +4,54 @@ package com.alibaba.excel.constant; * @author jipengfei */ public class ExcelXmlConstants { - public static final String DIMENSION = "dimension"; - public static final String DIMENSION_REF = "ref"; - public static final String POSITION = "r"; - + public static final String DIMENSION_TAG = "dimension"; public static final String ROW_TAG = "row"; - public static final String CELL_TAG = "c"; - public static final String CELL_VALUE_TYPE_TAG = "t"; - /** - * Number formatted label - */ - public static final String CELL_DATA_FORMAT_TAG = "s"; public static final String CELL_FORMULA_TAG = "f"; public static final String CELL_VALUE_TAG = "v"; /** * When the data is "inlineStr" his tag is "t" */ public static final String CELL_INLINE_STRING_VALUE_TAG = "t"; - + public static final String CELL_TAG = "c"; public static final String MERGE_CELL_TAG = "mergeCell"; public static final String HYPERLINK_TAG = "hyperlink"; + public static final String X_DIMENSION_TAG = "x:dimension"; + public static final String X_ROW_TAG = "x:row"; + public static final String X_CELL_FORMULA_TAG = "x:f"; + public static final String X_CELL_VALUE_TAG = "x:v"; /** - * Cell range split + * When the data is "inlineStr" his tag is "t" */ - public static final String CELL_RANGE_SPLIT = ":"; + public static final String X_CELL_INLINE_STRING_VALUE_TAG = "x:t"; + public static final String X_CELL_TAG = "x:c"; + public static final String X_MERGE_CELL_TAG = "x:mergeCell"; + public static final String X_HYPERLINK_TAG = "x:hyperlink"; + + /** + * s attribute + */ + public static final String ATTRIBUTE_S = "s"; /** * ref attribute */ public static final String ATTRIBUTE_REF = "ref"; + /** + * r attribute + */ + public static final String ATTRIBUTE_R = "r"; + /** + * t attribute + */ + public static final String ATTRIBUTE_T = "t"; /** * location attribute */ public static final String ATTRIBUTE_LOCATION = "location"; + + /** + * Cell range split + */ + public static final String CELL_RANGE_SPLIT = ":"; + } diff --git a/src/main/java/com/alibaba/excel/metadata/CellExtra.java b/src/main/java/com/alibaba/excel/metadata/CellExtra.java index 3a9c2b3..937b9ac 100644 --- a/src/main/java/com/alibaba/excel/metadata/CellExtra.java +++ b/src/main/java/com/alibaba/excel/metadata/CellExtra.java @@ -23,14 +23,14 @@ public class CellExtra extends AbstractCell { * First row index,if this object is an interval */ private Integer firstRowIndex; - /** - * First column index,if this object is an interval - */ - private Integer firstColumnIndex; /** * Last row index,if this object is an interval */ private Integer lastRowIndex; + /** + * First column index,if this object is an interval + */ + private Integer firstColumnIndex; /** * Last column index,if this object is an interval */ @@ -55,11 +55,11 @@ public class CellExtra extends AbstractCell { } public CellExtra(CellExtraTypeEnum type, String text, Integer rowIndex, Integer columnIndex) { - this(type, text, rowIndex, columnIndex, rowIndex, columnIndex); + this(type, text, rowIndex, rowIndex, columnIndex, columnIndex); } - public CellExtra(CellExtraTypeEnum type, String text, Integer firstRowIndex, Integer firstColumnIndex, - Integer lastRowIndex, Integer lastColumnIndex) { + public CellExtra(CellExtraTypeEnum type, String text, Integer firstRowIndex, Integer lastRowIndex, + Integer firstColumnIndex, Integer lastColumnIndex) { super(); setRowIndex(firstRowIndex); setColumnIndex(firstColumnIndex); diff --git a/src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java similarity index 58% rename from src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java rename to src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java index b661c12..3f42046 100644 --- a/src/main/java/com/alibaba/excel/write/merge/AbstractMergeStrategy.java +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java @@ -1,23 +1,22 @@ -package com.alibaba.excel.write.merge; +package com.alibaba.excel.write.handler; import java.util.List; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.Row; -import org.apache.poi.ss.usermodel.Sheet; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; -import com.alibaba.excel.write.handler.CellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; /** - * Merge strategy + * Abstract cell write handler * * @author Jiaju Zhuang - */ -public abstract class AbstractMergeStrategy implements CellWriteHandler { + **/ +public abstract class AbstractCellWriteHandler implements CellWriteHandler { + @Override public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { @@ -26,24 +25,13 @@ public abstract class AbstractMergeStrategy implements CellWriteHandler { @Override public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, - Head head, Integer relativeRowIndex, Boolean isHead) {} + Head head, Integer relativeRowIndex, Boolean isHead) { + + } @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { - if (isHead) { - return; - } - merge(writeSheetHolder.getSheet(), cell, head, relativeRowIndex); - } - /** - * merge - * - * @param sheet - * @param cell - * @param head - * @param relativeRowIndex - */ - protected abstract void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex); + } } diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java new file mode 100644 index 0000000..d1e8c3a --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractRowWriteHandler.java @@ -0,0 +1,31 @@ +package com.alibaba.excel.write.handler; + +import org.apache.poi.ss.usermodel.Row; + +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; + +/** + * Abstract row write handler + * + * @author Jiaju Zhuang + **/ +public abstract class AbstractRowWriteHandler implements RowWriteHandler { + @Override + public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer rowIndex, + Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) { + + } + + @Override + public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) { + + } +} diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java new file mode 100644 index 0000000..76f4c84 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractSheetWriteHandler.java @@ -0,0 +1,21 @@ +package com.alibaba.excel.write.handler; + +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +/** + * Abstract sheet write handler + * + * @author Jiaju Zhuang + **/ +public abstract class AbstractSheetWriteHandler implements SheetWriteHandler { + @Override + public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + + } + + @Override + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + + } +} diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java new file mode 100644 index 0000000..baad392 --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractWorkbookWriteHandler.java @@ -0,0 +1,26 @@ +package com.alibaba.excel.write.handler; + +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; + +/** + * Abstract workbook write handler + * + * @author Jiaju Zhuang + **/ +public abstract class AbstractWorkbookWriteHandler implements WorkbookWriteHandler { + + @Override + public void beforeWorkbookCreate() { + + } + + @Override + public void afterWorkbookCreate(WriteWorkbookHolder writeWorkbookHolder) { + + } + + @Override + public void afterWorkbookDispose(WriteWorkbookHolder writeWorkbookHolder) { + + } +} diff --git a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java index 615e408..9c9ece1 100644 --- a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java +++ b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java @@ -1,58 +1,64 @@ package com.alibaba.excel.write.merge; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Sheet; +import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.util.CellRangeAddress; -import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.AbstractRowWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteTableHolder; /** * The regions of the loop merge * * @author Jiaju Zhuang */ -public class LoopMergeStrategy extends AbstractMergeStrategy { +public class LoopMergeStrategy extends AbstractRowWriteHandler { + /** + * Each row + */ private int eachRow; - private int columnCount; + /** + * Extend column + */ + private int columnExtend; + /** + * The number of the current column + */ private int columnIndex; public LoopMergeStrategy(int eachRow, int columnIndex) { this(eachRow, 1, columnIndex); } - public LoopMergeStrategy(int eachRow, int columnCount, int columnIndex) { + public LoopMergeStrategy(int eachRow, int columnExtend, int columnIndex) { if (eachRow < 1) { throw new IllegalArgumentException("EachRows must be greater than 1"); } - if (columnCount < 1) { - throw new IllegalArgumentException("ColumnCount must be greater than 1"); + if (columnExtend < 1) { + throw new IllegalArgumentException("ColumnExtend must be greater than 1"); } - if (columnCount == 1 && eachRow == 1) { - throw new IllegalArgumentException("ColumnCount or eachRows must be greater than 1"); + if (columnExtend == 1 && eachRow == 1) { + throw new IllegalArgumentException("ColumnExtend or eachRows must be greater than 1"); } if (columnIndex < 0) { throw new IllegalArgumentException("ColumnIndex must be greater than 0"); } this.eachRow = eachRow; - this.columnCount = columnCount; + this.columnExtend = columnExtend; this.columnIndex = columnIndex; } @Override - protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { - if (relativeRowIndex == null) { + public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, + Integer relativeRowIndex, Boolean isHead) { + if (isHead) { return; } - Integer currentColumnIndex; - if (head != null) { - currentColumnIndex = head.getColumnIndex(); - } else { - currentColumnIndex = cell.getColumnIndex(); - } - if (currentColumnIndex == columnIndex && relativeRowIndex % eachRow == 0) { - CellRangeAddress cellRangeAddress = new CellRangeAddress(cell.getRowIndex(), - cell.getRowIndex() + eachRow - 1, cell.getColumnIndex(), cell.getColumnIndex() + columnCount - 1); - sheet.addMergedRegionUnsafe(cellRangeAddress); + if (relativeRowIndex % eachRow == 0) { + CellRangeAddress cellRangeAddress = new CellRangeAddress(row.getRowNum(), row.getRowNum() + eachRow - 1, + columnIndex, columnIndex + columnExtend - 1); + writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress); } } + } diff --git a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java index be05e22..71002ef 100644 --- a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java +++ b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java @@ -1,21 +1,32 @@ package com.alibaba.excel.write.merge; -import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.util.CellRangeAddress; -import com.alibaba.excel.metadata.Head; +import com.alibaba.excel.write.handler.AbstractSheetWriteHandler; +import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; +import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; /** * It only merges once when create cell(firstRowIndex,lastRowIndex) * * @author Jiaju Zhuang */ -public class OnceAbsoluteMergeStrategy extends AbstractMergeStrategy { - +public class OnceAbsoluteMergeStrategy extends AbstractSheetWriteHandler { + /** + * First row + */ private int firstRowIndex; + /** + * Last row + */ private int lastRowIndex; + /** + * First column + */ private int firstColumnIndex; + /** + * Last row + */ private int lastColumnIndex; public OnceAbsoluteMergeStrategy(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) { @@ -29,11 +40,9 @@ public class OnceAbsoluteMergeStrategy extends AbstractMergeStrategy { } @Override - protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) { - if (cell.getRowIndex() == firstRowIndex && cell.getColumnIndex() == firstColumnIndex) { - CellRangeAddress cellRangeAddress = - new CellRangeAddress(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex); - sheet.addMergedRegionUnsafe(cellRangeAddress); - } + public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { + CellRangeAddress cellRangeAddress = + new CellRangeAddress(firstRowIndex, lastRowIndex, firstColumnIndex, lastColumnIndex); + writeSheetHolder.getSheet().addMergedRegionUnsafe(cellRangeAddress); } } diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java index 30325d1..6c9bd8d 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/Lock2Test.java @@ -1,15 +1,24 @@ package com.alibaba.easyexcel.test.temp; import java.io.File; +import java.util.ArrayList; +import java.util.Date; import java.util.List; import org.apache.poi.hssf.util.CellReference; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.IndexedColors; import org.junit.Ignore; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.alibaba.easyexcel.test.demo.write.DemoData; +import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.write.metadata.style.WriteCellStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; +import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.alibaba.fastjson.JSON; /** @@ -32,6 +41,47 @@ public class Lock2Test { } } + @Test + public void write() throws Exception { + String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; + // 头的策略 + WriteCellStyle headWriteCellStyle = new WriteCellStyle(); + // 背景设置为红色 + headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex()); + WriteFont headWriteFont = new WriteFont(); + headWriteFont.setFontHeightInPoints((short)20); + headWriteCellStyle.setWriteFont(headWriteFont); + // 内容的策略 + WriteCellStyle contentWriteCellStyle = new WriteCellStyle(); + // 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定 + contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND); + // 背景绿色 + contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex()); + WriteFont contentWriteFont = new WriteFont(); + // 字体大小 + contentWriteFont.setFontHeightInPoints((short)20); + contentWriteCellStyle.setWriteFont(contentWriteFont); + // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现 + HorizontalCellStyleStrategy horizontalCellStyleStrategy = + new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle); + + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板") + .doWrite(data()); + } + + private List data() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + DemoData data = new DemoData(); + data.setString("字符串" + i); + data.setDate(new Date()); + data.setDoubleData(0.56); + list.add(data); + } + return list; + } + @Test public void testc() throws Exception { LOGGER.info("reslut:{}", JSON.toJSONString(new CellReference("B3"))); diff --git a/update.md b/update.md index 5cdab9b..2078a59 100644 --- a/update.md +++ b/update.md @@ -7,6 +7,10 @@ * 新增支持读取批注、超链接、合并单元格 * 如果是`RuntimeException`则不再封装对象 * 新增`CellData`可以获取行列号 +* 新增样式注解 +* 新增合并单元格注解 +* 提升合并策略效率 +* 兼容部分比较特殊的excel # 2.1.4 From 754c5d8dcab379e994cb2ddaf3c2624cf6a97350 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Sun, 15 Mar 2020 21:09:24 +0800 Subject: [PATCH 21/38] =?UTF-8?q?=E5=90=8C=E6=97=B6=E4=BC=A0=E5=85=A5?= =?UTF-8?q?=E4=BA=86`List>`=E5=92=8C`class`=E7=9A=84head,?= =?UTF-8?q?=E4=BC=9A=E9=80=9A=E8=BF=87index=E5=8E=BB=E5=8C=B9=E9=85=8D?= =?UTF-8?q?=E6=B3=A8=E8=A7=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../write/style/ContentFontStyle.java | 4 +- .../annotation/write/style/ContentStyle.java | 44 +- .../annotation/write/style/HeadFontStyle.java | 8 +- .../annotation/write/style/HeadStyle.java | 20 +- .../converters/DefaultConverterLoader.java | 101 ++--- .../java/com/alibaba/excel/metadata/Head.java | 63 +++ .../metadata/property/ExcelHeadProperty.java | 20 +- .../excel/metadata/property/FontProperty.java | 180 +++++++++ .../metadata/property/LoopMergeProperty.java | 47 +++ .../property/OnceAbsoluteMergeProperty.java | 74 ++++ .../metadata/property/StyleProperty.java | 377 ++++++++++++++++++ .../alibaba/excel/util/WriteHandlerUtils.java | 15 + .../executor/AbstractExcelWriteExecutor.java | 5 +- .../write/executor/ExcelWriteAddExecutor.java | 8 +- .../executor/ExcelWriteFillExecutor.java | 2 +- .../handler/AbstractCellWriteHandler.java | 6 + .../excel/write/handler/CellWriteHandler.java | 19 + .../excel/write/merge/LoopMergeStrategy.java | 5 + .../merge/OnceAbsoluteMergeStrategy.java | 6 + .../metadata/holder/AbstractWriteHolder.java | 57 ++- .../write/metadata/style/WriteCellStyle.java | 77 ++++ .../property/ExcelWriteHeadProperty.java | 51 +++ .../style/AbstractCellStyleStrategy.java | 6 + .../AbstractColumnWidthStyleStrategy.java | 20 +- .../demo/read/DemoCellCommentsListener.java | 77 ---- .../test/demo/read/DemoExtraData.java | 14 + .../test/demo/read/DemoExtraListener.java | 58 +++ .../easyexcel/test/demo/read/ReadTest.java | 23 +- .../demo/write/CustomCellWriteHandler.java | 17 +- .../test/demo/write/DemoMergeData.java | 27 ++ .../test/demo/write/DemoStyleData.java | 44 ++ .../easyexcel/test/demo/write/WriteTest.java | 60 ++- src/test/resources/demo/extra.xlsx | Bin 0 -> 12045 bytes update.md | 4 +- 34 files changed, 1315 insertions(+), 224 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/metadata/property/FontProperty.java create mode 100644 src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java create mode 100644 src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java create mode 100644 src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java delete mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraData.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/write/DemoMergeData.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/demo/write/DemoStyleData.java create mode 100644 src/test/resources/demo/extra.xlsx diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java index cb8d3c5..d593aef 100644 --- a/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java +++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentFontStyle.java @@ -16,7 +16,7 @@ import org.apache.poi.ss.usermodel.IndexedColors; * * @author Jiaju Zhuang */ -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ContentFontStyle { @@ -24,7 +24,7 @@ public @interface ContentFontStyle { /** * The name for the font (i.e. Arial) */ - String fontName(); + String fontName() default ""; /** * Height in the familiar unit of measure - points diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java index 1cece9b..9ef3f47 100644 --- a/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java +++ b/src/main/java/com/alibaba/excel/annotation/write/style/ContentStyle.java @@ -19,48 +19,48 @@ import org.apache.poi.ss.usermodel.VerticalAlignment; * * @author Jiaju Zhuang */ -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface ContentStyle { /** * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}. */ - short dataFormat(); + short dataFormat() default -1; /** * Set the cell's using this style to be hidden */ - boolean hidden(); + boolean hidden() default false; /** * Set the cell's using this style to be locked */ - boolean locked(); + boolean locked() default false; /** * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel */ - boolean quotePrefix(); + boolean quotePrefix() default false; /** * Set the type of horizontal alignment for the cell */ - HorizontalAlignment horizontalAlignment(); + HorizontalAlignment horizontalAlignment() default HorizontalAlignment.GENERAL; /** * Set whether the text should be wrapped. Setting this flag to true make all content visible within a * cell by displaying it on multiple lines * */ - boolean wrapped(); + boolean wrapped() default false; /** * Set the type of vertical alignment for the cell */ - VerticalAlignment verticalAlignment(); + VerticalAlignment verticalAlignment() default VerticalAlignment.CENTER; /** * Set the degree of rotation for the text in the cell. @@ -70,39 +70,39 @@ public @interface ContentStyle { * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is * applied to. */ - short rotation(); + short rotation() default -1; /** * Set the number of spaces to indent the text in the cell */ - short indent(); + short indent() default -1; /** * Set the type of border to use for the left border of the cell */ - BorderStyle borderLeft(); + BorderStyle borderLeft() default BorderStyle.NONE; /** * Set the type of border to use for the right border of the cell */ - BorderStyle borderRight(); + BorderStyle borderRight() default BorderStyle.NONE; /** * Set the type of border to use for the top border of the cell */ - BorderStyle borderTop(); + BorderStyle borderTop() default BorderStyle.NONE; /** * Set the type of border to use for the bottom border of the cell */ - BorderStyle borderBottom(); + BorderStyle borderBottom() default BorderStyle.NONE; /** * Set the color to use for the left border * * @see IndexedColors */ - short leftBorderColor(); + short leftBorderColor() default -1; /** * Set the color to use for the right border @@ -110,7 +110,7 @@ public @interface ContentStyle { * @see IndexedColors * */ - short rightBorderColor(); + short rightBorderColor() default -1; /** * Set the color to use for the top border @@ -118,7 +118,7 @@ public @interface ContentStyle { * @see IndexedColors * */ - short topBorderColor(); + short topBorderColor() default -1; /** * Set the color to use for the bottom border @@ -126,14 +126,14 @@ public @interface ContentStyle { * @see IndexedColors * */ - short bottomBorderColor(); + short bottomBorderColor() default -1; /** * Setting to one fills the cell with the foreground color... No idea about other values * * @see FillPatternType#SOLID_FOREGROUND */ - FillPatternType fillPatternType(); + FillPatternType fillPatternType() default FillPatternType.NO_FILL; /** * Set the background fill color. @@ -141,7 +141,7 @@ public @interface ContentStyle { * @see IndexedColors * */ - short fillBackgroundColor(); + short fillBackgroundColor() default -1; /** * Set the foreground fill color Note: Ensure Foreground color is set prior to background color. @@ -149,11 +149,11 @@ public @interface ContentStyle { * @see IndexedColors * */ - short fillForegroundColor(); + short fillForegroundColor() default -1; /** * Controls if the Cell should be auto-sized to shrink to fit if the text is too long */ - boolean shrinkToFit(); + boolean shrinkToFit() default false; } diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java index 907a44b..957e50f 100644 --- a/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java +++ b/src/main/java/com/alibaba/excel/annotation/write/style/HeadFontStyle.java @@ -16,7 +16,7 @@ import org.apache.poi.ss.usermodel.IndexedColors; * * @author Jiaju Zhuang */ -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface HeadFontStyle { @@ -24,12 +24,12 @@ public @interface HeadFontStyle { /** * The name for the font (i.e. Arial) */ - String fontName(); + String fontName() default "宋体"; /** * Height in the familiar unit of measure - points */ - short fontHeightInPoints() default -1; + short fontHeightInPoints() default 14; /** * Whether to use italics or not @@ -85,5 +85,5 @@ public @interface HeadFontStyle { /** * Bold */ - boolean bold() default false; + boolean bold() default true; } diff --git a/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java b/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java index 10252a7..d882da8 100644 --- a/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java +++ b/src/main/java/com/alibaba/excel/annotation/write/style/HeadStyle.java @@ -19,7 +19,7 @@ import org.apache.poi.ss.usermodel.VerticalAlignment; * * @author Jiaju Zhuang */ -@Target({ElementType.FIELD}) +@Target({ElementType.FIELD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface HeadStyle { @@ -36,7 +36,7 @@ public @interface HeadStyle { /** * Set the cell's using this style to be locked */ - boolean locked() default false; + boolean locked() default true; /** * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which @@ -48,19 +48,19 @@ public @interface HeadStyle { /** * Set the type of horizontal alignment for the cell */ - HorizontalAlignment horizontalAlignment(); + HorizontalAlignment horizontalAlignment() default HorizontalAlignment.CENTER; /** * Set whether the text should be wrapped. Setting this flag to true make all content visible within a * cell by displaying it on multiple lines * */ - boolean wrapped() default false; + boolean wrapped() default true; /** * Set the type of vertical alignment for the cell */ - VerticalAlignment verticalAlignment(); + VerticalAlignment verticalAlignment() default VerticalAlignment.CENTER; /** * Set the degree of rotation for the text in the cell. @@ -80,22 +80,22 @@ public @interface HeadStyle { /** * Set the type of border to use for the left border of the cell */ - BorderStyle borderLeft(); + BorderStyle borderLeft() default BorderStyle.THIN; /** * Set the type of border to use for the right border of the cell */ - BorderStyle borderRight(); + BorderStyle borderRight() default BorderStyle.THIN; /** * Set the type of border to use for the top border of the cell */ - BorderStyle borderTop(); + BorderStyle borderTop() default BorderStyle.THIN; /** * Set the type of border to use for the bottom border of the cell */ - BorderStyle borderBottom(); + BorderStyle borderBottom() default BorderStyle.THIN; /** * Set the color to use for the left border @@ -133,7 +133,7 @@ public @interface HeadStyle { * * @see FillPatternType#SOLID_FOREGROUND */ - FillPatternType fillPatternType(); + FillPatternType fillPatternType() default FillPatternType.SOLID_FOREGROUND; /** * Set the background fill color. diff --git a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java index 77e8b59..0182255 100644 --- a/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java +++ b/src/main/java/com/alibaba/excel/converters/DefaultConverterLoader.java @@ -48,56 +48,12 @@ public class DefaultConverterLoader { private static Map defaultWriteConverter; private static Map allConverter; - /** - * Load default write converter - * - * @return - */ - public static Map loadDefaultWriteConverter() { - if (defaultWriteConverter != null) { - return defaultWriteConverter; - } - defaultWriteConverter = new HashMap(32); - putWriteConverter(new BigDecimalNumberConverter()); - putWriteConverter(new BooleanBooleanConverter()); - putWriteConverter(new ByteNumberConverter()); - putWriteConverter(new DateStringConverter()); - putWriteConverter(new DoubleNumberConverter()); - putWriteConverter(new FloatNumberConverter()); - putWriteConverter(new IntegerNumberConverter()); - putWriteConverter(new LongNumberConverter()); - putWriteConverter(new ShortNumberConverter()); - putWriteConverter(new StringStringConverter()); - putWriteConverter(new FileImageConverter()); - putWriteConverter(new InputStreamImageConverter()); - putWriteConverter(new ByteArrayImageConverter()); - putWriteConverter(new BoxingByteArrayImageConverter()); - putWriteConverter(new UrlImageConverter()); - return defaultWriteConverter; + static { + initDefaultWriteConverter(); + initAllConverter(); } - private static void putWriteConverter(Converter converter) { - defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); - } - - /** - * Load default read converter - * - * @return - */ - public static Map loadDefaultReadConverter() { - return loadAllConverter(); - } - - /** - * Load all converter - * - * @return - */ - public static Map loadAllConverter() { - if (allConverter != null) { - return allConverter; - } + private static void initAllConverter() { allConverter = new HashMap(64); putAllConverter(new BigDecimalBooleanConverter()); putAllConverter(new BigDecimalNumberConverter()); @@ -138,6 +94,55 @@ public class DefaultConverterLoader { putAllConverter(new StringNumberConverter()); putAllConverter(new StringStringConverter()); putAllConverter(new StringErrorConverter()); + } + + private static void initDefaultWriteConverter() { + defaultWriteConverter = new HashMap(32); + putWriteConverter(new BigDecimalNumberConverter()); + putWriteConverter(new BooleanBooleanConverter()); + putWriteConverter(new ByteNumberConverter()); + putWriteConverter(new DateStringConverter()); + putWriteConverter(new DoubleNumberConverter()); + putWriteConverter(new FloatNumberConverter()); + putWriteConverter(new IntegerNumberConverter()); + putWriteConverter(new LongNumberConverter()); + putWriteConverter(new ShortNumberConverter()); + putWriteConverter(new StringStringConverter()); + putWriteConverter(new FileImageConverter()); + putWriteConverter(new InputStreamImageConverter()); + putWriteConverter(new ByteArrayImageConverter()); + putWriteConverter(new BoxingByteArrayImageConverter()); + putWriteConverter(new UrlImageConverter()); + } + + /** + * Load default write converter + * + * @return + */ + public static Map loadDefaultWriteConverter() { + return defaultWriteConverter; + } + + private static void putWriteConverter(Converter converter) { + defaultWriteConverter.put(ConverterKeyBuild.buildKey(converter.supportJavaTypeKey()), converter); + } + + /** + * Load default read converter + * + * @return + */ + public static Map loadDefaultReadConverter() { + return loadAllConverter(); + } + + /** + * Load all converter + * + * @return + */ + public static Map loadAllConverter() { return allConverter; } diff --git a/src/main/java/com/alibaba/excel/metadata/Head.java b/src/main/java/com/alibaba/excel/metadata/Head.java index c1cea10..c578cbb 100644 --- a/src/main/java/com/alibaba/excel/metadata/Head.java +++ b/src/main/java/com/alibaba/excel/metadata/Head.java @@ -4,6 +4,9 @@ import java.util.ArrayList; import java.util.List; import com.alibaba.excel.metadata.property.ColumnWidthProperty; +import com.alibaba.excel.metadata.property.FontProperty; +import com.alibaba.excel.metadata.property.LoopMergeProperty; +import com.alibaba.excel.metadata.property.StyleProperty; /** * excel head @@ -35,6 +38,26 @@ public class Head { * column with */ private ColumnWidthProperty columnWidthProperty; + /** + * Loop merge + */ + private LoopMergeProperty loopMergeProperty; + /** + * Head style + */ + private StyleProperty headStyleProperty; + /** + * Content style + */ + private StyleProperty contentStyleProperty; + /** + * Head font + */ + private FontProperty headFontProperty; + /** + * Content font + */ + private FontProperty contentFontProperty; public Head(Integer columnIndex, String fieldName, List headNameList, Boolean forceIndex, Boolean forceName) { @@ -95,4 +118,44 @@ public class Head { public void setForceName(Boolean forceName) { this.forceName = forceName; } + + public LoopMergeProperty getLoopMergeProperty() { + return loopMergeProperty; + } + + public void setLoopMergeProperty(LoopMergeProperty loopMergeProperty) { + this.loopMergeProperty = loopMergeProperty; + } + + public StyleProperty getHeadStyleProperty() { + return headStyleProperty; + } + + public void setHeadStyleProperty(StyleProperty headStyleProperty) { + this.headStyleProperty = headStyleProperty; + } + + public StyleProperty getContentStyleProperty() { + return contentStyleProperty; + } + + public void setContentStyleProperty(StyleProperty contentStyleProperty) { + this.contentStyleProperty = contentStyleProperty; + } + + public FontProperty getHeadFontProperty() { + return headFontProperty; + } + + public void setHeadFontProperty(FontProperty headFontProperty) { + this.headFontProperty = headFontProperty; + } + + public FontProperty getContentFontProperty() { + return contentFontProperty; + } + + public void setContentFontProperty(FontProperty contentFontProperty) { + this.contentFontProperty = contentFontProperty; + } } diff --git a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java index 782f635..34109ad 100644 --- a/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java +++ b/src/main/java/com/alibaba/excel/metadata/property/ExcelHeadProperty.java @@ -1,7 +1,6 @@ package com.alibaba.excel.metadata.property; import java.lang.reflect.Field; -import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; @@ -12,8 +11,6 @@ import java.util.TreeMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.alibaba.excel.annotation.ExcelIgnore; -import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.NumberFormat; @@ -21,7 +18,6 @@ import com.alibaba.excel.converters.AutoConverter; import com.alibaba.excel.converters.Converter; import com.alibaba.excel.enums.HeadKindEnum; import com.alibaba.excel.exception.ExcelCommonException; -import com.alibaba.excel.exception.ExcelGenerateException; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.Holder; import com.alibaba.excel.util.ClassUtils; @@ -86,10 +82,10 @@ public class ExcelHeadProperty { headIndex++; } headKind = HeadKindEnum.STRING; - } else { - // convert headClazz to head - initColumnProperties(holder, convertAllFiled); } + // convert headClazz to head + initColumnProperties(holder, convertAllFiled); + initHeadRowNumber(); if (LOGGER.isDebugEnabled()) { LOGGER.debug("The initialization sheet/table 'ExcelHeadProperty' is complete , head kind is {}", headKind); @@ -163,10 +159,14 @@ public class ExcelHeadProperty { List tmpHeadList = new ArrayList(); boolean notForceName = excelProperty == null || excelProperty.value().length <= 0 || (excelProperty.value().length == 1 && StringUtils.isEmpty((excelProperty.value())[0])); - if (notForceName) { - tmpHeadList.add(field.getName()); + if (headMap.containsKey(index)) { + tmpHeadList.addAll(headMap.get(index).getHeadNameList()); } else { - Collections.addAll(tmpHeadList, excelProperty.value()); + if (notForceName) { + tmpHeadList.add(field.getName()); + } else { + Collections.addAll(tmpHeadList, excelProperty.value()); + } } Head head = new Head(index, field.getName(), tmpHeadList, forceIndex, !notForceName); ExcelContentProperty excelContentProperty = new ExcelContentProperty(); diff --git a/src/main/java/com/alibaba/excel/metadata/property/FontProperty.java b/src/main/java/com/alibaba/excel/metadata/property/FontProperty.java new file mode 100644 index 0000000..04caf9b --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/FontProperty.java @@ -0,0 +1,180 @@ +package com.alibaba.excel.metadata.property; + +import org.apache.poi.common.usermodel.fonts.FontCharset; +import org.apache.poi.hssf.usermodel.HSSFPalette; +import org.apache.poi.ss.usermodel.Font; +import org.apache.poi.ss.usermodel.IndexedColors; + +import com.alibaba.excel.annotation.write.style.ContentFontStyle; +import com.alibaba.excel.annotation.write.style.HeadFontStyle; + +/** + * Configuration from annotations + * + * @author Jiaju Zhuang + */ +public class FontProperty { + /** + * The name for the font (i.e. Arial) + */ + private String fontName; + /** + * Height in the familiar unit of measure - points + */ + private Short fontHeightInPoints; + /** + * Whether to use italics or not + */ + private Boolean italic; + /** + * Whether to use a strikeout horizontal line through the text or not + */ + private Boolean strikeout; + /** + * The color for the font + * + * @see Font#COLOR_NORMAL + * @see Font#COLOR_RED + * @see HSSFPalette#getColor(short) + * @see IndexedColors + */ + private Short color; + /** + * Set normal,super or subscript. + * + * @see Font#SS_NONE + * @see Font#SS_SUPER + * @see Font#SS_SUB + */ + private Short typeOffset; + /** + * set type of text underlining to use + * + * @see Font#U_NONE + * @see Font#U_SINGLE + * @see Font#U_DOUBLE + * @see Font#U_SINGLE_ACCOUNTING + * @see Font#U_DOUBLE_ACCOUNTING + */ + + private Byte underline; + /** + * Set character-set to use. + * + * @see FontCharset + * @see Font#ANSI_CHARSET + * @see Font#DEFAULT_CHARSET + * @see Font#SYMBOL_CHARSET + */ + private Integer charset; + /** + * Bold + */ + private Boolean bold; + + public static FontProperty build(HeadFontStyle headFontStyle) { + if (headFontStyle == null) { + return null; + } + FontProperty styleProperty = new FontProperty(); + styleProperty.setFontName(headFontStyle.fontName()); + styleProperty.setFontHeightInPoints(headFontStyle.fontHeightInPoints()); + styleProperty.setItalic(headFontStyle.italic()); + styleProperty.setStrikeout(headFontStyle.strikeout()); + styleProperty.setColor(headFontStyle.color()); + styleProperty.setTypeOffset(headFontStyle.typeOffset()); + styleProperty.setUnderline(headFontStyle.underline()); + styleProperty.setCharset(headFontStyle.charset()); + styleProperty.setBold(headFontStyle.bold()); + return styleProperty; + } + + public static FontProperty build(ContentFontStyle contentFontStyle) { + if (contentFontStyle == null) { + return null; + } + FontProperty styleProperty = new FontProperty(); + styleProperty.setFontName(contentFontStyle.fontName()); + styleProperty.setFontHeightInPoints(contentFontStyle.fontHeightInPoints()); + styleProperty.setItalic(contentFontStyle.italic()); + styleProperty.setStrikeout(contentFontStyle.strikeout()); + styleProperty.setColor(contentFontStyle.color()); + styleProperty.setTypeOffset(contentFontStyle.typeOffset()); + styleProperty.setUnderline(contentFontStyle.underline()); + styleProperty.setCharset(contentFontStyle.charset()); + styleProperty.setBold(contentFontStyle.bold()); + return styleProperty; + } + + public String getFontName() { + return fontName; + } + + public void setFontName(String fontName) { + this.fontName = fontName; + } + + public Short getFontHeightInPoints() { + return fontHeightInPoints; + } + + public void setFontHeightInPoints(Short fontHeightInPoints) { + this.fontHeightInPoints = fontHeightInPoints; + } + + public Boolean getItalic() { + return italic; + } + + public void setItalic(Boolean italic) { + this.italic = italic; + } + + public Boolean getStrikeout() { + return strikeout; + } + + public void setStrikeout(Boolean strikeout) { + this.strikeout = strikeout; + } + + public Short getColor() { + return color; + } + + public void setColor(Short color) { + this.color = color; + } + + public Short getTypeOffset() { + return typeOffset; + } + + public void setTypeOffset(Short typeOffset) { + this.typeOffset = typeOffset; + } + + public Byte getUnderline() { + return underline; + } + + public void setUnderline(Byte underline) { + this.underline = underline; + } + + public Integer getCharset() { + return charset; + } + + public void setCharset(Integer charset) { + this.charset = charset; + } + + public Boolean getBold() { + return bold; + } + + public void setBold(Boolean bold) { + this.bold = bold; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java b/src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java new file mode 100644 index 0000000..05084bf --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/LoopMergeProperty.java @@ -0,0 +1,47 @@ +package com.alibaba.excel.metadata.property; + +import com.alibaba.excel.annotation.write.style.ContentLoopMerge; + +/** + * Configuration from annotations + * + * @author Jiaju Zhuang + */ +public class LoopMergeProperty { + /** + * Each row + */ + private int eachRow; + /** + * Extend column + */ + private int columnExtend; + + public LoopMergeProperty(int eachRow, int columnExtend) { + this.eachRow = eachRow; + this.columnExtend = columnExtend; + } + + public static LoopMergeProperty build(ContentLoopMerge contentLoopMerge) { + if (contentLoopMerge == null) { + return null; + } + return new LoopMergeProperty(contentLoopMerge.eachRow(), contentLoopMerge.columnExtend()); + } + + public int getEachRow() { + return eachRow; + } + + public void setEachRow(int eachRow) { + this.eachRow = eachRow; + } + + public int getColumnExtend() { + return columnExtend; + } + + public void setColumnExtend(int columnExtend) { + this.columnExtend = columnExtend; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java b/src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java new file mode 100644 index 0000000..c509219 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/OnceAbsoluteMergeProperty.java @@ -0,0 +1,74 @@ +package com.alibaba.excel.metadata.property; + +import com.alibaba.excel.annotation.write.style.OnceAbsoluteMerge; + +/** + * Configuration from annotations + * + * @author Jiaju Zhuang + */ +public class OnceAbsoluteMergeProperty { + /** + * First row + */ + private int firstRowIndex; + /** + * Last row + */ + private int lastRowIndex; + /** + * First column + */ + private int firstColumnIndex; + /** + * Last row + */ + private int lastColumnIndex; + + public OnceAbsoluteMergeProperty(int firstRowIndex, int lastRowIndex, int firstColumnIndex, int lastColumnIndex) { + this.firstRowIndex = firstRowIndex; + this.lastRowIndex = lastRowIndex; + this.firstColumnIndex = firstColumnIndex; + this.lastColumnIndex = lastColumnIndex; + } + + public static OnceAbsoluteMergeProperty build(OnceAbsoluteMerge onceAbsoluteMerge) { + if (onceAbsoluteMerge == null) { + return null; + } + return new OnceAbsoluteMergeProperty(onceAbsoluteMerge.firstRowIndex(), onceAbsoluteMerge.lastRowIndex(), + onceAbsoluteMerge.firstColumnIndex(), onceAbsoluteMerge.lastColumnIndex()); + } + + public int getFirstRowIndex() { + return firstRowIndex; + } + + public void setFirstRowIndex(int firstRowIndex) { + this.firstRowIndex = firstRowIndex; + } + + public int getLastRowIndex() { + return lastRowIndex; + } + + public void setLastRowIndex(int lastRowIndex) { + this.lastRowIndex = lastRowIndex; + } + + public int getFirstColumnIndex() { + return firstColumnIndex; + } + + public void setFirstColumnIndex(int firstColumnIndex) { + this.firstColumnIndex = firstColumnIndex; + } + + public int getLastColumnIndex() { + return lastColumnIndex; + } + + public void setLastColumnIndex(int lastColumnIndex) { + this.lastColumnIndex = lastColumnIndex; + } +} diff --git a/src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java b/src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java new file mode 100644 index 0000000..9222b10 --- /dev/null +++ b/src/main/java/com/alibaba/excel/metadata/property/StyleProperty.java @@ -0,0 +1,377 @@ +package com.alibaba.excel.metadata.property; + +import org.apache.poi.ss.usermodel.BorderStyle; +import org.apache.poi.ss.usermodel.BuiltinFormats; +import org.apache.poi.ss.usermodel.FillPatternType; +import org.apache.poi.ss.usermodel.HorizontalAlignment; +import org.apache.poi.ss.usermodel.IgnoredErrorType; +import org.apache.poi.ss.usermodel.IndexedColors; +import org.apache.poi.ss.usermodel.VerticalAlignment; + +import com.alibaba.excel.annotation.write.style.ContentStyle; +import com.alibaba.excel.annotation.write.style.HeadStyle; +import com.alibaba.excel.write.metadata.style.WriteFont; + +/** + * Configuration from annotations + * + * @author Jiaju Zhuang + */ +public class StyleProperty { + /** + * Set the data format (must be a valid format). Built in formats are defined at {@link BuiltinFormats}. + */ + private Short dataFormat; + /** + * Set the font for this style + */ + private WriteFont writeFont; + /** + * Set the cell's using this style to be hidden + */ + private Boolean hidden; + + /** + * Set the cell's using this style to be locked + */ + private Boolean locked; + /** + * Turn on or off "Quote Prefix" or "123 Prefix" for the style, which is used to tell Excel that the thing which + * looks like a number or a formula shouldn't be treated as on. Turning this on is somewhat (but not completely, see + * {@link IgnoredErrorType}) like prefixing the cell value with a ' in Excel + */ + private Boolean quotePrefix; + /** + * Set the type of horizontal alignment for the cell + */ + private HorizontalAlignment horizontalAlignment; + /** + * Set whether the text should be wrapped. Setting this flag to true make all content visible within a + * cell by displaying it on multiple lines + * + */ + private Boolean wrapped; + /** + * Set the type of vertical alignment for the cell + */ + private VerticalAlignment verticalAlignment; + /** + * Set the degree of rotation for the text in the cell. + * + * Note: HSSF uses values from -90 to 90 degrees, whereas XSSF uses values from 0 to 180 degrees. The + * implementations of this method will map between these two value-ranges accordingly, however the corresponding + * getter is returning values in the range mandated by the current type of Excel file-format that this CellStyle is + * applied to. + */ + private Short rotation; + /** + * Set the number of spaces to indent the text in the cell + */ + private Short indent; + /** + * Set the type of border to use for the left border of the cell + */ + private BorderStyle borderLeft; + /** + * Set the type of border to use for the right border of the cell + */ + private BorderStyle borderRight; + /** + * Set the type of border to use for the top border of the cell + */ + private BorderStyle borderTop; + + /** + * Set the type of border to use for the bottom border of the cell + */ + private BorderStyle borderBottom; + /** + * Set the color to use for the left border + * + * @see IndexedColors + */ + private Short leftBorderColor; + + /** + * Set the color to use for the right border + * + * @see IndexedColors + * + */ + private Short rightBorderColor; + + /** + * Set the color to use for the top border + * + * @see IndexedColors + * + */ + private Short topBorderColor; + /** + * Set the color to use for the bottom border + * + * @see IndexedColors + * + */ + private Short bottomBorderColor; + /** + * Setting to one fills the cell with the foreground color... No idea about other values + * + * @see FillPatternType#SOLID_FOREGROUND + */ + private FillPatternType fillPatternType; + + /** + * Set the background fill color. + * + * @see IndexedColors + * + */ + private Short fillBackgroundColor; + + /** + * Set the foreground fill color Note: Ensure Foreground color is set prior to background color. + * + * @see IndexedColors + * + */ + private Short fillForegroundColor; + /** + * Controls if the Cell should be auto-sized to shrink to fit if the text is too long + */ + private Boolean shrinkToFit; + + public static StyleProperty build(HeadStyle headStyle) { + if (headStyle == null) { + return null; + } + StyleProperty styleProperty = new StyleProperty(); + styleProperty.setDataFormat(headStyle.dataFormat()); + styleProperty.setHidden(headStyle.hidden()); + styleProperty.setLocked(headStyle.locked()); + styleProperty.setQuotePrefix(headStyle.quotePrefix()); + styleProperty.setHorizontalAlignment(headStyle.horizontalAlignment()); + styleProperty.setWrapped(headStyle.wrapped()); + styleProperty.setVerticalAlignment(headStyle.verticalAlignment()); + styleProperty.setRotation(headStyle.rotation()); + styleProperty.setIndent(headStyle.indent()); + styleProperty.setBorderLeft(headStyle.borderLeft()); + styleProperty.setBorderRight(headStyle.borderRight()); + styleProperty.setBorderTop(headStyle.borderTop()); + styleProperty.setBorderBottom(headStyle.borderBottom()); + styleProperty.setLeftBorderColor(headStyle.leftBorderColor()); + styleProperty.setRightBorderColor(headStyle.rightBorderColor()); + styleProperty.setTopBorderColor(headStyle.topBorderColor()); + styleProperty.setBottomBorderColor(headStyle.bottomBorderColor()); + styleProperty.setFillPatternType(headStyle.fillPatternType()); + styleProperty.setFillBackgroundColor(headStyle.fillBackgroundColor()); + styleProperty.setFillForegroundColor(headStyle.fillForegroundColor()); + styleProperty.setShrinkToFit(headStyle.shrinkToFit()); + return styleProperty; + } + + public static StyleProperty build(ContentStyle contentStyle) { + if (contentStyle == null) { + return null; + } + StyleProperty styleProperty = new StyleProperty(); + styleProperty.setDataFormat(contentStyle.dataFormat()); + styleProperty.setHidden(contentStyle.hidden()); + styleProperty.setLocked(contentStyle.locked()); + styleProperty.setQuotePrefix(contentStyle.quotePrefix()); + styleProperty.setHorizontalAlignment(contentStyle.horizontalAlignment()); + styleProperty.setWrapped(contentStyle.wrapped()); + styleProperty.setVerticalAlignment(contentStyle.verticalAlignment()); + styleProperty.setRotation(contentStyle.rotation()); + styleProperty.setIndent(contentStyle.indent()); + styleProperty.setBorderLeft(contentStyle.borderLeft()); + styleProperty.setBorderRight(contentStyle.borderRight()); + styleProperty.setBorderTop(contentStyle.borderTop()); + styleProperty.setBorderBottom(contentStyle.borderBottom()); + styleProperty.setLeftBorderColor(contentStyle.leftBorderColor()); + styleProperty.setRightBorderColor(contentStyle.rightBorderColor()); + styleProperty.setTopBorderColor(contentStyle.topBorderColor()); + styleProperty.setBottomBorderColor(contentStyle.bottomBorderColor()); + styleProperty.setFillPatternType(contentStyle.fillPatternType()); + styleProperty.setFillBackgroundColor(contentStyle.fillBackgroundColor()); + styleProperty.setFillForegroundColor(contentStyle.fillForegroundColor()); + styleProperty.setShrinkToFit(contentStyle.shrinkToFit()); + return styleProperty; + } + + public Short getDataFormat() { + return dataFormat; + } + + public void setDataFormat(Short dataFormat) { + this.dataFormat = dataFormat; + } + + public WriteFont getWriteFont() { + return writeFont; + } + + public void setWriteFont(WriteFont writeFont) { + this.writeFont = writeFont; + } + + public Boolean getHidden() { + return hidden; + } + + public void setHidden(Boolean hidden) { + this.hidden = hidden; + } + + public Boolean getLocked() { + return locked; + } + + public void setLocked(Boolean locked) { + this.locked = locked; + } + + public Boolean getQuotePrefix() { + return quotePrefix; + } + + public void setQuotePrefix(Boolean quotePrefix) { + this.quotePrefix = quotePrefix; + } + + public HorizontalAlignment getHorizontalAlignment() { + return horizontalAlignment; + } + + public void setHorizontalAlignment(HorizontalAlignment horizontalAlignment) { + this.horizontalAlignment = horizontalAlignment; + } + + public Boolean getWrapped() { + return wrapped; + } + + public void setWrapped(Boolean wrapped) { + this.wrapped = wrapped; + } + + public VerticalAlignment getVerticalAlignment() { + return verticalAlignment; + } + + public void setVerticalAlignment(VerticalAlignment verticalAlignment) { + this.verticalAlignment = verticalAlignment; + } + + public Short getRotation() { + return rotation; + } + + public void setRotation(Short rotation) { + this.rotation = rotation; + } + + public Short getIndent() { + return indent; + } + + public void setIndent(Short indent) { + this.indent = indent; + } + + public BorderStyle getBorderLeft() { + return borderLeft; + } + + public void setBorderLeft(BorderStyle borderLeft) { + this.borderLeft = borderLeft; + } + + public BorderStyle getBorderRight() { + return borderRight; + } + + public void setBorderRight(BorderStyle borderRight) { + this.borderRight = borderRight; + } + + public BorderStyle getBorderTop() { + return borderTop; + } + + public void setBorderTop(BorderStyle borderTop) { + this.borderTop = borderTop; + } + + public BorderStyle getBorderBottom() { + return borderBottom; + } + + public void setBorderBottom(BorderStyle borderBottom) { + this.borderBottom = borderBottom; + } + + public Short getLeftBorderColor() { + return leftBorderColor; + } + + public void setLeftBorderColor(Short leftBorderColor) { + this.leftBorderColor = leftBorderColor; + } + + public Short getRightBorderColor() { + return rightBorderColor; + } + + public void setRightBorderColor(Short rightBorderColor) { + this.rightBorderColor = rightBorderColor; + } + + public Short getTopBorderColor() { + return topBorderColor; + } + + public void setTopBorderColor(Short topBorderColor) { + this.topBorderColor = topBorderColor; + } + + public Short getBottomBorderColor() { + return bottomBorderColor; + } + + public void setBottomBorderColor(Short bottomBorderColor) { + this.bottomBorderColor = bottomBorderColor; + } + + public FillPatternType getFillPatternType() { + return fillPatternType; + } + + public void setFillPatternType(FillPatternType fillPatternType) { + this.fillPatternType = fillPatternType; + } + + public Short getFillBackgroundColor() { + return fillBackgroundColor; + } + + public void setFillBackgroundColor(Short fillBackgroundColor) { + this.fillBackgroundColor = fillBackgroundColor; + } + + public Short getFillForegroundColor() { + return fillForegroundColor; + } + + public void setFillForegroundColor(Short fillForegroundColor) { + this.fillForegroundColor = fillForegroundColor; + } + + public Boolean getShrinkToFit() { + return shrinkToFit; + } + + public void setShrinkToFit(Boolean shrinkToFit) { + this.shrinkToFit = shrinkToFit; + } +} diff --git a/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java b/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java index b303a31..06dcc72 100644 --- a/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java +++ b/src/main/java/com/alibaba/excel/util/WriteHandlerUtils.java @@ -123,6 +123,21 @@ public class WriteHandlerUtils { } } + public static void afterCellDataConverted(WriteContext writeContext, CellData cellData, Cell cell, Head head, + Integer relativeRowIndex, Boolean isHead) { + List handlerList = + writeContext.currentWriteHolder().writeHandlerMap().get(CellWriteHandler.class); + if (handlerList == null || handlerList.isEmpty()) { + return; + } + for (WriteHandler writeHandler : handlerList) { + if (writeHandler instanceof CellWriteHandler) { + ((CellWriteHandler)writeHandler).afterCellDataConverted(writeContext.writeSheetHolder(), + writeContext.writeTableHolder(), cellData, cell, head, relativeRowIndex, isHead); + } + } + } + public static void afterCellDispose(WriteContext writeContext, CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { List cellDataList = new ArrayList(); diff --git a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java index 1f09d47..4eb115c 100644 --- a/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/AbstractExcelWriteExecutor.java @@ -13,7 +13,9 @@ import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.exception.ExcelDataConvertException; import com.alibaba.excel.metadata.CellData; +import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.property.ExcelContentProperty; +import com.alibaba.excel.util.WriteHandlerUtils; import com.alibaba.excel.write.metadata.holder.WriteHolder; /** @@ -29,7 +31,7 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { } protected CellData converterAndSet(WriteHolder currentWriteHolder, Class clazz, Cell cell, Object value, - ExcelContentProperty excelContentProperty) { + ExcelContentProperty excelContentProperty, Head head, Integer relativeRowIndex) { if (value == null) { return new CellData(CellDataTypeEnum.EMPTY); } @@ -43,6 +45,7 @@ public abstract class AbstractExcelWriteExecutor implements ExcelWriteExecutor { if (cellData.getType() == null) { cellData.setType(CellDataTypeEnum.EMPTY); } + WriteHandlerUtils.afterCellDataConverted(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); switch (cellData.getType()) { case STRING: cell.setCellValue(cellData.getStringValue()); diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java index 5b0d8ae..66878c5 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java @@ -105,7 +105,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE); Object value = oneRowData.get(dataIndex); CellData cellData = converterAndSet(writeContext.currentWriteHolder(), value == null ? null : value.getClass(), - cell, value, null); + cell, value, null, head, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); } @@ -135,7 +135,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { WriteHandlerUtils.afterCellCreate(writeContext, cell, head, relativeRowIndex, Boolean.FALSE); Object value = beanMap.get(name); CellData cellData = converterAndSet(currentWriteHolder, excelContentProperty.getField().getType(), cell, - value, excelContentProperty); + value, excelContentProperty, head, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, head, relativeRowIndex, Boolean.FALSE); beanMapHandledSet.add(name); } @@ -160,8 +160,8 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { WriteHandlerUtils.beforeCellCreate(writeContext, row, null, cellIndex, relativeRowIndex, Boolean.FALSE); Cell cell = WorkBookUtil.createCell(row, cellIndex++); WriteHandlerUtils.afterCellCreate(writeContext, cell, null, relativeRowIndex, Boolean.FALSE); - CellData cellData = - converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), cell, value, null); + CellData cellData = converterAndSet(currentWriteHolder, value == null ? null : value.getClass(), cell, + value, null, null, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE); } } diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java index 495a134..75aa660 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java @@ -162,7 +162,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } Object value = dataMap.get(variable); CellData cellData = converterAndSet(writeSheetHolder, value == null ? null : value.getClass(), cell, - value, fieldNameContentPropertyMap.get(variable)); + value, fieldNameContentPropertyMap.get(variable), null, relativeRowIndex); WriteHandlerUtils.afterCellDispose(writeContext, cellData, cell, null, relativeRowIndex, Boolean.FALSE); } else { StringBuilder cellValueBuild = new StringBuilder(); diff --git a/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java index 3f42046..b649af7 100644 --- a/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/AbstractCellWriteHandler.java @@ -29,6 +29,12 @@ public abstract class AbstractCellWriteHandler implements CellWriteHandler { } + @Override + public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + } + @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { diff --git a/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java b/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java index 4d98138..8701d6a 100644 --- a/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java +++ b/src/main/java/com/alibaba/excel/write/handler/CellWriteHandler.java @@ -52,6 +52,25 @@ public interface CellWriteHandler extends WriteHandler { void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead); + /** + * Called after the cell data is converted + * + * @param writeSheetHolder + * @param writeTableHolder + * Nullable.It is null without using table writes. + * @param cell + * @param head + * Nullable.It is null in the case of fill data and without head. + * @param cellData + * Nullable.It is null in the case of add header. + * @param relativeRowIndex + * Nullable.It is null in the case of fill data. + * @param isHead + * It will always be false when fill data. + */ + void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, + Cell cell, Head head, Integer relativeRowIndex, Boolean isHead); + /** * Called after all operations on the cell have been completed * diff --git a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java index 9c9ece1..5796dde 100644 --- a/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java +++ b/src/main/java/com/alibaba/excel/write/merge/LoopMergeStrategy.java @@ -3,6 +3,7 @@ package com.alibaba.excel.write.merge; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.util.CellRangeAddress; +import com.alibaba.excel.metadata.property.LoopMergeProperty; import com.alibaba.excel.write.handler.AbstractRowWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -48,6 +49,10 @@ public class LoopMergeStrategy extends AbstractRowWriteHandler { this.columnIndex = columnIndex; } + public LoopMergeStrategy(LoopMergeProperty loopMergeProperty, Integer columnIndex) { + this(loopMergeProperty.getEachRow(), loopMergeProperty.getColumnExtend(), columnIndex); + } + @Override public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) { diff --git a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java index 71002ef..d85781e 100644 --- a/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java +++ b/src/main/java/com/alibaba/excel/write/merge/OnceAbsoluteMergeStrategy.java @@ -2,6 +2,7 @@ package com.alibaba.excel.write.merge; import org.apache.poi.ss.util.CellRangeAddress; +import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty; import com.alibaba.excel.write.handler.AbstractSheetWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder; @@ -39,6 +40,11 @@ public class OnceAbsoluteMergeStrategy extends AbstractSheetWriteHandler { this.lastColumnIndex = lastColumnIndex; } + public OnceAbsoluteMergeStrategy(OnceAbsoluteMergeProperty onceAbsoluteMergeProperty) { + this(onceAbsoluteMergeProperty.getFirstRowIndex(), onceAbsoluteMergeProperty.getLastRowIndex(), + onceAbsoluteMergeProperty.getFirstColumnIndex(), onceAbsoluteMergeProperty.getLastColumnIndex()); + } + @Override public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) { CellRangeAddress cellRangeAddress = diff --git a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java index 375602a..00f2ef7 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java +++ b/src/main/java/com/alibaba/excel/write/metadata/holder/AbstractWriteHolder.java @@ -22,6 +22,8 @@ import com.alibaba.excel.metadata.AbstractHolder; import com.alibaba.excel.metadata.Font; import com.alibaba.excel.metadata.Head; import com.alibaba.excel.metadata.TableStyle; +import com.alibaba.excel.metadata.property.LoopMergeProperty; +import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty; import com.alibaba.excel.metadata.property.RowHeightProperty; import com.alibaba.excel.util.CollectionUtils; import com.alibaba.excel.write.handler.CellWriteHandler; @@ -30,12 +32,15 @@ import com.alibaba.excel.write.handler.RowWriteHandler; import com.alibaba.excel.write.handler.SheetWriteHandler; import com.alibaba.excel.write.handler.WorkbookWriteHandler; import com.alibaba.excel.write.handler.WriteHandler; +import com.alibaba.excel.write.merge.LoopMergeStrategy; +import com.alibaba.excel.write.merge.OnceAbsoluteMergeStrategy; import com.alibaba.excel.write.metadata.WriteBasicParameter; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.WriteTable; import com.alibaba.excel.write.metadata.style.WriteCellStyle; import com.alibaba.excel.write.metadata.style.WriteFont; import com.alibaba.excel.write.property.ExcelWriteHeadProperty; +import com.alibaba.excel.write.style.AbstractVerticalCellStyleStrategy; import com.alibaba.excel.write.style.HorizontalCellStyleStrategy; import com.alibaba.excel.write.style.column.AbstractHeadColumnWidthStyleStrategy; import com.alibaba.excel.write.style.row.SimpleRowHeightStyleStrategy; @@ -279,19 +284,63 @@ public abstract class AbstractWriteHolder extends AbstractHolder implements Writ return; } Map headMap = getExcelWriteHeadProperty().getHeadMap(); - boolean hasColumnWidth = false; - for (Map.Entry entry : headMap.entrySet()) { - if (entry.getValue().getColumnWidthProperty() != null) { + boolean hasStyle = false; + + for (Head head : headMap.values()) { + if (head.getColumnWidthProperty() != null) { hasColumnWidth = true; - break; } + if (head.getHeadStyleProperty() != null || head.getHeadFontProperty() != null + || head.getContentStyleProperty() != null || head.getContentFontProperty() != null) { + hasStyle = true; + } + dealLoopMerge(handlerList, head); } if (hasColumnWidth) { dealColumnWidth(handlerList); } + + if (hasStyle) { + dealStyle(handlerList); + } + dealRowHigh(handlerList); + dealOnceAbsoluteMerge(handlerList); + + } + + private void dealStyle(List handlerList) { + WriteHandler styleStrategy = new AbstractVerticalCellStyleStrategy() { + @Override + protected WriteCellStyle headCellStyle(Head head) { + return WriteCellStyle.build(head.getHeadStyleProperty(), head.getHeadFontProperty()); + } + + @Override + protected WriteCellStyle contentCellStyle(Head head) { + return WriteCellStyle.build(head.getContentStyleProperty(), head.getContentFontProperty()); + } + }; + handlerList.add(styleStrategy); + } + + private void dealLoopMerge(List handlerList, Head head) { + LoopMergeProperty loopMergeProperty = head.getLoopMergeProperty(); + if (loopMergeProperty == null) { + return; + } + handlerList.add(new LoopMergeStrategy(loopMergeProperty, head.getColumnIndex())); + } + + private void dealOnceAbsoluteMerge(List handlerList) { + OnceAbsoluteMergeProperty onceAbsoluteMergeProperty = + getExcelWriteHeadProperty().getOnceAbsoluteMergeProperty(); + if (onceAbsoluteMergeProperty == null) { + return; + } + handlerList.add(new OnceAbsoluteMergeStrategy(onceAbsoluteMergeProperty)); } private void dealRowHigh(List handlerList) { diff --git a/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java b/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java index 01786ce..81c85e8 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java +++ b/src/main/java/com/alibaba/excel/write/metadata/style/WriteCellStyle.java @@ -8,6 +8,10 @@ import org.apache.poi.ss.usermodel.IgnoredErrorType; import org.apache.poi.ss.usermodel.IndexedColors; import org.apache.poi.ss.usermodel.VerticalAlignment; +import com.alibaba.excel.metadata.property.FontProperty; +import com.alibaba.excel.metadata.property.StyleProperty; +import com.alibaba.excel.util.StringUtils; + /** * Cell style when writing * @@ -137,6 +141,79 @@ public class WriteCellStyle { */ private Boolean shrinkToFit; + public static WriteCellStyle build(StyleProperty styleProperty, FontProperty fontProperty) { + if (styleProperty == null && fontProperty == null) { + return null; + } + WriteCellStyle writeCellStyle = new WriteCellStyle(); + if (styleProperty != null) { + if (styleProperty.getDataFormat() >= 0) { + writeCellStyle.setDataFormat(styleProperty.getDataFormat()); + } + writeCellStyle.setHidden(styleProperty.getHidden()); + writeCellStyle.setLocked(styleProperty.getLocked()); + writeCellStyle.setQuotePrefix(styleProperty.getQuotePrefix()); + writeCellStyle.setHorizontalAlignment(styleProperty.getHorizontalAlignment()); + writeCellStyle.setWrapped(styleProperty.getWrapped()); + writeCellStyle.setVerticalAlignment(styleProperty.getVerticalAlignment()); + if (styleProperty.getRotation() >= 0) { + writeCellStyle.setRotation(styleProperty.getRotation()); + } + if (styleProperty.getIndent() >= 0) { + writeCellStyle.setIndent(styleProperty.getIndent()); + } + writeCellStyle.setBorderLeft(styleProperty.getBorderLeft()); + writeCellStyle.setBorderRight(styleProperty.getBorderRight()); + writeCellStyle.setBorderTop(styleProperty.getBorderTop()); + writeCellStyle.setBorderBottom(styleProperty.getBorderBottom()); + if (styleProperty.getLeftBorderColor() >= 0) { + writeCellStyle.setLeftBorderColor(styleProperty.getLeftBorderColor()); + } + if (styleProperty.getRightBorderColor() >= 0) { + writeCellStyle.setRightBorderColor(styleProperty.getRightBorderColor()); + } + if (styleProperty.getTopBorderColor() >= 0) { + writeCellStyle.setTopBorderColor(styleProperty.getTopBorderColor()); + } + if (styleProperty.getBottomBorderColor() >= 0) { + writeCellStyle.setBottomBorderColor(styleProperty.getBottomBorderColor()); + } + writeCellStyle.setFillPatternType(styleProperty.getFillPatternType()); + if (styleProperty.getFillBackgroundColor() >= 0) { + writeCellStyle.setFillBackgroundColor(styleProperty.getFillBackgroundColor()); + } + if (styleProperty.getFillForegroundColor() >= 0) { + writeCellStyle.setFillForegroundColor(styleProperty.getFillForegroundColor()); + } + writeCellStyle.setShrinkToFit(styleProperty.getShrinkToFit()); + } + if (fontProperty != null) { + WriteFont writeFont = new WriteFont(); + writeCellStyle.setWriteFont(writeFont); + if (!StringUtils.isEmpty(fontProperty.getFontName())) { + writeFont.setFontName(fontProperty.getFontName()); + } + writeFont.setFontHeightInPoints(fontProperty.getFontHeightInPoints()); + writeFont.setItalic(fontProperty.getItalic()); + writeFont.setStrikeout(fontProperty.getStrikeout()); + if (fontProperty.getColor() >= 0) { + writeFont.setColor(fontProperty.getColor()); + } + if (fontProperty.getTypeOffset() >= 0) { + writeFont.setTypeOffset(fontProperty.getTypeOffset()); + } + if (fontProperty.getUnderline() >= 0) { + writeFont.setUnderline(fontProperty.getUnderline()); + } + if (fontProperty.getCharset() >= 0) { + writeFont.setCharset(fontProperty.getCharset()); + } + writeFont.setBold(fontProperty.getBold()); + } + + return writeCellStyle; + } + public Short getDataFormat() { return dataFormat; } diff --git a/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java b/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java index b1ba891..8fe0349 100644 --- a/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java +++ b/src/main/java/com/alibaba/excel/write/property/ExcelWriteHeadProperty.java @@ -9,8 +9,14 @@ import java.util.Set; import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.annotation.write.style.ColumnWidth; +import com.alibaba.excel.annotation.write.style.ContentFontStyle; +import com.alibaba.excel.annotation.write.style.ContentLoopMerge; import com.alibaba.excel.annotation.write.style.ContentRowHeight; +import com.alibaba.excel.annotation.write.style.ContentStyle; +import com.alibaba.excel.annotation.write.style.HeadFontStyle; import com.alibaba.excel.annotation.write.style.HeadRowHeight; +import com.alibaba.excel.annotation.write.style.HeadStyle; +import com.alibaba.excel.annotation.write.style.OnceAbsoluteMerge; import com.alibaba.excel.converters.ConverterKeyBuild; import com.alibaba.excel.converters.DefaultConverterLoader; import com.alibaba.excel.enums.CellDataTypeEnum; @@ -21,7 +27,11 @@ import com.alibaba.excel.metadata.Holder; import com.alibaba.excel.metadata.property.ColumnWidthProperty; import com.alibaba.excel.metadata.property.ExcelContentProperty; import com.alibaba.excel.metadata.property.ExcelHeadProperty; +import com.alibaba.excel.metadata.property.FontProperty; +import com.alibaba.excel.metadata.property.LoopMergeProperty; +import com.alibaba.excel.metadata.property.OnceAbsoluteMergeProperty; import com.alibaba.excel.metadata.property.RowHeightProperty; +import com.alibaba.excel.metadata.property.StyleProperty; /** * Define the header attribute of excel @@ -31,6 +41,7 @@ import com.alibaba.excel.metadata.property.RowHeightProperty; public class ExcelWriteHeadProperty extends ExcelHeadProperty { private RowHeightProperty headRowHeightProperty; private RowHeightProperty contentRowHeightProperty; + private OnceAbsoluteMergeProperty onceAbsoluteMergeProperty; public ExcelWriteHeadProperty(Holder holder, Class headClazz, List> head, Boolean convertAllFiled) { super(holder, headClazz, head, convertAllFiled); @@ -41,8 +52,15 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { RowHeightProperty.build((HeadRowHeight)headClazz.getAnnotation(HeadRowHeight.class)); this.contentRowHeightProperty = RowHeightProperty.build((ContentRowHeight)headClazz.getAnnotation(ContentRowHeight.class)); + this.onceAbsoluteMergeProperty = + OnceAbsoluteMergeProperty.build((OnceAbsoluteMerge)headClazz.getAnnotation(OnceAbsoluteMerge.class)); ColumnWidth parentColumnWidth = (ColumnWidth)headClazz.getAnnotation(ColumnWidth.class); + HeadStyle parentHeadStyle = (HeadStyle)headClazz.getAnnotation(HeadStyle.class); + HeadFontStyle parentHeadFontStyle = (HeadFontStyle)headClazz.getAnnotation(HeadFontStyle.class); + ContentStyle parentContentStyle = (ContentStyle)headClazz.getAnnotation(ContentStyle.class); + ContentFontStyle parentContentFontStyle = (ContentFontStyle)headClazz.getAnnotation(ContentFontStyle.class); + for (Map.Entry entry : getContentPropertyMap().entrySet()) { Integer index = entry.getKey(); ExcelContentProperty excelContentPropertyData = entry.getValue(); @@ -54,6 +72,31 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { } headData.setColumnWidthProperty(ColumnWidthProperty.build(columnWidth)); + HeadStyle headStyle = field.getAnnotation(HeadStyle.class); + if (headStyle == null) { + headStyle = parentHeadStyle; + } + headData.setHeadStyleProperty(StyleProperty.build(headStyle)); + + HeadFontStyle headFontStyle = field.getAnnotation(HeadFontStyle.class); + if (headFontStyle == null) { + headFontStyle = parentHeadFontStyle; + } + headData.setHeadFontProperty(FontProperty.build(headFontStyle)); + + ContentStyle contentStyle = field.getAnnotation(ContentStyle.class); + if (contentStyle == null) { + contentStyle = parentContentStyle; + } + headData.setContentStyleProperty(StyleProperty.build(contentStyle)); + + ContentFontStyle contentFontStyle = field.getAnnotation(ContentFontStyle.class); + if (contentFontStyle == null) { + contentFontStyle = parentContentFontStyle; + } + headData.setContentFontProperty(FontProperty.build(contentFontStyle)); + + headData.setLoopMergeProperty(LoopMergeProperty.build(field.getAnnotation(ContentLoopMerge.class))); // If have @NumberFormat, 'NumberStringConverter' is specified by default if (excelContentPropertyData.getConverter() == null) { NumberFormat numberFormat = field.getAnnotation(NumberFormat.class); @@ -81,6 +124,14 @@ public class ExcelWriteHeadProperty extends ExcelHeadProperty { this.contentRowHeightProperty = contentRowHeightProperty; } + public OnceAbsoluteMergeProperty getOnceAbsoluteMergeProperty() { + return onceAbsoluteMergeProperty; + } + + public void setOnceAbsoluteMergeProperty(OnceAbsoluteMergeProperty onceAbsoluteMergeProperty) { + this.onceAbsoluteMergeProperty = onceAbsoluteMergeProperty; + } + /** * Calculate all cells that need to be merged * diff --git a/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java index 7aafc44..4790ab1 100644 --- a/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/AbstractCellStyleStrategy.java @@ -40,6 +40,12 @@ public abstract class AbstractCellStyleStrategy implements CellWriteHandler, She } + @Override + public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + CellData cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + + } + @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { diff --git a/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java index 07afcfc..005f624 100644 --- a/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/column/AbstractColumnWidthStyleStrategy.java @@ -3,12 +3,11 @@ package com.alibaba.excel.write.style.column; import java.util.List; import org.apache.poi.ss.usermodel.Cell; -import org.apache.poi.ss.usermodel.Row; import com.alibaba.excel.event.NotRepeatExecutor; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; -import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.AbstractCellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -17,7 +16,7 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; * * @author Jiaju Zhuang */ -public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandler, NotRepeatExecutor { +public abstract class AbstractColumnWidthStyleStrategy extends AbstractCellWriteHandler implements NotRepeatExecutor { @Override public String uniqueValue() { @@ -25,15 +24,8 @@ public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandl } @Override - public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, - Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {} - - @Override - public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, - Head head, Integer relativeRowIndex, Boolean isHead) {} - - @Override - public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { + public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, + List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { setColumnWidth(writeSheetHolder, cellDataList, cell, head, relativeRowIndex, isHead); } @@ -47,7 +39,7 @@ public abstract class AbstractColumnWidthStyleStrategy implements CellWriteHandl * @param relativeRowIndex * @param isHead */ - protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, List cellDataList, Cell cell, Head head, - Integer relativeRowIndex, Boolean isHead); + protected abstract void setColumnWidth(WriteSheetHolder writeSheetHolder, List cellDataList, Cell cell, + Head head, Integer relativeRowIndex, Boolean isHead); } diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java deleted file mode 100644 index e7d8def..0000000 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoCellCommentsListener.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.alibaba.easyexcel.test.demo.read; - -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import com.alibaba.excel.context.AnalysisContext; -import com.alibaba.excel.event.AnalysisEventListener; -import com.alibaba.excel.exception.ExcelDataConvertException; -import com.alibaba.fastjson.JSON; - -/** - * 读取单元格的批注 - * - * @author: kaiux - * @date: 2019-10-23 14:10 - **/ -public class DemoCellCommentsListener extends AnalysisEventListener { - private static final Logger LOGGER = LoggerFactory.getLogger(DemoCellCommentsListener.class); - /** - * 每隔5条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 - */ - private static final int BATCH_COUNT = 5; - List list = new ArrayList(); - - /** - * 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。 - * - * @param exception - * @param context - * @throws Exception - */ - @Override - public void onException(Exception exception, AnalysisContext context) { - LOGGER.error("解析失败,但是继续解析下一行:{}", exception.getMessage()); - if (exception instanceof ExcelDataConvertException) { - ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception; - LOGGER.error("第{}行,第{}列解析异常", excelDataConvertException.getRowIndex(), - excelDataConvertException.getColumnIndex()); - } - } - - /** - * 这里会一行行的返回头 - * - * @param headMap - * @param context - */ - @Override - public void invokeHeadMap(Map headMap, AnalysisContext context) {} - - @Override - public void invoke(DemoData data, AnalysisContext context) { - LOGGER.info("解析到一条数据:{}", JSON.toJSONString(data)); - if (list.size() >= BATCH_COUNT) { - saveData(); - list.clear(); - } - } - - @Override - public void doAfterAllAnalysed(AnalysisContext context) { - saveData(); - LOGGER.info("所有数据解析完成!"); - } - - /** - * 加上存储数据库 - */ - private void saveData() { - LOGGER.info("{}条数据,开始存储数据库!", list.size()); - LOGGER.info("存储数据库成功!"); - } -} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraData.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraData.java new file mode 100644 index 0000000..e780bfa --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraData.java @@ -0,0 +1,14 @@ +package com.alibaba.easyexcel.test.demo.read; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +public class DemoExtraData { + + private String row1; + + private String row2; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java new file mode 100644 index 0000000..01adfe7 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/DemoExtraListener.java @@ -0,0 +1,58 @@ +package com.alibaba.easyexcel.test.demo.read; + +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.alibaba.excel.context.AnalysisContext; +import com.alibaba.excel.event.AnalysisEventListener; +import com.alibaba.excel.metadata.CellExtra; +import com.alibaba.fastjson.JSON; + +/** + * 读取单元格的批注 + * + * @author: kaiux + * @date: 2019-10-23 14:10 + **/ +public class DemoExtraListener extends AnalysisEventListener { + private static final Logger LOGGER = LoggerFactory.getLogger(DemoDataListener.class); + + @Override + public void invoke(DemoExtraData data, AnalysisContext context) {} + + @Override + public void doAfterAllAnalysed(AnalysisContext context) {} + + @Override + public void extra(CellExtra extra, AnalysisContext context) { + LOGGER.info("读取到了一条额外信息:{}", JSON.toJSONString(extra)); + switch (extra.getType()) { + case COMMENT: + LOGGER.info("额外信息是批注,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), extra.getColumnIndex(), + extra.getText()); + break; + case HYPERLINK: + if ("Sheet1!A1".equals(extra.getText())) { + LOGGER.info("额外信息是超链接,在rowIndex:{},columnIndex;{},内容是:{}", extra.getRowIndex(), + extra.getColumnIndex(), extra.getText()); + } else if ("Sheet2!A1".equals(extra.getText())) { + LOGGER.info( + "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}," + + "内容是:{}", + extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(), + extra.getLastColumnIndex(), extra.getText()); + } else { + Assert.fail("Unknown hyperlink!"); + } + break; + case MERGE: + LOGGER.info( + "额外信息是超链接,而且覆盖了一个区间,在firstRowIndex:{},firstColumnIndex;{},lastRowIndex:{},lastColumnIndex:{}", + extra.getFirstRowIndex(), extra.getFirstColumnIndex(), extra.getLastRowIndex(), + extra.getLastColumnIndex()); + break; + default: + } + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java index cd45f2e..5234f05 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java @@ -16,6 +16,7 @@ import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.format.DateTimeFormat; import com.alibaba.excel.annotation.format.NumberFormat; import com.alibaba.excel.converters.DefaultConverterLoader; +import com.alibaba.excel.enums.CellExtraTypeEnum; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.fastjson.JSON; @@ -162,20 +163,28 @@ public class ReadTest { } /** - * 读取单元格批注 + * 额外信息(批注、超链接、合并单元格信息读取) + *

+ * 由于是流式读取,没法在读取到单元格数据的时候直接读取到额外信息,所以只能最后通知哪些单元格有哪些额外信息 * *

- * 1. 创建excel对应的实体对象 参照{@link DemoData} + * 1. 创建excel对应的实体对象 参照{@link DemoExtraData} *

- * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} + * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExtraListener} *

* 3. 直接读即可 */ @Test - public void commentsRead() { - String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx"; + public void extraRead() { + String fileName = TestFileUtil.getPath() + "demo" + File.separator + "extra.xlsx"; // 这里 需要指定读用哪个class去读,然后读取第一个sheet - EasyExcel.read(fileName, DemoData.class, new DemoCellCommentsListener()).sheet().doRead(); + EasyExcel.read(fileName, DemoExtraData.class, new DemoExtraListener()) + // 需要读取批注 默认不读取 + .extraRead(CellExtraTypeEnum.COMMENT) + // 需要读取超链接 默认不读取 + .extraRead(CellExtraTypeEnum.HYPERLINK) + // 需要读取合并单元格信息 默认不读取 + .extraRead(CellExtraTypeEnum.MERGE).sheet().doRead(); } /** @@ -233,7 +242,7 @@ public class ReadTest { } /** - * 不创建对象的读,不是特别推荐使用,都用String接收对日期的支持不是很好 + * 不创建对象的读 */ @Test public void noModleRead() { diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java index b92d44a..b1bcb7d 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/CustomCellWriteHandler.java @@ -6,13 +6,12 @@ import org.apache.poi.common.usermodel.HyperlinkType; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CreationHelper; import org.apache.poi.ss.usermodel.Hyperlink; -import org.apache.poi.ss.usermodel.Row; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.metadata.Head; -import com.alibaba.excel.write.handler.CellWriteHandler; +import com.alibaba.excel.write.handler.AbstractCellWriteHandler; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import com.alibaba.excel.write.metadata.holder.WriteTableHolder; @@ -21,22 +20,10 @@ import com.alibaba.excel.write.metadata.holder.WriteTableHolder; * * @author Jiaju Zhuang */ -public class CustomCellWriteHandler implements CellWriteHandler { +public class CustomCellWriteHandler extends AbstractCellWriteHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CustomCellWriteHandler.class); - @Override - public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, - Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) { - - } - - @Override - public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, - Head head, Integer relativeRowIndex, Boolean isHead) { - - } - @Override public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) { diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoMergeData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoMergeData.java new file mode 100644 index 0000000..ad94321 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoMergeData.java @@ -0,0 +1,27 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.util.Date; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ContentLoopMerge; + +import lombok.Data; + +/** + * 样式的数据类 + * + * @author Jiaju Zhuang + **/ +@Data +// 将第6-7行的2-3列合并成一个单元格 +// @OnceAbsoluteMerge(firstRowIndex = 5, lastRowIndex = 6, firstColumnIndex = 1, lastColumnIndex = 2) +public class DemoMergeData { + // 这一列 每隔2行 合并单元格 + @ContentLoopMerge(eachRow = 2) + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; + @ExcelProperty("数字标题") + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoStyleData.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoStyleData.java new file mode 100644 index 0000000..c73a088 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/DemoStyleData.java @@ -0,0 +1,44 @@ +package com.alibaba.easyexcel.test.demo.write; + +import java.util.Date; + +import org.apache.poi.ss.usermodel.FillPatternType; + +import com.alibaba.excel.annotation.ExcelProperty; +import com.alibaba.excel.annotation.write.style.ContentFontStyle; +import com.alibaba.excel.annotation.write.style.ContentStyle; +import com.alibaba.excel.annotation.write.style.HeadFontStyle; +import com.alibaba.excel.annotation.write.style.HeadStyle; + +import lombok.Data; + +/** + * 样式的数据类 + * + * @author Jiaju Zhuang + **/ +@Data +// 头背景设置成红色 IndexedColors.RED.getIndex() +@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10) +// 头字体设置成20 +@HeadFontStyle(fontHeightInPoints = 20) +// 内容的背景设置成绿色 IndexedColors.GREEN.getIndex() +@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17) +// 内容字体设置成20 +@ContentFontStyle(fontHeightInPoints = 20) +public class DemoStyleData { + // 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex() + @HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14) + // 字符串的头字体设置成20 + @HeadFontStyle(fontHeightInPoints = 30) + // 字符串的内容的背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex() + @ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40) + // 字符串的内容字体设置成20 + @ContentFontStyle(fontHeightInPoints = 30) + @ExcelProperty("字符串标题") + private String string; + @ExcelProperty("日期标题") + private Date date; + @ExcelProperty("数字标题") + private Double doubleData; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index 7b7d6b3..8b5fe53 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -270,7 +270,21 @@ public class WriteTest { } /** - * 自定义样式 + * 注解形式自定义样式 + *

+ * 1. 创建excel对应的实体对象 参照{@link DemoStyleData} + *

+ * 3. 直接写即可 + */ + @Test + public void annotationStyleWrite() { + String fileName = TestFileUtil.getPath() + "annotationStyleWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoStyleData.class).sheet("模板").doWrite(data()); + } + + /** + * 拦截器形式自定义样式 *

* 1. 创建excel对应的实体对象 参照{@link DemoData} *

@@ -279,8 +293,8 @@ public class WriteTest { * 3. 直接写即可 */ @Test - public void styleWrite() { - String fileName = TestFileUtil.getPath() + "styleWrite" + System.currentTimeMillis() + ".xlsx"; + public void handlerStyleWrite() { + String fileName = TestFileUtil.getPath() + "handlerStyleWrite" + System.currentTimeMillis() + ".xlsx"; // 头的策略 WriteCellStyle headWriteCellStyle = new WriteCellStyle(); // 背景设置为红色 @@ -310,7 +324,7 @@ public class WriteTest { /** * 合并单元格 *

- * 1. 创建excel对应的实体对象 参照{@link DemoData} + * 1. 创建excel对应的实体对象 参照{@link DemoData} {@link DemoMergeData} *

* 2. 创建一个merge策略 并注册 *

@@ -318,7 +332,14 @@ public class WriteTest { */ @Test public void mergeWrite() { + // 方法1 注解 String fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; + // 在DemoStyleData里面加上ContentLoopMerge注解 + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, DemoMergeData.class).sheet("模板").doWrite(data()); + + // 方法2 自定义合并单元格策略 + fileName = TestFileUtil.getPath() + "mergeWrite" + System.currentTimeMillis() + ".xlsx"; // 每隔2行会合并 把eachColumn 设置成 3 也就是我们数据的长度,所以就第一列会合并。当然其他合并策略也可以自己写 LoopMergeStrategy loopMergeStrategy = new LoopMergeStrategy(2, 0); // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 @@ -414,6 +435,23 @@ public class WriteTest { .registerWriteHandler(new CustomCellWriteHandler()).sheet("模板").doWrite(data()); } + /** + * 可变标题处理(包括标题国际化等) + *

+ * 简单的说用List>的标题 但是还支持注解 + *

+ * 1. 创建excel对应的实体对象 参照{@link ConverterData} + *

+ * 2. 直接写即可 + */ + @Test + public void variableTitleWrite() { + // 写法1 + String fileName = TestFileUtil.getPath() + "variableTitleWrite" + System.currentTimeMillis() + ".xlsx"; + // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭 + EasyExcel.write(fileName, ConverterData.class).head(variableTitleHead()).sheet("模板").doWrite(data()); + } + /** * 不创建对象的写 */ @@ -437,6 +475,20 @@ public class WriteTest { return list; } + private List> variableTitleHead() { + List> list = new ArrayList>(); + List head0 = new ArrayList(); + head0.add("string" + System.currentTimeMillis()); + List head1 = new ArrayList(); + head1.add("number" + System.currentTimeMillis()); + List head2 = new ArrayList(); + head2.add("date" + System.currentTimeMillis()); + list.add(head0); + list.add(head1); + list.add(head2); + return list; + } + private List> head() { List> list = new ArrayList>(); List head0 = new ArrayList(); diff --git a/src/test/resources/demo/extra.xlsx b/src/test/resources/demo/extra.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..4936b05a0f48bd0e4d6f0b21d19c2e7522c98de5 GIT binary patch literal 12045 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和`class`的head,会通过index去匹配注解 +* 修复读取转换器的并发问题 +* # 2.1.4 * 新增参数`useDefaultListener` 可以排除默认对象转换 From ea2669db82153f1ac148db4c4e311b02e574978b Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Sun, 15 Mar 2020 21:28:29 +0800 Subject: [PATCH 22/38] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E6=9C=80=E5=90=8E=E4=B8=80=E5=88=97=E4=B8=BA=E7=A9=BA=E4=BC=9A?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E8=BF=94=E5=9B=9Elist=E5=B0=91=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=95=B0=E6=8D=AE=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/read/listener/ModelBuildEventListener.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java index f5594db..78b57e0 100644 --- a/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java +++ b/src/main/java/com/alibaba/excel/read/listener/ModelBuildEventListener.java @@ -62,6 +62,11 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener (String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(), currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); } + int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size(); + while (index < headSize) { + map.put(index, null); + index++; + } return map; } else { // Compatible with the old code the old code returns a list @@ -82,6 +87,11 @@ public class ModelBuildEventListener extends AbstractIgnoreExceptionReadListener (String)ConverterUtils.convertToJavaObject(cellData, null, null, currentReadHolder.converterMap(), currentReadHolder.globalConfiguration(), context.readRowHolder().getRowIndex(), key)); } + int headSize = currentReadHolder.excelReadHeadProperty().getHeadMap().size(); + while (index < headSize) { + list.add(null); + index++; + } return list; } } From f99c198df7601e6967f425008aacdb886c6be63d Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Mon, 16 Mar 2020 02:07:18 +0800 Subject: [PATCH 23/38] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B5=8B=E8=AF=95bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../excel/analysis/ExcelAnalyserImpl.java | 3 +- .../excel/analysis/v03/XlsSaxAnalyser.java | 12 +- .../v03/handlers/BofRecordHandler.java | 6 +- .../v03/handlers/DummyRecordHandler.java | 2 + .../v03/handlers/FormulaRecordHandler.java | 7 + .../analysis/v07/handlers/RowTagHandler.java | 19 ++- .../read/builder/ExcelReaderBuilder.java | 2 +- .../metadata/holder/ReadWorkbookHolder.java | 10 +- .../alibaba/excel/support/ExcelTypeEnum.java | 67 ++++---- .../executor/ExcelWriteFillExecutor.java | 149 +++++++++++------- .../write/metadata/fill/AnalysisCell.java | 19 ++- .../write/metadata/fill/FillWrapper.java | 44 ++++++ .../test/core/dataformat/DateFormatTest.java | 10 +- .../test/core/fill/FillDataTest.java | 44 ++++++ .../test/core/head/ListHeadDataListener.java | 8 +- .../easyexcel/test/demo/fill/FillTest.java | 33 ++++ .../easyexcel/test/temp/FillTempTest.java | 22 +-- .../easyexcel/test/temp/TempFillData.java | 15 ++ .../easyexcel/test/temp/read/CommentTest.java | 4 +- src/test/resources/demo/fill/composite.xlsx | Bin 0 -> 10461 bytes src/test/resources/fill/composite.xls | Bin 0 -> 19968 bytes src/test/resources/fill/composite.xlsx | Bin 0 -> 10461 bytes update.md | 2 +- 23 files changed, 350 insertions(+), 128 deletions(-) create mode 100644 src/main/java/com/alibaba/excel/write/metadata/fill/FillWrapper.java create mode 100644 src/test/java/com/alibaba/easyexcel/test/temp/TempFillData.java create mode 100644 src/test/resources/demo/fill/composite.xlsx create mode 100644 src/test/resources/fill/composite.xls create mode 100644 src/test/resources/fill/composite.xlsx diff --git a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java index 4546c4b..5487ee1 100644 --- a/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java +++ b/src/main/java/com/alibaba/excel/analysis/ExcelAnalyserImpl.java @@ -59,8 +59,7 @@ public class ExcelAnalyserImpl implements ExcelAnalyser { } private void choiceExcelExecutor(ReadWorkbook readWorkbook) throws Exception { - ExcelTypeEnum excelType = - ExcelTypeEnum.valueOf(readWorkbook.getFile(), readWorkbook.getInputStream(), readWorkbook.getExcelType()); + ExcelTypeEnum excelType = ExcelTypeEnum.valueOf(readWorkbook); switch (excelType) { case XLS: POIFSFileSystem poifsFileSystem; diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java index a94a7d3..2b92253 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsSaxAnalyser.java @@ -56,6 +56,7 @@ import com.alibaba.excel.analysis.v03.handlers.StringRecordHandler; import com.alibaba.excel.analysis.v03.handlers.TextObjectRecordHandler; import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.exception.ExcelAnalysisException; +import com.alibaba.excel.exception.ExcelAnalysisStopException; import com.alibaba.excel.read.metadata.ReadSheet; import com.alibaba.excel.read.metadata.holder.xls.XlsReadWorkbookHolder; @@ -108,9 +109,14 @@ public class XlsSaxAnalyser implements HSSFListener, ExcelReadExecutor { @Override public List sheetList() { - if (xlsReadContext.readWorkbookHolder().getActualSheetDataList() == null) { - LOGGER.warn("Getting the 'sheetList' before reading will cause the file to be read twice."); - new XlsListSheetListener(xlsReadContext).execute(); + try { + if (xlsReadContext.readWorkbookHolder().getActualSheetDataList() == null) { + new XlsListSheetListener(xlsReadContext).execute(); + } + } catch (ExcelAnalysisStopException e) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug("Custom stop!"); + } } return xlsReadContext.readWorkbookHolder().getActualSheetDataList(); } diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java index 973d83e..66e3ab7 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/BofRecordHandler.java @@ -23,10 +23,14 @@ public class BofRecordHandler extends AbstractXlsRecordHandler { @Override public void processRecord(XlsReadContext xlsReadContext, Record record) { BOFRecord br = (BOFRecord)record; + XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder(); + if (br.getType() == BOFRecord.TYPE_WORKBOOK) { + xlsReadWorkbookHolder.setReadSheetIndex(null); + return; + } if (br.getType() != BOFRecord.TYPE_WORKSHEET) { return; } - XlsReadWorkbookHolder xlsReadWorkbookHolder = xlsReadContext.xlsReadWorkbookHolder(); // Init read sheet Data initReadSheetDataList(xlsReadWorkbookHolder); Integer readSheetIndex = xlsReadWorkbookHolder.getReadSheetIndex(); diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java index ab41d29..54a2d1d 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/DummyRecordHandler.java @@ -8,6 +8,7 @@ import org.apache.poi.hssf.record.Record; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; import com.alibaba.excel.context.xls.XlsReadContext; +import com.alibaba.excel.enums.RowTypeEnum; import com.alibaba.excel.metadata.Cell; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.read.metadata.holder.ReadRowHolder; @@ -30,6 +31,7 @@ public class DummyRecordHandler extends AbstractXlsRecordHandler implements Igno xlsReadContext.readSheetHolder().getGlobalConfiguration(), xlsReadSheetHolder.getCellMap())); xlsReadContext.analysisEventProcessor().endRow(xlsReadContext); xlsReadSheetHolder.setCellMap(new LinkedHashMap()); + xlsReadSheetHolder.setTempRowType(RowTypeEnum.EMPTY); } else if (record instanceof MissingCellDummyRecord) { MissingCellDummyRecord mcdr = (MissingCellDummyRecord)record; xlsReadSheetHolder.getCellMap().put(mcdr.getColumn(), diff --git a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java index 004d9c6..099b308 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/handlers/FormulaRecordHandler.java @@ -11,6 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.alibaba.excel.analysis.v03.IgnorableXlsRecordHandler; +import com.alibaba.excel.constant.BuiltinFormats; import com.alibaba.excel.context.xls.XlsReadContext; import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.Cell; @@ -52,6 +53,12 @@ public class FormulaRecordHandler extends AbstractXlsRecordHandler implements Ig case NUMERIC: tempCellData.setType(CellDataTypeEnum.NUMBER); tempCellData.setNumberValue(BigDecimal.valueOf(frec.getValue())); + Integer dataFormat = + xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatIndex(frec); + tempCellData.setDataFormat(dataFormat); + tempCellData.setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, + xlsReadContext.xlsReadWorkbookHolder().getFormatTrackingHSSFListener().getFormatString(frec), + xlsReadContext.readSheetHolder().getGlobalConfiguration().getLocale())); cellMap.put((int)frec.getColumn(), tempCellData); break; case ERROR: diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java index ee33266..56fa7ae 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/RowTagHandler.java @@ -20,14 +20,25 @@ public class RowTagHandler extends AbstractXlsxTagHandler { @Override public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { - xlsxReadContext.readRowHolder( - new ReadRowHolder(PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R)), - RowTypeEnum.DATA, xlsxReadContext.readSheetHolder().getGlobalConfiguration(), null)); + int rowIndex = PositionUtils.getRowByRowTagt(attributes.getValue(ExcelXmlConstants.ATTRIBUTE_R)); + Integer lastIndex = xlsxReadContext.readSheetHolder().getRowIndex(); + if (lastIndex != null) { + while (lastIndex + 1 < rowIndex) { + xlsxReadContext.readRowHolder(new ReadRowHolder(lastIndex + 1, RowTypeEnum.EMPTY, + xlsxReadContext.readSheetHolder().getGlobalConfiguration(), new LinkedHashMap())); + xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); + xlsxReadContext.xlsxReadSheetHolder().setCellMap(new LinkedHashMap()); + lastIndex++; + } + } + xlsxReadContext.readSheetHolder().setRowIndex(rowIndex); } @Override public void endElement(XlsxReadContext xlsxReadContext, String name) { - xlsxReadContext.readRowHolder().setCellMap(xlsxReadContext.xlsxReadSheetHolder().getCellMap()); + xlsxReadContext.readRowHolder(new ReadRowHolder(xlsxReadContext.readSheetHolder().getRowIndex(), + RowTypeEnum.DATA, xlsxReadContext.readSheetHolder().getGlobalConfiguration(), + xlsxReadContext.xlsxReadSheetHolder().getCellMap())); xlsxReadContext.analysisEventProcessor().endRow(xlsxReadContext); xlsxReadContext.xlsxReadSheetHolder().setCellMap(new LinkedHashMap()); } diff --git a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java index 342d943..81f3586 100644 --- a/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java +++ b/src/main/java/com/alibaba/excel/read/builder/ExcelReaderBuilder.java @@ -205,9 +205,9 @@ public class ExcelReaderBuilder extends AbstractExcelReaderParameterBuilder List doReadAllSync() { - ExcelReader excelReader = build(); SyncReadListener syncReadListener = new SyncReadListener(); registerReadListener(syncReadListener); + ExcelReader excelReader = build(); excelReader.readAll(); excelReader.finish(); return (List)syncReadListener.getList(); diff --git a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java index 7ad8972..375e32c 100644 --- a/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java +++ b/src/main/java/com/alibaba/excel/read/metadata/holder/ReadWorkbookHolder.java @@ -1,6 +1,5 @@ package com.alibaba.excel.read.metadata.holder; -import java.io.BufferedInputStream; import java.io.File; import java.io.InputStream; import java.util.HashSet; @@ -126,16 +125,9 @@ public class ReadWorkbookHolder extends AbstractReadHolder { super(readWorkbook, null, readWorkbook.getConvertAllFiled()); this.readWorkbook = readWorkbook; if (readWorkbook.getInputStream() != null) { - if (readWorkbook.getInputStream().markSupported()) { - this.inputStream = readWorkbook.getInputStream(); - } else { - this.inputStream = new BufferedInputStream(readWorkbook.getInputStream()); - } + this.inputStream = readWorkbook.getInputStream(); } this.file = readWorkbook.getFile(); - if (file == null && inputStream == null) { - throw new ExcelAnalysisException("File and inputStream must be a non-null."); - } if (readWorkbook.getMandatoryUseInputStream() == null) { this.mandatoryUseInputStream = Boolean.FALSE; } else { diff --git a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java index b4e41df..100775d 100644 --- a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java +++ b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java @@ -3,12 +3,13 @@ package com.alibaba.excel.support; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; -import java.io.IOException; import java.io.InputStream; import org.apache.poi.poifs.filesystem.FileMagic; +import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelCommonException; +import com.alibaba.excel.read.metadata.ReadWorkbook; /** * @author jipengfei @@ -29,44 +30,56 @@ public enum ExcelTypeEnum { this.setValue(value); } - public static ExcelTypeEnum valueOf(File file, InputStream inputStream, ExcelTypeEnum excelType) { + public static ExcelTypeEnum valueOf(ReadWorkbook readWorkbook) { + ExcelTypeEnum excelType = readWorkbook.getExcelType(); + if (excelType != null) { + return excelType; + } + File file = readWorkbook.getFile(); + InputStream inputStream = readWorkbook.getInputStream(); + if (file == null && inputStream == null) { + throw new ExcelAnalysisException("File and inputStream must be a non-null."); + } try { - FileMagic fileMagic; if (file != null) { + if (!file.exists()) { + throw new ExcelAnalysisException("File " + file.getAbsolutePath() + " not exists."); + } + String fileName = file.getName(); + if (fileName.endsWith(XLSX.getValue())) { + return XLSX; + } else if (fileName.endsWith(XLS.getValue())) { + return XLS; + } BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file)); try { - fileMagic = FileMagic.valueOf(bufferedInputStream); + return recognitionExcelType(bufferedInputStream); } finally { bufferedInputStream.close(); } - if (!FileMagic.OLE2.equals(fileMagic) && !FileMagic.OOXML.equals(fileMagic)) { - String fileName = file.getName(); - if (fileName.endsWith(XLSX.getValue())) { - return XLSX; - } else if (fileName.endsWith(XLS.getValue())) { - return XLS; - } else { - throw new ExcelCommonException("Unknown excel type."); - } - } - } else { - fileMagic = FileMagic.valueOf(inputStream); } - if (FileMagic.OLE2.equals(fileMagic)) { - return XLS; - } - if (FileMagic.OOXML.equals(fileMagic)) { - return XLSX; - } - } catch (IOException e) { - if (excelType != null) { - return excelType; + if (!inputStream.markSupported()) { + inputStream = new BufferedInputStream(inputStream); + readWorkbook.setInputStream(inputStream); } + return recognitionExcelType(inputStream); + } catch (ExcelCommonException e) { + throw e; + } catch (ExcelAnalysisException e) { + throw e; + } catch (Exception e) { throw new ExcelCommonException( "Convert excel format exception.You can try specifying the 'excelType' yourself", e); } - if (excelType != null) { - return excelType; + } + + private static ExcelTypeEnum recognitionExcelType(InputStream inputStream) throws Exception { + FileMagic fileMagic = FileMagic.valueOf(inputStream); + if (FileMagic.OLE2.equals(fileMagic)) { + return XLS; + } + if (FileMagic.OOXML.equals(fileMagic)) { + return XLSX; } throw new ExcelCommonException( "Convert excel format exception.You can try specifying the 'excelType' yourself"); diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java index 75aa660..0b8889a 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java @@ -27,6 +27,7 @@ import com.alibaba.excel.util.StringUtils; import com.alibaba.excel.util.WriteHandlerUtils; import com.alibaba.excel.write.metadata.fill.AnalysisCell; import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; import com.alibaba.excel.write.metadata.holder.WriteSheetHolder; import net.sf.cglib.beans.BeanMap; @@ -47,28 +48,36 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { /** * Fields to replace in the template */ - private Map> templateAnalysisCache = new HashMap>(8); + private Map> templateAnalysisCache = new HashMap>(8); /** * Collection fields to replace in the template */ - private Map> templateCollectionAnalysisCache = - new HashMap>(8); + private Map> templateCollectionAnalysisCache = + new HashMap>(8); /** * Style cache for collection fields */ - private Map> collectionFieldStyleCache = - new HashMap>(8); + private Map> collectionFieldStyleCache = + new HashMap>(8); /** * Row height cache for collection */ - private Map collectionRowHeightCache = new HashMap(8); + private Map collectionRowHeightCache = new HashMap(8); /** * Last index cache for collection fields */ - private Map> collectionLastIndexCache = - new HashMap>(8); + private Map> collectionLastIndexCache = + new HashMap>(8); - private Map relativeRowIndexMap = new HashMap(8); + private Map relativeRowIndexMap = new HashMap(8); + /** + * The data prefix that is populated this time + */ + private String currentDataPrefix; + /** + * The unique data encoding for this fill + */ + private String currentUniqueDataFlag; public ExcelWriteFillExecutor(WriteContext writeContext) { super(writeContext); @@ -79,9 +88,22 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { fillConfig = FillConfig.builder().build(true); } fillConfig.init(); - if (data instanceof Collection) { + + Object realData; + if (data instanceof FillWrapper) { + FillWrapper fillWrapper = (FillWrapper)data; + currentDataPrefix = fillWrapper.getName(); + realData = fillWrapper.getCollectionData(); + } else { + realData = data; + currentDataPrefix = null; + } + currentUniqueDataFlag = uniqueDataFlag(writeContext.writeSheetHolder().getSheetNo(), currentDataPrefix); + + // processing data + if (realData instanceof Collection) { List analysisCellList = readTemplateData(templateCollectionAnalysisCache); - Collection collectionData = (Collection)data; + Collection collectionData = (Collection)realData; if (CollectionUtils.isEmpty(collectionData)) { return; } @@ -93,7 +115,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { doFill(analysisCellList, iterator.next(), fillConfig, getRelativeRowIndex()); } } else { - doFill(readTemplateData(templateAnalysisCache), data, fillConfig, null); + doFill(readTemplateData(templateAnalysisCache), realData, fillConfig, null); } } @@ -102,8 +124,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { return; } int maxRowIndex = 0; - Integer sheetNo = writeContext.writeSheetHolder().getSheetNo(); - Map collectionLastIndexMap = collectionLastIndexCache.get(sheetNo); + Map collectionLastIndexMap = collectionLastIndexCache.get(currentUniqueDataFlag); for (AnalysisCell analysisCell : analysisCellList) { if (collectionLastIndexMap != null) { Integer lastRowIndex = collectionLastIndexMap.get(analysisCell); @@ -132,7 +153,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { return; } sheet.shiftRows(maxRowIndex + 1, lastRowIndex, number, true, false); - for (AnalysisCell analysisCell : templateAnalysisCache.get(writeContext.writeSheetHolder().getSheetNo())) { + for (AnalysisCell analysisCell : templateAnalysisCache.get(currentUniqueDataFlag)) { if (analysisCell.getRowIndex() > maxRowIndex) { analysisCell.setRowIndex(analysisCell.getRowIndex() + number); } @@ -206,14 +227,13 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } private Integer getRelativeRowIndex() { - Integer sheetNo = writeContext.writeSheetHolder().getSheetNo(); - Integer relativeRowIndex = relativeRowIndexMap.get(sheetNo); + Integer relativeRowIndex = relativeRowIndexMap.get(currentUniqueDataFlag); if (relativeRowIndex == null) { relativeRowIndex = 0; } else { relativeRowIndex++; } - relativeRowIndexMap.put(sheetNo, relativeRowIndex); + relativeRowIndexMap.put(currentUniqueDataFlag, relativeRowIndex); return relativeRowIndex; } @@ -222,13 +242,12 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { if (WriteTemplateAnalysisCellTypeEnum.COMMON.equals(analysisCell.getCellType())) { return cachedSheet.getRow(analysisCell.getRowIndex()).getCell(analysisCell.getColumnIndex()); } - Integer sheetNo = writeContext.writeSheetHolder().getSheetNo(); Sheet sheet = writeContext.writeSheetHolder().getSheet(); - Map collectionLastIndexMap = collectionLastIndexCache.get(sheetNo); + Map collectionLastIndexMap = collectionLastIndexCache.get(currentUniqueDataFlag); if (collectionLastIndexMap == null) { collectionLastIndexMap = new HashMap(16); - collectionLastIndexCache.put(sheetNo, collectionLastIndexMap); + collectionLastIndexCache.put(currentUniqueDataFlag, collectionLastIndexMap); } boolean isOriginalCell = false; Integer lastRowIndex; @@ -269,10 +288,10 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } else { row = sheet.createRow(lastRowIndex); } - checkRowHeight(analysisCell, fillConfig, isOriginalCell, row, sheetNo); + checkRowHeight(analysisCell, fillConfig, isOriginalCell, row); WriteHandlerUtils.afterRowCreate(writeContext, row, null, Boolean.FALSE); } else { - checkRowHeight(analysisCell, fillConfig, isOriginalCell, row, sheetNo); + checkRowHeight(analysisCell, fillConfig, isOriginalCell, row); } } Cell cell = row.getCell(lastColumnIndex); @@ -282,10 +301,10 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { WriteHandlerUtils.afterCellCreate(writeContext, cell, null, null, Boolean.FALSE); } - Map collectionFieldStyleMap = collectionFieldStyleCache.get(sheetNo); + Map collectionFieldStyleMap = collectionFieldStyleCache.get(currentUniqueDataFlag); if (collectionFieldStyleMap == null) { collectionFieldStyleMap = new HashMap(16); - collectionFieldStyleCache.put(sheetNo, collectionFieldStyleMap); + collectionFieldStyleCache.put(currentUniqueDataFlag, collectionFieldStyleMap); } if (isOriginalCell) { collectionFieldStyleMap.put(analysisCell, cell.getCellStyle()); @@ -298,31 +317,27 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { return cell; } - private void checkRowHeight(AnalysisCell analysisCell, FillConfig fillConfig, boolean isOriginalCell, Row row, - Integer sheetNo) { - if (!analysisCell.getFirstColumn() || !WriteDirectionEnum.VERTICAL.equals(fillConfig.getDirection())) { + private void checkRowHeight(AnalysisCell analysisCell, FillConfig fillConfig, boolean isOriginalCell, Row row) { + if (!analysisCell.getFirstRow() || !WriteDirectionEnum.VERTICAL.equals(fillConfig.getDirection())) { return; } if (isOriginalCell) { - collectionRowHeightCache.put(sheetNo, row.getHeight()); + collectionRowHeightCache.put(currentUniqueDataFlag, row.getHeight()); return; } - Short rowHeight = collectionRowHeightCache.get(sheetNo); + Short rowHeight = collectionRowHeightCache.get(currentUniqueDataFlag); if (rowHeight != null) { row.setHeight(rowHeight); } } - private List readTemplateData(Map> analysisCache) { - Integer sheetNo = writeContext.writeSheetHolder().getSheetNo(); - List analysisCellList = analysisCache.get(sheetNo); + private List readTemplateData(Map> analysisCache) { + List analysisCellList = analysisCache.get(currentUniqueDataFlag); if (analysisCellList != null) { return analysisCellList; } Sheet sheet = writeContext.writeSheetHolder().getCachedSheet(); - analysisCellList = new ArrayList(); - List collectionAnalysisCellList = new ArrayList(); - Set firstColumnCache = new HashSet(); + Map> firstRowCache = new HashMap>(8); for (int i = 0; i <= sheet.getLastRowNum(); i++) { Row row = sheet.getRow(i); if (row == null) { @@ -333,32 +348,26 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { if (cell == null) { continue; } - String preparedData = - prepareData(cell, analysisCellList, collectionAnalysisCellList, i, j, firstColumnCache); + String preparedData = prepareData(cell, i, j, firstRowCache); // Prevent empty data from not being replaced if (preparedData != null) { cell.setCellValue(preparedData); } } } - templateAnalysisCache.put(sheetNo, analysisCellList); - templateCollectionAnalysisCache.put(sheetNo, collectionAnalysisCellList); - return analysisCache.get(sheetNo); + return analysisCache.get(currentUniqueDataFlag); } /** * To prepare data * * @param cell - * @param analysisCellList - * @param collectionAnalysisCellList * @param rowIndex * @param columnIndex - * @param firstColumnCache + * @param firstRowCache * @return Returns the data that the cell needs to replace */ - private String prepareData(Cell cell, List analysisCellList, - List collectionAnalysisCellList, int rowIndex, int columnIndex, Set firstColumnCache) { + private String prepareData(Cell cell, int rowIndex, int columnIndex, Map> firstRowCache) { if (!CellType.STRING.equals(cell.getCellTypeEnum())) { return null; } @@ -404,8 +413,12 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { if (StringUtils.isEmpty(variable)) { continue; } - if (variable.startsWith(COLLECTION_PREFIX)) { - variable = variable.substring(1); + int collectPrefixIndex = variable.indexOf(COLLECTION_PREFIX); + if (collectPrefixIndex > -1) { + if (collectPrefixIndex != 0) { + analysisCell.setPrefix(variable.substring(0, collectPrefixIndex)); + } + variable = variable.substring(collectPrefixIndex + 1); if (StringUtils.isEmpty(variable)) { continue; } @@ -422,13 +435,13 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } lastPrepareDataIndex = suffixIndex + 1; } - return dealAnalysisCell(analysisCell, value, rowIndex, lastPrepareDataIndex, length, analysisCellList, - collectionAnalysisCellList, firstColumnCache, preparedData); + return dealAnalysisCell(analysisCell, value, rowIndex, lastPrepareDataIndex, length, firstRowCache, + preparedData); } private String dealAnalysisCell(AnalysisCell analysisCell, String value, int rowIndex, int lastPrepareDataIndex, - int length, List analysisCellList, List collectionAnalysisCellList, - Set firstColumnCache, StringBuilder preparedData) { + int length, Map> firstRowCache, StringBuilder preparedData) { + Integer sheetNo = writeContext.writeSheetHolder().getSheetNo(); if (analysisCell != null) { if (lastPrepareDataIndex == length) { analysisCell.getPrepareDataList().add(StringUtils.EMPTY); @@ -436,12 +449,29 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { analysisCell.getPrepareDataList().add(convertPrepareData(value.substring(lastPrepareDataIndex))); analysisCell.setOnlyOneVariable(Boolean.FALSE); } + String uniqueDataFlag = uniqueDataFlag(sheetNo, analysisCell.getPrefix()); if (WriteTemplateAnalysisCellTypeEnum.COMMON.equals(analysisCell.getCellType())) { + List analysisCellList = templateAnalysisCache.get(uniqueDataFlag); + if (analysisCellList == null) { + analysisCellList = new ArrayList(); + templateAnalysisCache.put(uniqueDataFlag, analysisCellList); + } analysisCellList.add(analysisCell); } else { - if (!firstColumnCache.contains(rowIndex)) { - analysisCell.setFirstColumn(Boolean.TRUE); - firstColumnCache.add(rowIndex); + Set uniqueFirstRowCache = firstRowCache.get(uniqueDataFlag); + if (uniqueFirstRowCache == null) { + uniqueFirstRowCache = new HashSet(); + firstRowCache.put(uniqueDataFlag, uniqueFirstRowCache); + } + if (!uniqueFirstRowCache.contains(rowIndex)) { + analysisCell.setFirstRow(Boolean.TRUE); + uniqueFirstRowCache.add(rowIndex); + } + + List collectionAnalysisCellList = templateCollectionAnalysisCache.get(uniqueDataFlag); + if (collectionAnalysisCellList == null) { + collectionAnalysisCellList = new ArrayList(); + templateCollectionAnalysisCache.put(uniqueDataFlag, collectionAnalysisCellList); } collectionAnalysisCellList.add(analysisCell); } @@ -460,7 +490,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { List prepareDataList = new ArrayList(); analysisCell.setPrepareDataList(prepareDataList); analysisCell.setCellType(WriteTemplateAnalysisCellTypeEnum.COMMON); - analysisCell.setFirstColumn(Boolean.FALSE); + analysisCell.setFirstRow(Boolean.FALSE); return analysisCell; } @@ -470,4 +500,11 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { return prepareData; } + private String uniqueDataFlag(Integer sheetNo, String wrapperName) { + if (StringUtils.isEmpty(wrapperName)) { + return sheetNo.toString() + "-"; + } + return sheetNo + "-" + wrapperName; + } + } diff --git a/src/main/java/com/alibaba/excel/write/metadata/fill/AnalysisCell.java b/src/main/java/com/alibaba/excel/write/metadata/fill/AnalysisCell.java index 47a2594..41b2cfc 100644 --- a/src/main/java/com/alibaba/excel/write/metadata/fill/AnalysisCell.java +++ b/src/main/java/com/alibaba/excel/write/metadata/fill/AnalysisCell.java @@ -16,7 +16,8 @@ public class AnalysisCell { private List prepareDataList; private Boolean onlyOneVariable; private WriteTemplateAnalysisCellTypeEnum cellType; - private Boolean firstColumn; + private String prefix; + private Boolean firstRow; public int getColumnIndex() { return columnIndex; @@ -58,6 +59,14 @@ public class AnalysisCell { this.onlyOneVariable = onlyOneVariable; } + public String getPrefix() { + return prefix; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + public WriteTemplateAnalysisCellTypeEnum getCellType() { return cellType; } @@ -66,12 +75,12 @@ public class AnalysisCell { this.cellType = cellType; } - public Boolean getFirstColumn() { - return firstColumn; + public Boolean getFirstRow() { + return firstRow; } - public void setFirstColumn(Boolean firstColumn) { - this.firstColumn = firstColumn; + public void setFirstRow(Boolean firstRow) { + this.firstRow = firstRow; } @Override diff --git a/src/main/java/com/alibaba/excel/write/metadata/fill/FillWrapper.java b/src/main/java/com/alibaba/excel/write/metadata/fill/FillWrapper.java new file mode 100644 index 0000000..e25e4da --- /dev/null +++ b/src/main/java/com/alibaba/excel/write/metadata/fill/FillWrapper.java @@ -0,0 +1,44 @@ +package com.alibaba.excel.write.metadata.fill; + +import java.util.Collection; + +/** + * Multiple lists are supported when packing + * + * @author Jiaju Zhuang + **/ +public class FillWrapper { + /** + * The collection prefix that needs to be filled. + */ + private String name; + /** + * Data that needs to be filled. + */ + private Collection collectionData; + + public FillWrapper(Collection collectionData) { + this.collectionData = collectionData; + } + + public FillWrapper(String name, Collection collectionData) { + this.name = name; + this.collectionData = collectionData; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Collection getCollectionData() { + return collectionData; + } + + public void setCollectionData(Collection collectionData) { + this.collectionData = collectionData; + } +} diff --git a/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java index 477652b..1ddb07f 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/dataformat/DateFormatTest.java @@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory; import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; /** * @@ -44,9 +45,10 @@ public class DateFormatTest { private void readCn(File file) { List list = EasyExcel.read(file, DateFormatData.class, null).locale(Locale.CHINA).sheet().doReadSync(); + System.out.println(JSON.toJSONString(list)); for (DateFormatData data : list) { - Assert.assertEquals(data.getDate(), data.getDateStringCn()); - Assert.assertEquals(data.getNumber(), data.getNumberStringCn()); + Assert.assertEquals(data.getDateStringCn(), data.getDate()); + Assert.assertEquals(data.getNumberStringCn(), data.getNumber()); } } @@ -54,8 +56,8 @@ public class DateFormatTest { List list = EasyExcel.read(file, DateFormatData.class, null).locale(Locale.US).sheet().doReadSync(); for (DateFormatData data : list) { - Assert.assertEquals(data.getDate(), data.getDateStringUs()); - Assert.assertEquals(data.getNumber(), data.getNumberStringUs()); + Assert.assertEquals(data.getDateStringUs(), data.getDate()); + Assert.assertEquals(data.getNumberStringUs(), data.getNumber()); } } } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java index 04a8bd1..bdcd34c 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java @@ -19,6 +19,7 @@ import com.alibaba.excel.enums.WriteDirectionEnum; import com.alibaba.excel.write.merge.LoopMergeStrategy; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; /** * @@ -39,6 +40,10 @@ public class FillDataTest { private static File horizontalFillTemplate07; private static File fileHorizontal03; private static File horizontalFillTemplate03; + private static File fileComposite07; + private static File compositeFillTemplate07; + private static File fileComposite03; + private static File compositeFillTemplate03; @BeforeClass public static void init() { @@ -54,6 +59,10 @@ public class FillDataTest { horizontalFillTemplate07 = TestFileUtil.readFile("fill" + File.separator + "horizontal.xlsx"); fileHorizontal03 = TestFileUtil.createNewFile("fillHorizontal03.xls"); horizontalFillTemplate03 = TestFileUtil.readFile("fill" + File.separator + "horizontal.xls"); + fileComposite07 = TestFileUtil.createNewFile("fileComposite07.xlsx"); + compositeFillTemplate07 = TestFileUtil.readFile("fill" + File.separator + "composite.xlsx"); + fileComposite03 = TestFileUtil.createNewFile("fileComposite03.xls"); + compositeFillTemplate03 = TestFileUtil.readFile("fill" + File.separator + "composite.xls"); } @Test @@ -86,6 +95,41 @@ public class FillDataTest { horizontalFill(fileHorizontal03, horizontalFillTemplate03); } + @Test + public void t07CompositeFill07() { + compositeFill(fileComposite07, compositeFillTemplate07); + } + + @Test + public void t08CompositeFill03() { + compositeFill(fileComposite03, compositeFillTemplate03); + } + + private void compositeFill(File file, File template) { + ExcelWriter excelWriter = EasyExcel.write(file).withTemplate(template).build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + + FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(); + excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet); + excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet); + excelWriter.fill(new FillWrapper("data2", data()), writeSheet); + excelWriter.fill(new FillWrapper("data2", data()), writeSheet); + excelWriter.fill(new FillWrapper("data3", data()), writeSheet); + excelWriter.fill(new FillWrapper("data3", data()), writeSheet); + Map map = new HashMap(); + map.put("date", "2019年10月9日13:28:28"); + excelWriter.fill(map, writeSheet); + excelWriter.finish(); + + List list = EasyExcel.read(file).ignoreEmptyRow(false).sheet().headRowNumber(0).doReadSync(); + Map map0 = (Map)list.get(0); + Assert.assertEquals("张三", map0.get(21)); + Map map27 = (Map)list.get(27); + Assert.assertEquals("张三", map27.get(0)); + Map map29 = (Map)list.get(29); + Assert.assertEquals("张三", map29.get(3)); + } + private void horizontalFill(File file, File template) { ExcelWriter excelWriter = EasyExcel.write(file).withTemplate(template).build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); diff --git a/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataListener.java index 81e85ae..c57976a 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/head/ListHeadDataListener.java @@ -29,10 +29,10 @@ public class ListHeadDataListener extends AnalysisEventListener data = list.get(0); - Assert.assertEquals(data.get(0), "字符串0"); - Assert.assertEquals(data.get(1), "1.0"); - Assert.assertEquals(data.get(2), "2020-01-01 01:01:01"); - Assert.assertEquals(data.get(3), "额外数据"); + Assert.assertEquals("字符串0", data.get(0)); + Assert.assertEquals("1", data.get(1)); + Assert.assertEquals("2020-01-01 01:01:01", data.get(2)); + Assert.assertEquals("额外数据", data.get(3)); LOGGER.debug("First row:{}", JSON.toJSONString(list.get(0))); } } diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java index 32a0185..068045e 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java @@ -15,6 +15,7 @@ import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.enums.WriteDirectionEnum; import com.alibaba.excel.write.metadata.WriteSheet; import com.alibaba.excel.write.metadata.fill.FillConfig; +import com.alibaba.excel.write.metadata.fill.FillWrapper; /** * 写的填充写法 @@ -179,6 +180,38 @@ public class FillTest { excelWriter.finish(); } + /** + * 组合填充填充 + * + * @since 2.2.0 + */ + @Test + public void compositeFill() { + // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 + // {} 代表普通变量 {.} 代表是list的变量 {前缀.} 前缀可以区分不同的list + String templateFileName = + TestFileUtil.getPath() + "demo" + File.separator + "fill" + File.separator + "composite.xlsx"; + + String fileName = TestFileUtil.getPath() + "compositeFill" + System.currentTimeMillis() + ".xlsx"; + ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build(); + WriteSheet writeSheet = EasyExcel.writerSheet().build(); + FillConfig fillConfig = FillConfig.builder().direction(WriteDirectionEnum.HORIZONTAL).build(); + // 如果有多个list 模板上必须有{前缀.} 这里的前缀就是 data1,然后多个list必须用 FillWrapper包裹 + excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet); + excelWriter.fill(new FillWrapper("data1", data()), fillConfig, writeSheet); + excelWriter.fill(new FillWrapper("data2", data()), writeSheet); + excelWriter.fill(new FillWrapper("data2", data()), writeSheet); + excelWriter.fill(new FillWrapper("data3", data()), writeSheet); + excelWriter.fill(new FillWrapper("data3", data()), writeSheet); + + Map map = new HashMap(); + map.put("date", "2019年10月9日13:28:28"); + excelWriter.fill(map, writeSheet); + + // 别忘记关闭流 + excelWriter.finish(); + } + private List data() { List list = new ArrayList(); for (int i = 0; i < 10; i++) { diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java index 8049d89..0ed625d 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/FillTempTest.java @@ -14,7 +14,6 @@ import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; -import com.alibaba.excel.write.metadata.fill.FillConfig; /** * 写的填充写法 @@ -34,18 +33,12 @@ public class FillTempTest { public void complexFill() { // 模板注意 用{} 来表示你要用的变量 如果本来就有"{","}" 特殊字符 用"\{","\}"代替 // {} 代表普通变量 {.} 代表是list的变量 - String templateFileName = "D:\\test\\complex.xlsx"; + String templateFileName = "D:\\test\\simple.xlsx"; String fileName = TestFileUtil.getPath() + "complexFill" + System.currentTimeMillis() + ".xlsx"; ExcelWriter excelWriter = EasyExcel.write(fileName).withTemplate(templateFileName).build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); - // 这里注意 入参用了forceNewRow 代表在写入list的时候不管list下面有没有空行 都会创建一行,然后下面的数据往后移动。默认 是false,会直接使用下一行,如果没有则创建。 - // forceNewRow 如果设置了true,有个缺点 就是他会把所有的数据都放到内存了,所以慎用 - // 简单的说 如果你的模板有list,且list不是最后一行,下面还有数据需要填充 就必须设置 forceNewRow=true 但是这个就会把所有数据放到内存 会很耗内存 - // 如果数据量大 list不是最后一行 参照下一个 - FillConfig fillConfig = FillConfig.builder().forceNewRow(Boolean.TRUE).build(); - excelWriter.fill(data(), fillConfig, writeSheet); -// excelWriter.fill(data2(), fillConfig, writeSheet); + excelWriter.fill(teamp(), writeSheet); Map map = new HashMap(); map.put("date", "2019年10月9日13:28:28"); map.put("total", 1000); @@ -106,6 +99,17 @@ public class FillTempTest { return list; } + private List teamp() { + List list = new ArrayList(); + for (int i = 0; i < 10; i++) { + TempFillData fillData = new TempFillData(); + list.add(fillData); + fillData.setName("张三"); + fillData.setNumber(5.2); + } + return list; + } + private List data() { List list = new ArrayList(); for (int i = 0; i < 10; i++) { diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/TempFillData.java b/src/test/java/com/alibaba/easyexcel/test/temp/TempFillData.java new file mode 100644 index 0000000..55984a7 --- /dev/null +++ b/src/test/java/com/alibaba/easyexcel/test/temp/TempFillData.java @@ -0,0 +1,15 @@ +package com.alibaba.easyexcel.test.temp; + +import com.alibaba.excel.annotation.write.style.ContentRowHeight; + +import lombok.Data; + +/** + * @author Jiaju Zhuang + */ +@Data +@ContentRowHeight(30) +public class TempFillData { + private String name; + private double number; +} diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java index 21e0d9c..2c9235a 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java @@ -24,10 +24,10 @@ public class CommentTest { @Test public void comment() throws Exception { - File file = new File("D:\\test\\comment.xls"); + File file = new File("D:\\test\\listHead07.xlsx"); List> datas = EasyExcel.read(file).doReadAllSync(); for (Map data : datas) { - LOGGER.info("数据:{}", JSON.toJSONString(data.get(0))); + LOGGER.info("数据:{}", JSON.toJSONString(data)); } } diff --git a/src/test/resources/demo/fill/composite.xlsx b/src/test/resources/demo/fill/composite.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c76a2b12ba8576c8394009436ec01ba7e88c89e1 GIT binary patch literal 10461 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

u{y6O^mTHrURC|_V1#A9 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 DQ|0>1 literal 0 HcmV?d00001 diff --git a/src/test/resources/fill/composite.xlsx b/src/test/resources/fill/composite.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..c76a2b12ba8576c8394009436ec01ba7e88c89e1 GIT binary patch literal 10461 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和`class`的head,会通过index去匹配注解 * 修复读取转换器的并发问题 -* +* 填充支持多个List对象 # 2.1.4 * 新增参数`useDefaultListener` 可以排除默认对象转换 From 26c6de095b892fdbc2b804a30c0a95be41728b7a Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Mon, 16 Mar 2020 22:39:31 +0800 Subject: [PATCH 24/38] =?UTF-8?q?=E9=87=8D=E5=86=99=E4=B8=BB=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=EF=BC=8C=E4=BB=A3=E7=A0=81=E6=9B=B4=E5=8A=A0=E4=BC=98?= =?UTF-8?q?=E9=9B=85=20=E6=B5=8B=E8=AF=95=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../analysis/v07/handlers/CellTagHandler.java | 22 +++++++++++------ .../excel/constant/BuiltinFormats.java | 8 +++--- .../alibaba/excel/support/ExcelTypeEnum.java | 23 ++++++++++++++---- .../core/converter/ConverterDataListener.java | 2 +- .../ReadAllConverterDataListener.java | 2 +- .../test/core/dataformat/DateFormatTest.java | 2 -- .../test/core/encrypt/EncryptDataTest.java | 12 +++------ .../easyexcel/test/temp/read/CommentTest.java | 2 +- src/test/resources/dataformat/dataformat.xls | Bin 26112 -> 26112 bytes src/test/resources/dataformat/dataformat.xlsx | Bin 11754 -> 11746 bytes 10 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java index 7ba521d..2f35435 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/CellTagHandler.java @@ -10,6 +10,7 @@ import com.alibaba.excel.enums.CellDataTypeEnum; import com.alibaba.excel.metadata.CellData; import com.alibaba.excel.read.metadata.holder.xlsx.XlsxReadSheetHolder; import com.alibaba.excel.util.PositionUtils; +import com.alibaba.excel.util.StringUtils; /** * Cell Handler @@ -18,6 +19,8 @@ import com.alibaba.excel.util.PositionUtils; */ public class CellTagHandler extends AbstractXlsxTagHandler { + private static final int DEFAULT_FORMAT_INDEX = 0; + @Override public void startElement(XlsxReadContext xlsxReadContext, String name, Attributes attributes) { XlsxReadSheetHolder xlsxReadSheetHolder = xlsxReadContext.xlsxReadSheetHolder(); @@ -36,15 +39,18 @@ public class CellTagHandler extends AbstractXlsxTagHandler { // Put in data transformation information String dateFormatIndex = attributes.getValue(ExcelXmlConstants.ATTRIBUTE_S); - if (dateFormatIndex != null) { - int dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); - XSSFCellStyle xssfCellStyle = - xlsxReadContext.xlsxReadWorkbookHolder().getStylesTable().getStyleAt(dateFormatIndexInteger); - int dataFormat = xssfCellStyle.getDataFormat(); - xlsxReadSheetHolder.getTempCellData().setDataFormat(dataFormat); - xlsxReadSheetHolder.getTempCellData().setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, - xssfCellStyle.getDataFormatString(), xlsxReadSheetHolder.getGlobalConfiguration().getLocale())); + Integer dateFormatIndexInteger; + if (StringUtils.isEmpty(dateFormatIndex)) { + dateFormatIndexInteger = DEFAULT_FORMAT_INDEX; + } else { + dateFormatIndexInteger = Integer.parseInt(dateFormatIndex); } + XSSFCellStyle xssfCellStyle = + xlsxReadContext.xlsxReadWorkbookHolder().getStylesTable().getStyleAt(dateFormatIndexInteger); + int dataFormat = xssfCellStyle.getDataFormat(); + xlsxReadSheetHolder.getTempCellData().setDataFormat(dataFormat); + xlsxReadSheetHolder.getTempCellData().setDataFormatString(BuiltinFormats.getBuiltinFormat(dataFormat, + xssfCellStyle.getDataFormatString(), xlsxReadSheetHolder.getGlobalConfiguration().getLocale())); } } diff --git a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java index 1dec2c6..95eb0b8 100644 --- a/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java +++ b/src/main/java/com/alibaba/excel/constant/BuiltinFormats.java @@ -64,8 +64,8 @@ public class BuiltinFormats { // 21 "h:mm:ss", // 22 - // The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy/m/d h:mm". - "yyyy/m/d h:mm", + // The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy-m-d h:mm". + "yyyy-m-d h:mm", // 23-26 No specific correspondence found in the official documentation. // 23 null, @@ -236,8 +236,8 @@ public class BuiltinFormats { // 21 "h:mm:ss", // 22 - // The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy/m/d h:mm". - "yyyy/m/d h:mm", + // The official documentation shows "m/d/yy h:mm", but the actual test is "yyyy-m-d h:mm". + "yyyy-m-d h:mm", // 23-26 No specific correspondence found in the official documentation. // 23 null, diff --git a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java index 100775d..cdca07f 100644 --- a/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java +++ b/src/main/java/com/alibaba/excel/support/ExcelTypeEnum.java @@ -10,6 +10,7 @@ import org.apache.poi.poifs.filesystem.FileMagic; import com.alibaba.excel.exception.ExcelAnalysisException; import com.alibaba.excel.exception.ExcelCommonException; import com.alibaba.excel.read.metadata.ReadWorkbook; +import com.alibaba.excel.util.StringUtils; /** * @author jipengfei @@ -45,17 +46,29 @@ public enum ExcelTypeEnum { if (!file.exists()) { throw new ExcelAnalysisException("File " + file.getAbsolutePath() + " not exists."); } + // If there is a password, use the FileMagic first + if (!StringUtils.isEmpty(readWorkbook.getPassword())) { + BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file)); + try { + return recognitionExcelType(bufferedInputStream); + } finally { + bufferedInputStream.close(); + } + } + // Use the name to determine the type String fileName = file.getName(); if (fileName.endsWith(XLSX.getValue())) { return XLSX; } else if (fileName.endsWith(XLS.getValue())) { return XLS; } - BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file)); - try { - return recognitionExcelType(bufferedInputStream); - } finally { - bufferedInputStream.close(); + if (StringUtils.isEmpty(readWorkbook.getPassword())) { + BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream(file)); + try { + return recognitionExcelType(bufferedInputStream); + } finally { + bufferedInputStream.close(); + } } } if (!inputStream.markSupported()) { diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataListener.java index abd5e1c..210ca14 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ConverterDataListener.java @@ -32,7 +32,7 @@ public class ConverterDataListener extends AnalysisEventListener Assert.assertEquals(list.size(), 1); ConverterData data = list.get(0); try { - Assert.assertEquals(data.getDate(), DateUtils.parseDate("2020-01-01 01:01:01")); + Assert.assertEquals(DateUtils.parseDate("2020-01-01 01:01:01"), data.getDate()); } catch (ParseException e) { throw new ExcelCommonException("Test Exception", e); } diff --git a/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java index c8b5d8b..d5da81a 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/converter/ReadAllConverterDataListener.java @@ -64,7 +64,7 @@ public class ReadAllConverterDataListener extends AnalysisEventListener list = EasyExcel.read(file, DateFormatData.class, null).locale(Locale.CHINA).sheet().doReadSync(); - System.out.println(JSON.toJSONString(list)); for (DateFormatData data : list) { Assert.assertEquals(data.getDateStringCn(), data.getDate()); Assert.assertEquals(data.getNumberStringCn(), data.getNumber()); diff --git a/src/test/java/com/alibaba/easyexcel/test/core/encrypt/EncryptDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/encrypt/EncryptDataTest.java index 98f580f..375f9be 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/encrypt/EncryptDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/encrypt/EncryptDataTest.java @@ -6,19 +6,15 @@ import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; -import org.junit.Assert; import org.junit.BeforeClass; import org.junit.FixMethodOrder; import org.junit.Test; import org.junit.runners.MethodSorters; import com.alibaba.easyexcel.test.core.simple.SimpleData; -import com.alibaba.easyexcel.test.core.simple.SimpleDataListener; -import com.alibaba.easyexcel.test.core.simple.SimpleDataSheetNameListener; import com.alibaba.easyexcel.test.util.TestFileUtil; import com.alibaba.excel.EasyExcel; import com.alibaba.excel.support.ExcelTypeEnum; -import com.alibaba.excel.util.FileUtils; /** * @@ -51,12 +47,12 @@ public class EncryptDataTest { } @Test - public void t01ReadAndWriteStream07() throws Exception { + public void t03ReadAndWriteStream07() throws Exception { readAndWriteStream(file07OutputStream, ExcelTypeEnum.XLSX); } @Test - public void t02ReadAndWriteStream03() throws Exception { + public void t04ReadAndWriteStream03() throws Exception { readAndWriteStream(file03OutputStream, ExcelTypeEnum.XLS); } @@ -72,8 +68,8 @@ public class EncryptDataTest { fileOutputStream.close(); FileInputStream fileInputStream = new FileInputStream(file); - EasyExcel.read(fileInputStream, EncryptData.class, new EncryptDataListener()).password("123456") - .excelType(excelType).sheet().doRead(); + EasyExcel.read(fileInputStream, EncryptData.class, new EncryptDataListener()).password("123456").sheet() + .doRead(); } private List data() { diff --git a/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java b/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java index 2c9235a..22de395 100644 --- a/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/temp/read/CommentTest.java @@ -24,7 +24,7 @@ public class CommentTest { @Test public void comment() throws Exception { - File file = new File("D:\\test\\listHead07.xlsx"); + File file = new File("D:\\test\\d1.xlsx"); List> datas = EasyExcel.read(file).doReadAllSync(); for (Map data : datas) { LOGGER.info("数据:{}", JSON.toJSONString(data)); diff --git a/src/test/resources/dataformat/dataformat.xls b/src/test/resources/dataformat/dataformat.xls index c03847e4e5cde9f156ddf23b5d8263dc1357453e..632cb1ec752ba058ef533540929c9af7b61d489e 100644 GIT binary patch delta 1338 zcmZ`(U2GIp6#njXW@lR3(wY71wyfPse^_L*>{{xB32qIxwa_9q#nP>%Q`*HQLQT65 zq9)zMfC-vNJtp;`iX>FdD;iFIV4eB#Euh2CkK)3aFx@vUNk9vSQjikB_Cxp{fI;Yk&;u};!4B|6v z#1JTk8>~{z`WobubfdrZhn8RRDng2ilib? zYa-V4@3X4e&QYZcFA^8BYH zA2jNVJ|B`k>*n8S3B#O34Tq6<*#q28MOxkDBwkv?S8K4De((nMCko0fzNp=r_a9-_ zu7TIBf#<8sG7nWf?v_aeU7J`d)>@hYcbA?hWV_236UJScb6tOV+Mfl=L6`bB(6>7+<<<*y zyZ;a8{I1{h=`wkg?-1-5%` zUj7f;lI*4e+mh_&0^2=(LwPne_BD(B)ZG^o!}KOwo4#N>LO-!RK-%7z7^NrKj*-na zL+?v_Vee3-n=fR6*;AZT{T~ab=cU($vwdJzd_5RY^z9`_|C#^&pc5YYStr|l?rFEovZys2i?2Cb4Oi_Y?acfOs>>i|LRyr70n%!3$AiNR#$p>%mApG||K&2f;VHtESbY^Gn|Q zz4t!vJHL7PO?IBM^L$ZNxE`AF11H>{l}Xmab${J_Z5l)BIPb)=+UzePqE&ftQr)P% z<3)IwNxk5u)TgCtEhND;ENgW^jkuBeXh_y5VXvM-x4ssq^`vqxjoSHI^^W*=MN3m}$27TpN5kD>dl0SlkzY%wQHh%SQ#dXOQ2g3N+_X>{qcca1| zb}IrWR4qnRWMDEF;V%3V9E+FHkK`vFp#18hxSVv9DpiN3De$x~KvHrKhE6ItZ(5o$R8W!0jhZnNG`KYe!Qmb*T>XuGf09*;)P zz9AdoFym!6US1JF!Thlwt+7_ASHhk2PakD*H LPhl5!9oX>*@$4IE diff --git a/src/test/resources/dataformat/dataformat.xlsx b/src/test/resources/dataformat/dataformat.xlsx index 0085930c31d5b3a08eb63f6f868089eb89c6a29d..9f41f274801a008d8e96a12c8a0c31e6f5165216 100644 GIT binary patch delta 6381 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 delta 6401 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 L2VI`)ALPFP?t%%5 From f567698331a26782f7bca86f75b3b8b4e3bf83f9 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Mon, 16 Mar 2020 22:55:15 +0800 Subject: [PATCH 25/38] =?UTF-8?q?=E9=87=8D=E5=86=99=E4=B8=BB=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=EF=BC=8C=E4=BB=A3=E7=A0=81=E6=9B=B4=E5=8A=A0=E4=BC=98?= =?UTF-8?q?=E9=9B=85=20=E6=B5=8B=E8=AF=95=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java | 1 + .../analysis/v07/handlers/AbstractCellValueTagHandler.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java index 3b4fa7c..ca9218a 100644 --- a/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v03/XlsRecordHandler.java @@ -15,6 +15,7 @@ public interface XlsRecordHandler { * * @param xlsReadContext * @param record + * @return */ boolean support(XlsReadContext xlsReadContext, Record record); diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java index 0c60d66..3521e46 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/AbstractCellValueTagHandler.java @@ -58,6 +58,8 @@ public abstract class AbstractCellValueTagHandler extends AbstractXlsxTagHandler /** * Set string value. + * + * @param xlsxReadContext */ protected abstract void setStringValue(XlsxReadContext xlsxReadContext); From 75391650e70353bdd27a1ed7458f7aa391526aa0 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Mon, 16 Mar 2020 23:13:20 +0800 Subject: [PATCH 26/38] =?UTF-8?q?=E9=87=8D=E5=86=99=E4=B8=BB=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=EF=BC=8C=E4=BB=A3=E7=A0=81=E6=9B=B4=E5=8A=A0=E4=BC=98?= =?UTF-8?q?=E9=9B=85=20=E6=B5=8B=E8=AF=95=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java index 3bd353a..fe392f9 100644 --- a/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java +++ b/src/main/java/com/alibaba/excel/analysis/v07/handlers/XlsxTagHandler.java @@ -15,6 +15,7 @@ public interface XlsxTagHandler { * Whether to support * * @param xlsxReadContext + * @return */ boolean support(XlsxReadContext xlsxReadContext); From c88a0820350a2151b395308009832b861959f735 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Mon, 16 Mar 2020 23:29:43 +0800 Subject: [PATCH 27/38] =?UTF-8?q?=E9=87=8D=E5=86=99=E4=B8=BB=E6=B5=81?= =?UTF-8?q?=E7=A8=8B=EF=BC=8C=E4=BB=A3=E7=A0=81=E6=9B=B4=E5=8A=A0=E4=BC=98?= =?UTF-8?q?=E9=9B=85=20=E6=B5=8B=E8=AF=95=E5=AE=8C=E6=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/alibaba/excel/context/AnalysisContext.java | 2 +- .../alibaba/excel/write/executor/ExcelWriteAddExecutor.java | 2 +- .../alibaba/excel/write/executor/ExcelWriteFillExecutor.java | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/alibaba/excel/context/AnalysisContext.java b/src/main/java/com/alibaba/excel/context/AnalysisContext.java index 684fb6e..df17f55 100644 --- a/src/main/java/com/alibaba/excel/context/AnalysisContext.java +++ b/src/main/java/com/alibaba/excel/context/AnalysisContext.java @@ -88,7 +88,7 @@ public interface AnalysisContext { /** * Data that the customer needs to read * - * @return + * @param readSheetList */ void readSheetList(List readSheetList); diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java index 66878c5..e218fa7 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteAddExecutor.java @@ -37,7 +37,7 @@ public class ExcelWriteAddExecutor extends AbstractExcelWriteExecutor { public void add(List data) { if (CollectionUtils.isEmpty(data)) { - return; + data = new ArrayList(); } WriteSheetHolder writeSheetHolder = writeContext.writeSheetHolder(); int newRowIndex = writeSheetHolder.getNewRowIndexAndStartDoWrite(); diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java index 0b8889a..03607b3 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java @@ -84,6 +84,9 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { } public void fill(Object data, FillConfig fillConfig) { + if (data == null) { + data = new HashMap(16); + } if (fillConfig == null) { fillConfig = FillConfig.builder().build(true); } From b3a30d099383d364dbf9e202893c4025df81ae5b Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 00:46:22 +0800 Subject: [PATCH 28/38] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../easyexcel/test/core/fill/FillDataTest.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java index a3e2463..5c40030 100644 --- a/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/core/fill/FillDataTest.java @@ -113,23 +113,23 @@ public class FillDataTest { byNameFill(byName03, byNameTemplate03); } - private void byNameFill(File file, File template) { - FillData fillData = new FillData(); - fillData.setName("张三"); - fillData.setNumber(5.2); - EasyExcel.write(file, FillData.class).withTemplate(template).sheet("Sheet2").doFill(fillData); - } - @Test - public void t07CompositeFill07() { + public void t09CompositeFill07() { compositeFill(fileComposite07, compositeFillTemplate07); } @Test - public void t08CompositeFill03() { + public void t10CompositeFill03() { compositeFill(fileComposite03, compositeFillTemplate03); } + private void byNameFill(File file, File template) { + FillData fillData = new FillData(); + fillData.setName("张三"); + fillData.setNumber(5.2); + EasyExcel.write(file, FillData.class).withTemplate(template).sheet("Sheet2").doFill(fillData); + } + private void compositeFill(File file, File template) { ExcelWriter excelWriter = EasyExcel.write(file).withTemplate(template).build(); WriteSheet writeSheet = EasyExcel.writerSheet().build(); From 0bf3e5e9a5b89d1e4ee206a81a1309d82127c346 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 00:56:19 +0800 Subject: [PATCH 29/38] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=90=88=E5=B9=B6?= =?UTF-8?q?=E5=BC=82=E5=B8=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../executor/ExcelWriteFillExecutor.java | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java index 03607b3..51d7d3a 100644 --- a/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java +++ b/src/main/java/com/alibaba/excel/write/executor/ExcelWriteFillExecutor.java @@ -85,7 +85,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { public void fill(Object data, FillConfig fillConfig) { if (data == null) { - data = new HashMap(16); + data = new HashMap(16); } if (fillConfig == null) { fillConfig = FillConfig.builder().build(true); @@ -101,7 +101,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { realData = data; currentDataPrefix = null; } - currentUniqueDataFlag = uniqueDataFlag(writeContext.writeSheetHolder().getSheetNo(), currentDataPrefix); + currentUniqueDataFlag = uniqueDataFlag(writeContext.writeSheetHolder(), currentDataPrefix); // processing data if (realData instanceof Collection) { @@ -444,7 +444,6 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { private String dealAnalysisCell(AnalysisCell analysisCell, String value, int rowIndex, int lastPrepareDataIndex, int length, Map> firstRowCache, StringBuilder preparedData) { - Integer sheetNo = writeContext.writeSheetHolder().getSheetNo(); if (analysisCell != null) { if (lastPrepareDataIndex == length) { analysisCell.getPrepareDataList().add(StringUtils.EMPTY); @@ -452,7 +451,7 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { analysisCell.getPrepareDataList().add(convertPrepareData(value.substring(lastPrepareDataIndex))); analysisCell.setOnlyOneVariable(Boolean.FALSE); } - String uniqueDataFlag = uniqueDataFlag(sheetNo, analysisCell.getPrefix()); + String uniqueDataFlag = uniqueDataFlag(writeContext.writeSheetHolder(), analysisCell.getPrefix()); if (WriteTemplateAnalysisCellTypeEnum.COMMON.equals(analysisCell.getCellType())) { List analysisCellList = templateAnalysisCache.get(uniqueDataFlag); if (analysisCellList == null) { @@ -503,11 +502,17 @@ public class ExcelWriteFillExecutor extends AbstractExcelWriteExecutor { return prepareData; } - private String uniqueDataFlag(Integer sheetNo, String wrapperName) { + private String uniqueDataFlag(WriteSheetHolder writeSheetHolder, String wrapperName) { + String prefix; + if (writeSheetHolder.getSheetNo() != null) { + prefix = writeSheetHolder.getSheetNo().toString(); + } else { + prefix = writeSheetHolder.getSheetName().toString(); + } if (StringUtils.isEmpty(wrapperName)) { - return sheetNo.toString() + "-"; + return prefix + "-"; } - return sheetNo + "-" + wrapperName; + return prefix + "-" + wrapperName; } } From 611cfd5045f9e1df30d1ecb795a8537dcebf1327 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 01:36:42 +0800 Subject: [PATCH 30/38] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=86=99=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/easyexcel/test/demo/write/WriteTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index 8b5fe53..55a1ae3 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -160,8 +160,8 @@ public class WriteTest { excelWriter = EasyExcel.write(fileName, DemoData.class).build(); // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面 for (int i = 0; i < 5; i++) { - // 每次都要创建writeSheet 这里注意必须指定sheetNo - writeSheet = EasyExcel.writerSheet(i, "模板").build(); +·· // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样 + writeSheet = EasyExcel.writerSheet(i, "模板" + i).build(); // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 List data = data(); excelWriter.write(data, writeSheet); From bc966c08ce831816f50c2a78655fc8cd42882400 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 01:36:55 +0800 Subject: [PATCH 31/38] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=86=99=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/easyexcel/test/demo/write/WriteTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index 55a1ae3..3e93d6e 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -160,7 +160,7 @@ public class WriteTest { excelWriter = EasyExcel.write(fileName, DemoData.class).build(); // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面 for (int i = 0; i < 5; i++) { -·· // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样 + // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样 writeSheet = EasyExcel.writerSheet(i, "模板" + i).build(); // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 List data = data(); From b3d9147f8e6c32ec8389e8ced3dea509924bbab9 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 01:37:27 +0800 Subject: [PATCH 32/38] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E5=86=99=E6=8F=8F=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/easyexcel/test/demo/write/WriteTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index 3e93d6e..0a04f89 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -175,8 +175,8 @@ public class WriteTest { excelWriter = EasyExcel.write(fileName).build(); // 去调用写入,这里我调用了五次,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面 for (int i = 0; i < 5; i++) { - // 每次都要创建writeSheet 这里注意必须指定sheetNo。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变 - writeSheet = EasyExcel.writerSheet(i, "模板").head(DemoData.class).build(); + // 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变 + writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build(); // 分页去数据库查询数据 这里可以去数据库查询每一页的数据 List data = data(); excelWriter.write(data, writeSheet); From 487c18a7881c27a558b035e3fd5fb4df6a098324 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 22:00:42 +0800 Subject: [PATCH 33/38] =?UTF-8?q?=E6=96=B0=E5=A2=9Esince?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/easyexcel/test/demo/read/ReadTest.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java index 5234f05..b411cae 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/read/ReadTest.java @@ -173,6 +173,8 @@ public class ReadTest { * 2. 由于默认异步读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoExtraListener} *

* 3. 直接读即可 + * + * @since 2.2.0-beat1 */ @Test public void extraRead() { @@ -191,11 +193,13 @@ public class ReadTest { * 读取公式和单元格类型 * *

- * 1. 创建excel对应的实体对象 参照{@link DemoData} + * 1. 创建excel对应的实体对象 参照{@link CellDataReadDemoData} *

* 2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoHeadDataListener} *

* 3. 直接读即可 + * + * @since 2.2.0-beat1 */ @Test public void cellDataRead() { From 254387d0f8f3859a9eb06aae5fc49a72a775353c Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 22:22:59 +0800 Subject: [PATCH 34/38] =?UTF-8?q?=E6=96=B0=E5=A2=9Esince?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/easyexcel/test/demo/fill/FillTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java index 068045e..48fd9f1 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java @@ -181,7 +181,7 @@ public class FillTest { } /** - * 组合填充填充 + * 多列表组合填充填充 * * @since 2.2.0 */ From 3ef7c198d8cbb928db6d54796e94eddd2592ec31 Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 22:23:15 +0800 Subject: [PATCH 35/38] =?UTF-8?q?=E6=96=B0=E5=A2=9Esince?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/easyexcel/test/demo/fill/FillTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java index 48fd9f1..7a0e92e 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/fill/FillTest.java @@ -183,7 +183,7 @@ public class FillTest { /** * 多列表组合填充填充 * - * @since 2.2.0 + * @since 2.2.0-beta1 */ @Test public void compositeFill() { From d44523d1426e42a790be2eb10b696684048fe7ea Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Tue, 17 Mar 2020 23:17:54 +0800 Subject: [PATCH 36/38] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=9C=80=E9=95=BF?= =?UTF-8?q?=E5=8C=B9=E9=85=8D=E7=AD=96=E7=95=A5=E4=B8=8D=E5=90=8C=E8=A1=A8?= =?UTF-8?q?=E6=A0=BC=E4=BC=9A=E6=9C=89=E5=BD=B1=E5=93=8D=E7=9A=84bug=20#10?= =?UTF-8?q?10?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 2 +- .../style/column/LongestMatchColumnWidthStyleStrategy.java | 6 +++--- update.md | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index 4a47b3d..51f6323 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ 4.0.0 com.alibaba easyexcel - 2.2.0-beta1 + 2.2.0-beta2 jar easyexcel diff --git a/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java b/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java index 5140ae6..cc8dcb2 100644 --- a/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java +++ b/src/main/java/com/alibaba/excel/write/style/column/LongestMatchColumnWidthStyleStrategy.java @@ -24,7 +24,7 @@ public class LongestMatchColumnWidthStyleStrategy extends AbstractColumnWidthSty private static final int MAX_COLUMN_WIDTH = 255; - private static final Map> CACHE = new HashMap>(8); + private Map> cache = new HashMap>(8); @Override protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List cellDataList, Cell cell, Head head, @@ -33,10 +33,10 @@ public class LongestMatchColumnWidthStyleStrategy extends AbstractColumnWidthSty if (!needSetWidth) { return; } - Map maxColumnWidthMap = CACHE.get(writeSheetHolder.getSheetNo()); + Map maxColumnWidthMap = cache.get(writeSheetHolder.getSheetNo()); if (maxColumnWidthMap == null) { maxColumnWidthMap = new HashMap(16); - CACHE.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap); + cache.put(writeSheetHolder.getSheetNo(), maxColumnWidthMap); } Integer columnWidth = dataLength(cellDataList, cell, isHead); if (columnWidth < 0) { diff --git a/update.md b/update.md index 834bee6..0f68032 100644 --- a/update.md +++ b/update.md @@ -1,3 +1,6 @@ +# 2.2.0-beta1 +* 修复最长匹配策略不同表格会有影响的bug [Issue #1010](https://github.com/alibaba/easyexcel/issues/1010) + # 2.2.0-beta1 * 重写主流程,代码更加优雅 * 修复用String接收日期、数字和excel显示不一致的bug(不是完美修复,但是大部分情况已经兼容) From 04883601ed7dc1c74ab85c7397b74f5817ea2f0e Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Wed, 18 Mar 2020 00:00:21 +0800 Subject: [PATCH 37/38] =?UTF-8?q?=E6=96=B0=E5=A2=9Esince?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/alibaba/easyexcel/test/demo/write/WriteTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java index 0a04f89..43c6e68 100644 --- a/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java +++ b/src/test/java/com/alibaba/easyexcel/test/demo/write/WriteTest.java @@ -275,6 +275,8 @@ public class WriteTest { * 1. 创建excel对应的实体对象 参照{@link DemoStyleData} *

* 3. 直接写即可 + * + * @since 2.2.0-beta1 */ @Test public void annotationStyleWrite() { @@ -329,6 +331,8 @@ public class WriteTest { * 2. 创建一个merge策略 并注册 *

* 3. 直接写即可 + * + * @since 2.2.0-beta1 */ @Test public void mergeWrite() { From 0cb24f848a7a5ff1fcbec16d42abb5f08d7e29fa Mon Sep 17 00:00:00 2001 From: Jiaju Zhuang Date: Wed, 18 Mar 2020 00:09:05 +0800 Subject: [PATCH 38/38] =?UTF-8?q?`LinkedList`=E5=86=99=E5=85=A5=E7=9A=84?= =?UTF-8?q?=E6=80=A7=E8=83=BD=E9=97=AE=E9=A2=98=20#1121?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- update.md | 1 + 1 file changed, 1 insertion(+) diff --git a/update.md b/update.md index 0f68032..43dd560 100644 --- a/update.md +++ b/update.md @@ -1,5 +1,6 @@ # 2.2.0-beta1 * 修复最长匹配策略不同表格会有影响的bug [Issue #1010](https://github.com/alibaba/easyexcel/issues/1010) +* `LinkedList`写入的性能问题 #1121 # 2.2.0-beta1 * 重写主流程,代码更加优雅