Browse Source

新增交叉表(二维表、透视表)导出辅助工具类

pull/3609/head
phaeris 1 year ago
parent
commit
4f9a51f75e
  1. 132
      easyexcel-core/src/main/java/com/alibaba/excel/util/PivotUtils.java
  2. 91
      easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/pivot/PivotTest.java

132
easyexcel-core/src/main/java/com/alibaba/excel/util/PivotUtils.java

@ -0,0 +1,132 @@
package com.alibaba.excel.util;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.math3.util.Pair;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author phaeris
* @since 2023/12/15
*/
public class PivotUtils {
private PivotUtils() {}
/**
* get pivot table head and data
*
* @param rowFields pivot row fields
* @param columnFields pivot column fields
* @param aggFields aggregator fields
* @param data original data
* @return head & data
*/
public static Pair<List<List<String>>, List<List<Object>>> getHeadAndData(List<String> rowFields, List<String> columnFields, List<String> aggFields,
List<Map<String, Object>> data) {
return getHeadAndData(rowFields, columnFields, aggFields, null, data);
}
/**
* get pivot table head and data
*
* @param rowFields pivot row fields
* @param columnFields pivot column fields
* @param aggFields aggregator fields
* @param alias alias mapping
* @param data original data
* @return head & data
*/
public static Pair<List<List<String>>, List<List<Object>>> getHeadAndData(List<String> rowFields, List<String> columnFields, List<String> aggFields,
Map<String, String> alias, List<Map<String, Object>> data) {
//current row size empty data
final List<Object> emptyRowData = rowFields.stream().map(x -> null).collect(Collectors.toList());
//current column size empty data
final List<Object> emptyColData = columnFields.stream().map(x -> null).collect(Collectors.toList());
//left top head
List<List<String>> centerHeadPart = rowFields.stream().map(col -> {
List<String> centerHead = new ArrayList<>(columnFields);
centerHead.add(col);
return centerHead;
}).collect(Collectors.toList());
//aggregator head
List<List<String>> aggHeadPart = Lists.newArrayList();
//data init, fill row data
Map<List<Object>, List<Object>> dataList = data.stream()
.map(row -> getGroup(row, rowFields, emptyRowData))
.distinct()
.collect(Collectors.toMap(x -> x, ArrayList::new, (o, n) -> n, LinkedHashMap::new));
//original data group by columns
Map<List<Object>, List<Map<String, Object>>> groupByCols = data.stream()
.collect(Collectors.groupingBy(row -> getGroup(row, columnFields, emptyColData), LinkedHashMap::new, Collectors.toList()));
//fill aggregator head and data
for (Map.Entry<List<Object>, List<Map<String, Object>>> eachColData : groupByCols.entrySet()) {
//each column head
List<String> colHead = eachColData.getKey().stream()
.map(x -> Objects.isNull(x) ? StringUtils.EMPTY : String.valueOf(x))
.collect(Collectors.toList());
//each col data group by row
Map<List<Object>, List<Map<String, Object>>> groupByRows = eachColData.getValue()
.stream()
.collect(Collectors.groupingBy(x -> getGroup(x, rowFields, emptyRowData)));
//aggregator head nums: column data size * aggregator nums
for (String aggField : aggFields) {
//col head
List<String> copyColHead = new ArrayList<>(colHead);
copyColHead.add(aggField);
aggHeadPart.add(copyColHead);
//this col all data for each row
dataList.forEach((originalRowData, finalRowData) -> {
List<Map<String, Object>> curRowData = groupByRows.get(originalRowData);
if (curRowData != null && !curRowData.isEmpty()) {
//group by column and row, get first
finalRowData.add(curRowData.get(0).get(aggField));
} else {
//no match, fill empty
finalRowData.add(null);
}
});
}
}
//merge and replace alias head
centerHeadPart.addAll(aggHeadPart);
List<List<String>> head = centerHeadPart.stream()
.map(x -> x.stream().map(c -> getAlias(alias, c)).collect(Collectors.toList()))
.collect(Collectors.toList());
return Pair.create(head, new ArrayList<>(dataList.values()));
}
/**
* get group
*
* @param row row data
* @param fields fields
* @param emptyData or else empty data object
* @return group
*/
private static List<Object> getGroup(Map<String, Object> row, List<String> fields, List<Object> emptyData) {
List<Object> dataList = fields.stream()
.map(row::get)
.collect(Collectors.toList());
List<Object> nonNull = dataList.stream().filter(Objects::nonNull).collect(Collectors.toList());
return nonNull.isEmpty() ? emptyData : dataList;
}
/**
* get head alias
*
* @param alias alias mapping
* @param field field
* @return alias of field
*/
private static String getAlias(Map<String, String> alias, String field) {
return alias != null && !alias.isEmpty() && StringUtils.isNotBlank(alias.get(field))
? alias.get(field)
: field;
}
}

