一、EasyExcel
EasyExcel 是一个为了简化 Excel 操作,而封装的一个 Java 工具库。它可以帮助我们以最快的速度读取或者写入 Excel 文件。
二、示例
1. 准备模板
- 在模板中占位符用
{变量}表示,比如{deptName}、{groupName} - 如果占位符为列表,则使用
{.变量}表示,比如:{.deptName}、{.groupName} - 官方文档:填充Excel
首先准备一个Excel模板文件:template.xlsx,当前我们使用占位符为列表的场景,设置两个Sheet页内容。
Sheet1:
| 部门 | 群组 | 人员 | 性别 |
| {.deptName} | {.groupName} | {.userName} | {.sex} |
Sheet2:
| 部门 | 群组 | 人员 | 性别 |
| {.deptName} | {.groupName} | {.userName} | {.sex} |
2. 模板使用
新建Java Maven项目,将模板文件放在 resources 下。
pom.xml 文件引入相关依赖:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.13.3</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>4.0.1</version>
</dependency>
JAVA版本使用的是JDK11。
3. 数据获取
当前示例数据为虚拟数据,若要从数据库获取需要增加额外逻辑。
增加方法:getSheet1Data 、getSheet2Data
其中 getSheet2Data 方法中对 deptName 和 groupName 字段做了升序。
public static List<Map<String, String>> getSheet1Data() {
List<Map<String, String>> dataList = new ArrayList<>();
Map<String, String> map1 = new HashMap<>();
map1.put("deptName", "研发一部");
map1.put("groupName", "小组1");
map1.put("userName", "XX1");
map1.put("sex", "男");
Map<String, String> map2 = new HashMap<>();
map2.put("deptName", "研发一部");
map2.put("groupName", "小组1");
map2.put("userName", "XX2");
map2.put("sex", "女");
dataList.add(map1);
dataList.add(map2);
return dataList;
}
public static List<Map<String, String>> getSheet2Data() {
List<Map<String, String>> dataList = new ArrayList<>();
Map<String, String> map1 = new HashMap<>();
map1.put("deptName", "研发一部");
map1.put("groupName", "一部小组1");
map1.put("userName", "自来也");
map1.put("sex", "男");
Map<String, String> map2 = new HashMap<>();
map2.put("deptName", "研发二部");
map2.put("groupName", "二部小组1");
map2.put("userName", "雏田");
map2.put("sex", "女");
Map<String, String> map3 = new HashMap<>();
map3.put("deptName", "研发二部");
map3.put("groupName", "二部小组1");
map3.put("userName", "小樱");
map3.put("sex", "女");
Map<String, String> map4 = new HashMap<>();
map4.put("deptName", "研发一部");
map4.put("groupName", "一部小组2");
map4.put("userName", "鸣人");
map4.put("sex", "男");
Map<String, String> map5 = new HashMap<>();
map5.put("deptName", "研发一部");
map5.put("groupName", "一部小组2");
map5.put("userName", "佐助");
map5.put("sex", "男");
Map<String, String> map6 = new HashMap<>();
map6.put("deptName", "研发三部");
map6.put("groupName", "三部小组");
map6.put("userName", "拓海");
map6.put("sex", "男");
dataList.add(map1);
dataList.add(map2);
dataList.add(map3);
dataList.add(map4);
dataList.add(map5);
dataList.add(map6);
// deptName 和 groupName 升序
dataList.sort(Comparator
.comparing((Map<String, String> map) -> map.get("deptName"))
.thenComparing((Map<String,String> map) -> map.get("groupName")));
return dataList;
}
4. 数据填充并导出
数据填充方法 :fillDataExp
入参说明:
sheet1Data : 第一个sheet填充所需数据;
sheet2Data : 第二个sheet填充所需数据;
expExcelName : 数据导出Excel名称;
outFilePath : Excel导出路径。
public static void fillDataExp(List<Map<String,String>> sheet1Data, List<Map<String,String>> sheet2Data, String expExcelName, String outFilePath){
String templateFile = System.getProperty("user.dir") + "/src/main/resources/template.xlsx";
FileUtil.buildFilePath(outFilePath);
String outFile = outFilePath + expExcelName;
ExcelWriter writer = EasyExcel
.write(outFile)
.withTemplate(templateFile)
.build();
WriteSheet firstSheet = EasyExcel.writerSheet(0).build();
WriteSheet secondSheet = EasyExcel.writerSheet(1).build();
FillConfig fillConfig = FillConfig.builder()
// 开启填充行 不开启是在一行覆盖,开启会创建新的行
.forceNewRow(true)
.build();
// 执行填充操作
writer.fill(sheet1Data, fillConfig, firstSheet);
writer.fill(sheet2Data, fillConfig, secondSheet);
writer.finish();
}
5. 单元格合并
单元格合并实现逻辑是遍历集合数据解析出要合并的下标值集合,再通过 Apache POI 组件读取Excel文件进行单元格合并。
代码如下:
public static void mergeExcel(List<Map<String,String>> dataList, String outFilePath){
LinkedMap<String, Integer> deptMap = new LinkedMap<>();
LinkedMap<String, Integer> groupMap = new LinkedMap<>();
String lastValue = "";
int groupIndex = 0;
int groupCount = 1;
for(Map<String, String> map : dataList) {
String deptName = map.get("deptName");
String groupName = map.get("groupName");
deptMap.put(deptName, deptMap.getOrDefault(deptName, 0) + 1);
if(!"".equals(lastValue) && groupName.equals(lastValue)){
groupCount++;
groupMap.put(groupIndex + groupName, groupCount);
} else {
groupIndex++;
groupCount = 1;
groupMap.put(groupIndex + groupName, groupCount);
lastValue = groupName;
}
}
List<String> deptNameCellRangeList = new ArrayList<>();
List<String> groupNameCellRangeList = new ArrayList<>();
int initDeptNameRowINdex = 1; // 刨去标题行
int initGroupNameRowINdex = 1; // 刨去标题行
for (Map.Entry<String, Integer> entry: deptMap.entrySet()) {
logger.info(entry.getKey() + ":" + entry.getValue());
int cellRangeRow = initDeptNameRowINdex + entry.getValue() -1;
deptNameCellRangeList.add(initDeptNameRowINdex + "-" + cellRangeRow);
initDeptNameRowINdex = cellRangeRow + 1;
}
for (Map.Entry<String, Integer> entry: groupMap.entrySet()) {
logger.info(entry.getKey() + ":" + entry.getValue());
int cellRangeRow = initGroupNameRowINdex + entry.getValue() -1;
groupNameCellRangeList.add(initGroupNameRowINdex + "-" + cellRangeRow);
initGroupNameRowINdex = cellRangeRow + 1;
}
try {
// 使用Apache POI合并单元格
FileInputStream inputStream = new FileInputStream(outFilePath);
Workbook workbook = new XSSFWorkbook(inputStream);
FileOutputStream outputStream = new FileOutputStream(outFilePath);
Sheet sheet = workbook.getSheetAt(1); // 合并第二个sheet
// 合并
for(String deptNameCellRange : deptNameCellRangeList){
int firstRow = Integer.parseInt(deptNameCellRange.split("-")[0]);
int lastRow = Integer.parseInt(deptNameCellRange.split("-")[1]);
if(firstRow != lastRow){
// 入参: firstRow 合并开始行; lastRow 合并结尾行; firstCol 合并开始列; lastCol 合并结束列。
CellRangeAddress cellAddresses = new CellRangeAddress(firstRow, lastRow, 0, 0);
sheet.addMergedRegion(cellAddresses);
}
}
groupNameCellRangeList.forEach(groupNameCellRange -> { // forEach 写法
int firstRow = Integer.parseInt(groupNameCellRange.split("-")[0]);
int lastRow = Integer.parseInt(groupNameCellRange.split("-")[1]);
if (firstRow != lastRow) {
// 入参: firstRow 合并开始行; lastRow 合并结尾行; firstCol 合并开始列; lastCol 合并结束列。
CellRangeAddress cellAddresses = new CellRangeAddress(firstRow, lastRow, 1, 1);
sheet.addMergedRegion(cellAddresses);
}
});
// 保存合并后的Excel文件
workbook.write(outputStream);
} catch (IOException e) {
logger.error(e.getMessage(), e);
}
}
6. 测试
写一个main方法用于验证功能。
定义文件输出路径:D:\\ExcelExport\\ ;
定义文件名称:EasyExcelExport.xlsx
获取两个Sheet页所需数据:getSheet1DataList()、getSheet2DataList()
public static void main(String[] args) {
String outFilePath = "D:\\ExcelExport\\"; // 文件输出路径
String expExcelName = "EasyExcelExport.xlsx";
List<Map<String, String>> sheet1Data = getSheet1DataList();
List<Map<String, String>> sheet2Data = getSheet2DataList();
fillDataExp(sheet1Data, sheet2Data, expExcelName, outFilePath); // 填充数据并导出
mergeExcel(sheet2Data, outFilePath + expExcelName); // 合并单元格
}
7. 效果
Sheet1 :

Sheet2 :


754

被折叠的 条评论
为什么被折叠?



