POI/Excel/HTML單元格公式問題

一、問題描述

使用MyBatis從數據庫中獲取數據,然後用POI把數據填充到Excel模板中,生成最終的xls文件。把最終的xls文件轉換爲html文件,並返回給前臺顯示在Panel中。

Excel模板中,除了數據點位符外,還有一些計算公式。由於這些計算公式引用的數據在模板中是點位符,所以計算單元顯示爲「#VALUE!」。見下圖:

clip_image001

生成Excel文件,在添加了重算的相關代碼(見下文)後,計算單元格的值能夠正常顯示。轉換爲html後,這些計算單元格不會重新計算,仍然顯示爲「#VALUE!」。

 

二、問題分析

這個問題一直存在了兩週左右,期間斷斷續續地花了一些時間研究,但問題沒有得到解決。

這種使用第三方組件導致的問題,排查起來比較困難。在網上搜索了一大圈,沒有發現對類似問題的描述。有一些關於使用POI重新計算Excel單元格公式的內容可參考。

下載了POI 3.11相關的源代碼,在本機架設了測試環境,進行跟蹤調試。發現是ExcelToHtmlConverter類中,在獲取含有公式的單元格的CachedFormulaResultType時,總是返回Cell.CELL_TYPE_ERROR,導致該方法只能通過cell.getErrorCellValue()獲取單元格的值(就是#VALUE!)並返回。

clip_image002

看了一下相關的源代碼,POI把_record等屬性設置爲private,調用時無法修改。又在網上搜索了一番,更加沒有什麼有參考價值的信息。

 

三、問題解決

在用Excel打開並關閉填充數據後生成的xls文件時,Excel總是會提示是否要保存,但實際上沒有進行任何的修改。如果「保存」這個模板,再生成html,單元格公式會計算,顯示正常。總是感覺POI生成的xls文件實際上還是有兼容性問題,但MS在Office2007以前並沒有開發相關文件的格式及說明,所以也怪不到POI。

生成Excel後,重新對公式單元格進行計算:

clip_image003

【僅僅setForceFormulaRecalculation(Boolean.TRUE)在轉換爲html時是無效的】

正式工程和一開始的測試代碼中,取數生成Excel、轉換爲html是寫在一個function中的。在測試中感覺不是太方便。於是就把生個Excel、轉爲html拆分爲兩個function,以便於控制是否重新生成Excel。沒想到拆分完一運行測試代碼,html中的計算單元竟然有值了!簡直是簡直了!

然後把正式工程中的代碼也拆分了一下,這個讓人抓狂的問題,就以這種無厘頭的方式解決了。

 

四、問題總結

在同一個方法裏進行生成xls文件、轉換爲html有問題,拆分爲兩個方法後就沒有問題。這種現象是比較怪異的,應該還是代碼層面存在問題。暫時就不再深究了。