Excel2003–公式重新計算問題
需求描述
有個30M的Excel需要導出,其中一個SHEET叫做s1用來做數據輸入,其他的SHEET引用s1的數據進行操作,涉及到公式的計算。
解決方案
1,其他SHEET的公式不自動計算
在excel下載之前,再重新計算一遍。當時沒有什麼好辦法,甚至想到用VBA來解決。
發現poi自帶的函數
HSSFWorkbook fWorkbook = new HSSFWorkbook(fileInput);
fWorkbook.setForceFormulaRecalculation(true); //強制重新計算
poi版本
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.14</version>
</dependency>
2,圖片處理
Excel中對圖片的簡單理解就是:圖片是矩形的,直接確定對角的兩個座標,就確定了圖片的位置。
圖片一個點的座標由兩部分組成:單元格的位置+某個點在該單元格的相對座標,一共四個數字。也就是說確定一個圖片要8個數字。
HSSFSheet autoPicture = fWorkbook.getSheet("sheet1"); //根據SHEET的名字獲得SHEET
HSSFPatriarch autoPicturePaneContainer = autoPicture.createDrawingPatriarch();
//看名字是創建一個圖片的容器,這樣的只能創建一次。
HSSFClientAnchor pl =
new HSSFClientAnchor(64, 0, 923, 0, (short) 2, 3, (short) 8, 42); //圖片的
autoPicturePaneContainer.createPicture(pl, fWorkbook.addPicture(getResourcesByteArray(tst), HSSFWorkbook.PICTURE_TYPE_JPEG));
這個東西網上比較多,就不多少說了!
但是這樣做是處理不了問題的,比如多個SHEET有多處引用圖片,每次更改位置都要重新修改代碼,或者做一次初始化。
考慮這樣一個解決方案【證實可用】:
使用Excel本身的功能—-Excel圖片引用!就像單元格值引用一樣。
修改SHEET2中A2單元格的內容就可以在圖片控件中看到A2單元格內的圖片,解決Excel處理複雜的問題。
3,單元格賦值
不用考慮直接賦值的問題,就是說直接定位A1賦值。一旦Excel結構發生變化,就需要調整代碼或者配置文件。
現提供一個解決方案:
標記我們要賦值的單元格,確定該單元格後給正確的值。
具體實現:
a.定義一套標記語法,個人覺得EL表達式就不錯。eg.#{name} or #{s.name}
b.從SHEET中篩選出我們標記的單元格。
c.給符合的單元格賦值
注意:
1,遍歷某個單元格時,可能遍歷所有,應該只遍歷有值得單元格
2,獲取單元格的值時,注意單元格的類型
3,篩選時獲得了單元格的值,可以考慮使用正則表達式提取花括號裏面的值
4,賦值的時候可以考慮設置單元格的類型爲文本直接強轉賦值
5,在這裏囉嗦一下,獲得name,可以想一下。
比如name可以是某個對象的屬性,或者某個map的key
說道這裏推薦大家使用JEXL3
https://commons.apache.org/proper/commons-jexl/
這個東西
使用正則表達式取值,然後賦值
private static final Pattern P_EXPRESSION = Pattern.compile("\\$\\{([^\\}]+)\\}");
private String tryEvaluateValue(String value, JexlContext jc) {
//value 單元格的值
if (value == null) {
return null;
}
Matcher m = P_EXPRESSION.matcher(value);//正則篩選
if (!m.find()) {
return null;
}
StringBuffer sb = new StringBuffer();
do {
String express = m.group(1);
JexlExpression e = jexl.createExpression(express);
Object o = e.evaluate(jc);
m.appendReplacement(sb, o == null ? "" : String.valueOf(o));
} while (m.find());
m.appendTail(sb);
return sb.toString();
}