業務場景
由於業務需要導出如下圖中訂單數據和訂單項信息,而一個訂單對應多個訂單項,所以會涉及到自定義合併行
1.簡單處理
項目使用的EasyExcel,經查找發現Excel種有個AbstractMergeStrategy抽象類,可以用於合併單元格。
於是先簡單的寫一個工具類實現根據數據自定義合併單元行,基本思路是獲取當前單元格內容和上一行的單元格內容比對,如果相同則添加合併區域,如果不同則不處理,如果上一個單元格在合併區域中,則先移除合併區域再將當前單元格添加到合併區域中。
2.優化數據顯示
第一個版本上線後財務反饋數據有問題。如圖,求和數值實際應該是45,但是顯示爲90,導致財務不好對賬
z
經排查發現圖中C3、C5單元格雖然已經合併了,但是數據仍然存在,導致下拉選中的時候將他們的值也計算進去了。於是在1.0的基礎上調整,將合併單元格僅保留首行數據,其他行內容直接清空
3.優化合並策略
第二版上線後數據問題已經解決,但是財務反饋導出大量數據時太慢。本來打算調整爲異步導出解決此問題,但是經過測試發現10000條數據如果不合並直接生成excel只要幾秒,但是使用合併自定義合併策略就非常慢,需要一二十分鐘,這個時間差大的太離譜了,於是查看合併策略代碼有哪些地方可以優化的。
經過查看代碼可以發現在上述2.1步驟中一直查找合併單元格數據,然後一直刪除再新增。假設10000條數據,有3列需要自動合併,每三行合併,執行以上代碼會執行6666✖️3次新增和3333✖️3次刪除,大大的影響了效率。於是調整代碼,處理數據時只保存需要合併的單元格信息,導出完成再統一添加合併信息到sheet
經過測試,原本生成文件需要20分鐘左右,現優化到只需要20多秒了。
工具類
/**
* excel線程上下文.
*
*/
public class ExcelThreadContext {
private static final ThreadLocal<Map<String, Object>> THREAD_LOCAL = ThreadLocal.withInitial(HashMap::new);
public static void clear() {
THREAD_LOCAL.remove();
}
public static void setData(String key, Object value) {
Map<String, Object> map = get();
map.put(key, value);
}
public static Integer getInteger(String key) {
return getInteger(key, 1);
}
public static Integer getInteger(String key, Integer defaultValue) {
Map<String, Object> map = get();
return Convert.toInt(map.get(key), defaultValue);
}
public static <K, V> Map<K, V> getMap(String key) {
return getMap(key, new HashMap<>());
}
public static <K, V> Map<K, V> getMap(String key, Map<K, V> defaultValue) {
Map<String, Object> map = get();
try {
return (Map<K, V>) map.getOrDefault(key, defaultValue);
} catch (Exception e) {
return defaultValue;
}
}
public static <T> T getObject(String key) {
return getObject(key, null);
}
public static <T> T getObject(String key, T defaultValue) {
Map<String, Object> map = get();
try {
return (T) map.getOrDefault(key, defaultValue);
} catch (Exception e) {
return defaultValue;
}
}
private static void set(Map<String, Object> map) {
THREAD_LOCAL.set(map);
}
public static Map<String, Object> get() {
return THREAD_LOCAL.get();
}
}
因爲數據是存儲在線程中的,需要每次使用後清理線程數據