Теперь нам нужно изменить функцию экспорта данных списка в таблицу Excel, чтобы те же данные в указанном столбце можно было автоматически объединять в ячейки.
Как показано на рисунке выше, укажите два столбца A и B для автоматического объединения. Как показано на рисунке (6, 7), (8, 9), (13, 14, 15), ячейки должны быть автоматически объединены. слились.
EasyExcel — это быстрый и лаконичный инструмент обработки Excel на основе Java, который устраняет переполнение памяти больших файлов. Он позволяет быстро выполнять чтение, запись и другие функции Excel без учета таких факторов, как производительность и память.
EasyExcel имеет лучший алгоритм управления потреблением памяти, чем другие платформы синтаксического анализа Excel (Apache poi и jxl). Специально для версии Excel 07 EasyExcel переписывает базовую логику синтаксического анализа. Для синтаксического анализа 3M Excel требуется всего несколько МБ памяти, но для синтаксического анализа poi может потребоваться около 100 МБ памяти. EasyExcel имеет улучшенную производительность чтения. Он может прочитать 75 МБ Excel за 20 секунд с памятью 64 МБ. Существует также более быстрый режим экстремальной скорости, но он потребляет больше памяти.
EasyExcel поддерживает пользовательские стратегии объединения ячеек, которые позволяют быстро и легко заполнять данные в шаблонах. Он имеет активную поддержку китайского сообщества и полные тестовые примеры, которые могут охватывать большинство бизнес-сценариев.
Пример кода для экспорта Excel с помощью EasyExcel:
@Test
public void testWrite() throws IOException {
List<DemoMergeData> resultList = new ArrayList<>();
resultList.add(DemoMergeData.builder().id(1).sub("Чжан Шэннань").date("12").build()); resultList.add(DemoMergeData.builder().id(1).sub("Джон Доу").date("224").build()); resultList.add(DemoMergeData.builder().id(3).sub("Ван Ву").date("224").build()); resultList.add(DemoMergeData.builder().id(4).sub("Чжао Лю").date("224").build()); resultList.add(DemoMergeData.builder().id(5).sub("Чжао Лю").date("224").build()); resultList.add(DemoMergeData.builder().id(5).sub("Чжао Лю").date("224").build()); resultList.add(DemoMergeData.builder().id(8).sub("Чжао Лю").date("224").build()); resultList.add(DemoMergeData.builder().id(8).sub("Чжао Лю").date("224").build()); resultList.add(DemoMergeData.builder().id(9).sub("Чэнь Ци").date("224").build()); resultList.add(DemoMergeData.builder().id(10).sub("нуб").date("241").build()); resultList.add(DemoMergeData.builder().id(11).sub("Сяохэй").date("241").build()); resultList.add(DemoMergeData.builder().id(12).sub("Сяохэй").date("241").build()); resultList.add(DemoMergeData.builder().id(12).sub("Сяохэй").date("241").build()); resultList.add(DemoMergeData.builder().id(12).sub("Сяохэй").date("241").build()); resultList.add(DemoMergeData.builder().id(13).sub("Сяохэй").date("241").build()); // Установить имя файла
String fileName = "C:\\Users\\Administrator\\Downloads\\test\\t1.xlsx";
File file = new File(fileName);
if (!file.exists()) {
file.createNewFile();
}
// имя листа
EasyExcel.write(fileName, DemoMergeData.class)
.autoCloseStream(Boolean.TRUE)
.sheet("Экспорт теста").doWrite(resultList);
}
Экспортировать стиль таблицы:
Пример кода собственной стратегии:
public class ExcelFillCellMergeStrategy implements CellWriteHandler {
private int[] mergeColumnIndex;
private int mergeRowIndex;
public ExcelFillCellMergeStrategy() {
}
public ExcelFillCellMergeStrategy(int mergeRowIndex, int[] mergeColumnIndex) {
this.mergeRowIndex = mergeRowIndex;
this.mergeColumnIndex = mergeColumnIndex;
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {
//Текущая строка
int curRowIndex = cell.getRowIndex();
//Текущий столбец
int curColIndex = cell.getColumnIndex();
if (curRowIndex > mergeRowIndex) {
for (int columnIndex : mergeColumnIndex) {
if (curColIndex == columnIndex) {
mergeWithPrevRow(writeSheetHolder, cell, curRowIndex, curColIndex);
break;
}
}
}
}
/**
* Объединить текущие ячейки вверх
*
* @param cell текущая ячейка
* @param curRowIndex текущая строка
* @param curColIndex текущий столбец
*/
private void mergeWithPrevRow(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex) {
//получатьтекущая строкаизтекущий столбецизданные и предыдущая строкаизтекущий данные столбца столбец,Объединение на основе того, совпадают ли данные в предыдущей строке.
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
Cell preCell = cell.getSheet().getRow(curRowIndex - 1).getCell(curColIndex);
Object preData = preCell.getCellTypeEnum() == CellType.STRING ? preCell.getStringCellValue() : preCell.getNumericCellValue();
// Сравниватьтекущая строкаизпервый столбециз Ячейка такая же, как предыдущая строка?,То же слияние текущая ячейка с предыдущей строкой
if (curData.equals(preData)) {
Sheet sheet = writeSheetHolder.getSheet();
List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
boolean isMerged = false;
for (int i = 0; i < mergeRegions.size() && !isMerged; i++) {
CellRangeAddress cellRangeAddr = mergeRegions.get(i);
// Если предыдущая ячейка была объединена, сначала удалите исходную объединенную единицу, а затем снова добавьте объединенную единицу.
if (cellRangeAddr.isInRange(curRowIndex - 1, curColIndex)) {
sheet.removeMergedRegion(i);
cellRangeAddr.setLastRow(curRowIndex);
sheet.addMergedRegion(cellRangeAddr);
isMerged = true;
}
}
// Если предыдущая ячейка не была объединена, добавьте новую объединенную ячейку.
if (!isMerged) {
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex - 1, curRowIndex, curColIndex, curColIndex);
sheet.addMergedRegion(cellRangeAddress);
}
}
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
}
Пример тестового кода:
@Test
public void testWrite() throws IOException {
int[] mergeColumnIndex = {0,1};
// С какой строки нужно начинать слияние?
int mergeRowIndex = 1;
// Данные не инициализируются.
List<DemoMergeData> resultList = new ArrayList<>();
// Установить имя файла
String fileName = "C:\\Users\\Administrator\\Downloads\\test\\t1.xlsx";
File file = new File(fileName);
if (!file.exists()) {
file.createNewFile();
}
// имя листа
EasyExcel.write(fileName, DemoMergeData.class)
.autoCloseStream(Boolean.TRUE)
.registerWriteHandler(new ExcelFillCellMergeStrategy(mergeRowIndex,mergeColumnIndex))
.sheet("Экспорт теста").doWrite(resultList);
}
Стиль экспорта:
Пример кода пользовательской стратегии 2:
public class MultiColumnMergeStrategy extends AbstractMergeStrategy {
// Номер объединенного столбца, начиная с 0, заданного индекса или пронумерован в порядке полей.
private Integer startCellIndex = 0;
private Integer endCellIndex = 0;
// Размер набора данных, используемый для различения конечной позиции строки.
private Integer maxRow = 0;
// Операторы без параметров запрещены.
private MultiColumnMergeStrategy() {
}
public MultiColumnMergeStrategy(Integer maxRow, Integer startCellIndex, Integer endCellIndex) {
this.startCellIndex = startCellIndex;
this.endCellIndex = endCellIndex;
this.maxRow = maxRow;
}
// Запишите информацию о последнем слиянии
private final List<List<String>> dataList = new ArrayList<>();
/**
* Будут введены каждая строка и столбец. Обратите внимание на условные ограничения в цикле.
*/
@Override
protected void merge(Sheet sheet, Cell cell, Head head, int relativeRowIndex) {
int currentCellIndex = cell.getColumnIndex();
int currentRowIndex = cell.getRowIndex();
// Определите, нужно ли объединить столбец
if (currentCellIndex < startCellIndex || currentCellIndex > endCellIndex) {
return;
}
Object curData = cell.getCellTypeEnum() == CellType.STRING ? cell.getStringCellValue() : cell.getNumericCellValue();
String currentCellValue = curData.toString();
List<String> rowList;
if (dataList.size() > currentRowIndex - 1) {
rowList = dataList.get(currentRowIndex - 1);
} else {
rowList = new ArrayList<>();
dataList.add(rowList);
}
rowList.add(currentCellValue);
// Конечная позиция запускает последнее незавершенное слияние.
if (relativeRowIndex == (maxRow - 1) && currentCellIndex == endCellIndex) {
System.out.println(JSONObject.toJSONString(dataList));
List<String> tempList = null;
Integer tempIndex = null;
for (int i = 0; i < dataList.size(); i++) {
if (tempList == null) {
tempList = dataList.get(i);
tempIndex = i;
continue;
}
List<String> currList = dataList.get(i);
if (tempList.equals(currList)) {
if (i >= dataList.size() - 1) {
// Конечная позиция запускает последнее незавершенное слияние.
for (int j = 0; j < tempList.size(); j++) {
sheet.addMergedRegionUnsafe(new CellRangeAddress(tempIndex + 1, i + 1, startCellIndex + j, startCellIndex + j));
}
}
continue;
}
// текущая Слияние запускается, когда данные строки отличаются от предыдущей строки данных и выше имеется несколько строк одинаковых данных.
if (i - tempIndex > 1) {
for (int j = 0; j < tempList.size(); j++) {
sheet.addMergedRegionUnsafe(new CellRangeAddress(tempIndex + 1, i, startCellIndex + j, startCellIndex + j));
}
}
tempIndex = i;
tempList = currList;
}
}
}
}
Пример тестового кода:
@Test
public void testWrite() throws IOException {
// Данные не инициализируются.
List<DemoMergeData> resultList = new ArrayList<>();
// Установить имя файла
String fileName = "C:\\Users\\Administrator\\Downloads\\test\\t1.xlsx";
File file = new File(fileName);
if (!file.exists()) {
file.createNewFile();
}
// имя листа
EasyExcel.write(fileName, DemoMergeData.class)
.autoCloseStream(Boolean.TRUE)
.registerWriteHandler(new MultiColumnMergeStrategy(resultList.size(),0,1))
.sheet("Экспорт теста").doWrite(resultList);
}
Стиль экспорта:
EasyExcel — это гибкий и мощный инструмент. Вы можете настроить стиль в соответствии со своими бизнес-сценариями, а также использовать функцию заполнения шаблонов для выполнения сложных функций, таких как экспорт международных языков.