阿丹:
? ? ? ? 有些業(yè)務(wù)邏輯需要在導(dǎo)出非常大量的數(shù)據(jù),幾百甚至幾千萬的數(shù)據(jù)這個時候再導(dǎo)出excel來對于性能都不是很友好,這個時候就需要替換實現(xiàn)思路來解決這個問題。文章來源:http://www.zghlxwxcb.cn/news/detail-793315.html
? ? ? ? 本文章提供了兩種解決的方案,也是兩種從數(shù)據(jù)庫中拿取數(shù)據(jù)的方式一種是原生的jdbc一種是使用mybatis來封裝對象來完成的。文章來源地址http://www.zghlxwxcb.cn/news/detail-793315.html
使用字符串?dāng)?shù)組的導(dǎo)出:
package com.lianlu.export.util;
import org.apache.poi.ss.formula.functions.T;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
/**
* CSV導(dǎo)出工具類,用于將數(shù)據(jù)列表導(dǎo)出為CSV文件。
*/
public class CSVExportUtil {
/**
* 導(dǎo)出CSV文件。
*
* @param dataList 需要導(dǎo)出的內(nèi)容,類型為字符串?dāng)?shù)組的列表。
* @param validationRulesMap 校驗和替換規(guī)則的映射,鍵為列索引,值為一個映射,其中鍵為需要替換的字符串,值為替換后的字符串。
* @param headers CSV文件的表頭,類型為字符串?dāng)?shù)組。
* @param fileName 導(dǎo)出CSV文件的名稱。
* @throws IOException 如果在寫入文件過程中發(fā)生異常。
*/
public static void exportCSV(List<String[]> dataList, Map<Integer, Map<String, String>> validationRulesMap, String[] headers, String fileName) throws IOException {
// 預(yù)處理數(shù)據(jù)(校驗和替換)
List<String[]> preprocessedDataList = preprocessData(dataList, validationRulesMap);
// 寫入CSV文件
writeCSVToFile(preprocessedDataList, headers, fileName);
}
/**
* 不需要替換規(guī)則的導(dǎo)出
* @param dataList
* @param headers
* @param fileName
* @throws IOException
*/
public static void exportCSV(List<String[]> dataList, String[] headers, String fileName) throws IOException {
// 寫入CSV文件
writeCSVToFile(dataList, headers, fileName);
}
/**
* 預(yù)處理數(shù)據(jù)列表(校驗和替換)。
*
* @param dataList 原始數(shù)據(jù)列表。
* @param validationRulesMap 校驗和替換規(guī)則的映射。
* @return 預(yù)處理后的數(shù)據(jù)列表。
*/
private static List<String[]> preprocessData(List<String[]> dataList, Map<Integer, Map<String, String>> validationRulesMap) {
return dataList.stream()
.map(row -> preprocessDataRow(row, validationRulesMap))
.collect(Collectors.toList());
}
/**
* 預(yù)處理單行數(shù)據(jù)(校驗和替換)。
*
* @param row 單行數(shù)據(jù)。
* @param validationRulesMap 校驗和替換規(guī)則的映射。
* @return 預(yù)處理后的單行數(shù)據(jù)。
*/
private static String[] preprocessDataRow(String[] row, Map<Integer, Map<String, String>> validationRulesMap) {
for (Map.Entry<Integer, Map<String, String>> entry : validationRulesMap.entrySet()) {
int columnIndex = entry.getKey();
Map<String, String> rules = entry.getValue();
String originalValue = row[columnIndex];
String replacedValue = rules.getOrDefault(originalValue, originalValue);
row[columnIndex] = replacedValue;
}
return row;
}
/**
* 將預(yù)處理后的數(shù)據(jù)寫入CSV文件。
*
* @param dataList 預(yù)處理后的數(shù)據(jù)列表。
* @param headers CSV文件的表頭。
* @param fileName 導(dǎo)出CSV文件的名稱。
* @throws IOException 如果在寫入文件過程中發(fā)生異常。
*/
private static void writeCSVToFile(List<String[]> dataList, String[] headers, String fileName) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
// 寫入表頭
writer.write(String.join(",", headers));
writer.newLine();
// 分批寫入數(shù)據(jù)以提高性能
AtomicInteger counter = new AtomicInteger(0);
while (counter.get() < dataList.size()) {
int batchSize = Math.min(10000, dataList.size() - counter.get()); // 每次寫入10000條數(shù)據(jù),可根據(jù)實際需求調(diào)整
List<String[]> batchData = dataList.subList(counter.get(), counter.get() + batchSize);
for (String[] dataRow : batchData) {
writer.write(String.join(",", dataRow));
writer.newLine();
}
counter.addAndGet(batchSize);
}
}
}
/**
* 從泛型對象中獲取屬性值并轉(zhuǎn)換為字符串?dāng)?shù)組。
*
* @param data 泛型對象
* @return 字符串?dāng)?shù)組,包含對象的屬性值
*/
private String[] convertObjectToArray(T data) {
Class<?> clazz = data.getClass();
Field[] fields = clazz.getDeclaredFields();
// 獲取對象的所有字段,并設(shè)置它們?yōu)榭稍L問
for (Field field : fields) {
field.setAccessible(true);
}
String[] rowData = new String[fields.length];
// 遍歷所有字段,獲取每個字段的值并添加到字符串?dāng)?shù)組中
for (int i = 0; i < fields.length; i++) {
try {
rowData[i] = fields[i].get(data).toString();
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access field value", e);
}
}
return rowData;
}
}
通過對象的導(dǎo)出:
package com.lianlu.export.util;
import java.io.*;
import java.lang.reflect.Field;
import java.util.*;
public class CSVExportUtil<T> {
/**
* 導(dǎo)出CSV文件。
*
* @param dataList 需要導(dǎo)出的數(shù)據(jù)列表(泛型對象列表)
* @param validationRulesMap 校驗和替換規(guī)則映射(鍵為列索引,值為校驗和替換規(guī)則的映射)
* @param headers CSV表頭數(shù)組
* @param fileName 導(dǎo)出CSV文件的名稱
* @throws IOException 如果在寫入文件時發(fā)生錯誤
*/
public void exportCSV(List<T> dataList, Map<Integer, Map<String, String>> validationRulesMap, String[] headers, String fileName) throws IOException {
// 預(yù)處理數(shù)據(jù)(校驗和替換)
List<String[]> preprocessedData = preprocessData(dataList, validationRulesMap);
// 寫入CSV文件
writeCSV(preprocessedData, headers, fileName);
}
/**
* 預(yù)處理數(shù)據(jù)(校驗和替換)。
*
* @param dataList 數(shù)據(jù)列表(泛型對象列表)
* @param validationRulesMap 校驗和替換規(guī)則映射(鍵為列索引,值為校驗和替換規(guī)則的映射)
* @return 預(yù)處理后的數(shù)據(jù)(字符串?dāng)?shù)組列表)
*/
private List<String[]> preprocessData(List<T> dataList, Map<Integer, Map<String, String>> validationRulesMap) {
List<String[]> preprocessedData = new ArrayList<>(dataList.size());
for (T data : dataList) {
String[] rowData = convertObjectToArray(data);
preprocessedData.add(validateAndReplace(rowData, validationRulesMap));
}
return preprocessedData;
}
/**
* 從泛型對象中獲取屬性值并轉(zhuǎn)換為字符串?dāng)?shù)組。
*
* @param data 泛型對象
* @return 字符串?dāng)?shù)組,包含對象的屬性值
*/
private String[] convertObjectToArray(T data) {
Class<?> clazz = data.getClass();
Field[] fields = clazz.getDeclaredFields();
// 獲取對象的所有字段,并設(shè)置它們?yōu)榭稍L問
for (Field field : fields) {
field.setAccessible(true);
}
String[] rowData = new String[fields.length];
// 遍歷所有字段,獲取每個字段的值并添加到字符串?dāng)?shù)組中
for (int i = 0; i < fields.length; i++) {
try {
rowData[i] = fields[i].get(data).toString();
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to access field value", e);
}
}
return rowData;
}
/**
* 根據(jù)提供的校驗和替換規(guī)則對字符串?dāng)?shù)組進(jìn)行校驗和替換。
*
* @param rowData 字符串?dāng)?shù)組
* @param rulesMap 校驗和替換規(guī)則映射(鍵為列索引,值為校驗和替換規(guī)則的映射)
* @return 校驗和替換后的字符串?dāng)?shù)組
*/
private String[] validateAndReplace(String[] rowData, Map<Integer, Map<String, String>> rulesMap) {
for (Map.Entry<Integer, Map<String, String>> entry : rulesMap.entrySet()) {
int columnIndex = entry.getKey();
Map<String, String> ruleMap = entry.getValue();
String currentValue = rowData[columnIndex];
if (ruleMap.containsKey(currentValue)) {
rowData[columnIndex] = ruleMap.get(currentValue);
}
}
return rowData;
}
/**
* 將預(yù)處理后的數(shù)據(jù)寫入CSV文件。
*
* @param preprocessedData 預(yù)處理后的數(shù)據(jù)(字符串?dāng)?shù)組列表)
* @param headers CSV表頭數(shù)組
* @param fileName 導(dǎo)出CSV文件的名稱
* @throws IOException 如果在寫入文件時發(fā)生錯誤
*/
private void writeCSV(List<String[]> preprocessedData, String[] headers, String fileName) throws IOException {
try (BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))) {
CSVWriter csvWriter = new CSVWriter(writer);
// 寫入表頭
csvWriter.writeNext(headers);
// 寫入數(shù)據(jù)
csvWriter.writeAll(preprocessedData);
csvWriter.close();
}
}
}
到了這里,關(guān)于大批量數(shù)據(jù)導(dǎo)出csv,平替導(dǎo)出excel性能優(yōu)化解決方案封裝工具類的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!