91
easyexcel-test/src/test/java/com/alibaba/easyexcel/test/core/pivot/PivotTest.java

@ -0,0 +1,91 @@
package com.alibaba.easyexcel.test.core.pivot;
import com.alibaba.excel.EasyExcelFactory;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.util.ListUtils;
import com.alibaba.excel.util.PivotUtils;
import com.alibaba.excel.write.metadata.WriteSheet;
import org.apache.commons.math3.util.Pair;
import org.junit.jupiter.api.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author phaeris
* @since 2023/12/15
*/
@SuppressWarnings("unchecked")
public class PivotTest {
private static final String EXPORT_FILE_PATH = "C:\\Users\\A11-9\\Desktop\\excel\\pivot.xlsx";
private static final String SHEET_NAME = "pivot";
public static final List<String> ROW_FIELDS = ListUtils.newArrayList("address");
public static final List<String> COLUMN_FIELDS = ListUtils.newArrayList("name", "phone");
public static final List<String> AGG_FIELDS = ListUtils.newArrayList("age", "height");
private static final Map<String, String> ALIAS;
private static final List<Map<String, Object>> DATA;
static {
Map<String, Object> row1 = new HashMap<>();
row1.put("address", "上海");
row1.put("name", "张三");
row1.put("phone", "110");
row1.put("age", "18");
row1.put("height", "170");
Map<String, Object> row2 = new HashMap<>();
row2.put("address", "上海");
row2.put("name", "李四");
row2.put("phone", "120");
row2.put("age", "19");
row2.put("height", "173");
Map<String, Object> row3 = new HashMap<>();
row3.put("address", "北京");
row3.put("name", "王五");
row3.put("phone", "119");
row3.put("age", "22");
row3.put("height", "175");
Map<String, Object> row4 = new HashMap<>();
row4.put("address", "北京");
row4.put("name", "赵六");
row4.put("phone", "114");
row4.put("age", "30");
row4.put("height", "180");
DATA = ListUtils.newArrayList(row1, row2, row3, row4);
Map<String, String> alias = new HashMap<>();
alias.put("name", "姓名");
alias.put("phone", "手机号");
alias.put("address", "地址");
alias.put("age", "年龄");
alias.put("height", "身高");
ALIAS = alias;
}
@Test
void testExportPivot() {
Pair<List<List<String>>, List<List<Object>>> headAndData = PivotUtils.getHeadAndData(ROW_FIELDS, COLUMN_FIELDS, AGG_FIELDS, DATA);
write(headAndData);
}
@Test
void testExportPivotHaveAlias() {
Pair<List<List<String>>, List<List<Object>>> headAndData = PivotUtils.getHeadAndData(ROW_FIELDS, COLUMN_FIELDS, AGG_FIELDS, ALIAS, DATA);
write(headAndData);
}
private void write(Pair<List<List<String>>, List<List<Object>>> headAndData) {
ExcelWriter writer = EasyExcelFactory.write(EXPORT_FILE_PATH).build();
WriteSheet sheet = EasyExcelFactory.writerSheet(SHEET_NAME)
.head(headAndData.getKey())
.build();
writer.write(headAndData.getValue(), sheet);
writer.finish();
}
}
Loading…
Cancel
Save