Java 树形结构数据生成导出excel文件V2

** >> 相对于V1版本,优化了代码逻辑,合理使用递归计算树数据的坐标 << **

1、效果

Java 树形结构数据生成导出excel文件V2_第1张图片

2、使用方法


import com.alibaba.fastjson.JSONArray;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Workbook;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

public class Tree2ExcelDemo {

    public static void main(String[] args) throws IOException {
        String jsonStr = "[{\"name\":\"aaa\",\"children\":[{\"name\":\"bbb\",\"children\":[{\"name\":\"eee\"},{\"name\":\"fff\",\"children\":[{\"name\":\"iii\"},{\"name\":\"jjj\",\"children\":[{\"name\":\"qqq\"},{\"name\":\"ttt\"}]}]},{\"name\":\"www\"}]},{\"name\":\"ccc\",\"children\":[{\"name\":\"ggg\"},{\"name\":\"hhh\",\"children\":[{\"name\":\"kkk\",\"children\":[{\"name\":\"ttt\"},{\"name\":\"mmm\"}]},{\"name\":\"uuu\"}]},{\"name\":\"ooo\"}]},{\"name\":\"ddd\",\"children\":[{\"name\":\"ggg\"},{\"name\":\"hhh\",\"children\":[{\"name\":\"kkk\"},{\"name\":\"uuu\"}]}]}]}]";

        List<TestDemo.TreeE> list = JSONArray.parseArray(jsonStr, TestDemo.TreeE.class);

        String path = "C:\\Users\\LZY\\Desktop\\" + System.currentTimeMillis() + ".xls";

        File file = new File(path);
        file.createNewFile();

        Workbook workbook = new HSSFWorkbook();

        Tree2ExcelUtil.handle(workbook, list, "TOP", Tree2ExcelUtil.Type.TOP,
                null, null, 1, 1, 1);
        Tree2ExcelUtil.handle(workbook, list, "MIDDLE", Tree2ExcelUtil.Type.MIDDLE,
                null, null, 1, 1, 1);
        Tree2ExcelUtil.handle(workbook, list, "BOTTOM", Tree2ExcelUtil.Type.BOTTOM,
                null, null, 1, 1, 1);

        try (
                FileOutputStream fos = new FileOutputStream(file)
        ) {
            workbook.write(fos);

            fos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            workbook.close();
        }

    }
}

3、源码


import org.apache.poi.ss.usermodel.*;

import java.lang.reflect.Field;
import java.util.*;

/**
 * 树形结构数据导出生成excel文件
 * 

* Created by lzy on 2024/1/13 14:09 */ @SuppressWarnings("unchecked") public class Tree2ExcelUtil { /** * 处理填充 树数据 到工作簿 * * @param workbook 工作簿 * @param treeList 树数据,children结构 * @param 数据泛型 */ public static <T> void handle(Workbook workbook, List<T> treeList) { handle(workbook, treeList, null, Type.MIDDLE, null, null, 1, 1, 1); } /** * 处理填充 树数据 到工作簿 * * @param workbook 工作簿 * @param treeList 树数据,children结构 * @param type 树类型 * @param 数据泛型 */ public static <T> void handle(Workbook workbook, List<T> treeList, Type type) { handle(workbook, treeList, null, type, null, null, 1, 1, 1); } /** * 处理填充 树数据 到工作簿 * * @param workbook 工作簿 * @param treeList 树数据,children结构 * @param sheetName 工作表名,用于给指定工作表填充树数据 * @param type 树类型 * @param 数据泛型 */ public static <T> void handle(Workbook workbook, List<T> treeList, String sheetName, Type type) { handle(workbook, treeList, sheetName, type, null, null, 1, 1, 1); } /** * 处理填充 树数据 到工作簿 * * @param workbook 工作簿 * @param treeList 树数据,children结构 * @param type 树类型 * @param lableField 标签字段名 * @param childrenField 孩子集合字段名 * @param 数据泛型 */ public static <T> void handle(Workbook workbook, List<T> treeList, Type type, String lableField, String childrenField) { handle(workbook, treeList, null, type, lableField, childrenField, 1, 1, 1); } /** * 处理填充 树数据 到工作簿 * * @param workbook 工作簿 * @param treeList 树数据,children结构 * @param sheetName 工作表名,用于给指定工作表填充树数据 * @param type 树类型 * @param lableField 标签字段名 * @param childrenField 孩子集合字段名 * @param 数据泛型 */ public static <T> void handle(Workbook workbook, List<T> treeList, String sheetName, Type type, String lableField, String childrenField) { handle(workbook, treeList, sheetName, type, lableField, childrenField, 1, 1, 1); } /** * 处理填充 树数据 到工作簿 * * @param workbook 工作簿 * @param treeList 树数据,children结构 * @param sheetName 工作表名,用于给指定工作表填充树数据 * @param type 树类型 * @param lableField 标签字段名 * @param childrenField 孩子集合字段名 * @param startRow 开始行数,默认:1 * @param rowOffset 间隔行数,默认:1 * @param startCol 开始列数,默认:1 * @param 数据泛型 */ public static <T> void handle(Workbook workbook, List<T> treeList, String sheetName, Type type, String lableField, String childrenField, int startRow, int rowOffset, int startCol) { if (startRow < 0) { throw new Tree2ExcelException("开始行数不能小于0"); } if (rowOffset < 0) { throw new Tree2ExcelException("间隔行数不能小于0"); } if (startCol < 1) { throw new Tree2ExcelException("开始列数不能小于1"); } List<Map<String, Object>> newList = new ArrayList<>(); childrenField = emptyToDefault(childrenField, CHILDREN_FIELD); handleCoord(treeList, childrenField, startRow, rowOffset, startCol, newList); //配置单元格背景色 CellStyle style1 = getCellStyle(workbook, IndexedColors.LIGHT_GREEN); CellStyle style2 = getCellStyle(workbook, IndexedColors.LIGHT_YELLOW); sheetName = emptyToDefault(sheetName, "Sheet1"); Sheet sheet = workbook.getSheet(sheetName); if (sheet == null) { sheet = workbook.createSheet(sheetName); } heandleExcel(sheet, type, newList, emptyToDefault(lableField, LABLE_FIELD), childrenField, style1, style2); } /* 列字段标识 */ private static final String COL = "_$col"; /* 开始行字段标识 */ private static final String S_ROW = "_$s_row"; /* 中间行字段标识 */ private static final String C_ROW = "_$c_row"; /* 结束行字段标识 */ private static final String E_ROW = "_$e_row"; /* 标签字段标识 */ private static final String LABLE_FIELD = "name"; /* 子集字段标识 */ private static final String CHILDREN_FIELD = "children"; /** * 处理树数据坐标 * * @param treeList 树数据,children结构 * @param childrenField 孩子集合字段名 * @param startRow 开始行数 * @param rowOffset 间隔行数 * @param startCol 开始列数 * @param result 引用传递 * @param 数据泛型 * @return 子集的行高 */ private static <T> int handleCoord(List<T> treeList, String childrenField, int startRow, int rowOffset, int startCol, List<Map<String, Object>> result) { if (isCollNotEmpty(treeList)) { // 当前所在元素高度 int tempRow = 0; // 所有子集的高度和 int childrenRows = 0; for (int i = 0; i < treeList.size(); i++) { Map<String, Object> item = convertBeanToMap(treeList.get(i)); tempRow = i + i * rowOffset; item.put(COL, startCol); item.put(S_ROW, startRow + tempRow + childrenRows); // 子集合的高度 int childRow = 0; List<T> children = (List<T>) item.get(childrenField); if (isCollNotEmpty(children)) { List<Map<String, Object>> childrenRes = new ArrayList<>(); item.put(childrenField, childrenRes); childRow = handleCoord(children, childrenField, startRow + tempRow + childrenRows, rowOffset, startCol + 2, childrenRes); } item.put(C_ROW, startRow + tempRow + childrenRows + (Math.floorDiv(childRow, 2))); childrenRows += childRow; item.put(E_ROW, startRow + tempRow + childrenRows); result.add(item); } return tempRow + childrenRows; } return 0; } /** * 处理Excel * * @param sheet 工作表 * @param type 树类型 * @param list 带有坐标的数据 * @param lableField 标签字段名 * @param childrenField 孩子集合字段名 * @param style1 文本样式 * @param style2 连线样式 */ private static void heandleExcel(Sheet sheet, Type type, List<Map<String, Object>> list, String lableField, String childrenField, CellStyle style1, CellStyle style2) { if (isCollNotEmpty(list)) { int startRow = -1, endRow = -1, fullCol = -1; int size = list.size(); for (int i = 0; i < size; i++) { Map<String, Object> item = list.get(i); int x = toInt(item.get(COL)); int y = toInt(item.get(TYPE_KEY_MAP.get(type))); Cell cell = getOrCreateCell(sheet, x, y); if (cell != null) { cell.setCellStyle(style1); cell.setCellValue(toStringOrNull(item.get(lableField))); } List<Map<String, Object>> children = (List<Map<String, Object>>) item.get(childrenField); if (isCollNotEmpty(children)) { heandleExcel(sheet, type, children, lableField, childrenField, style1, style2); } if (i == 0) { startRow = y; } if (i == size - 1) { endRow = y; } fullCol = x; } if (startRow != -1 && endRow != -1 && fullCol > 0) { sheet.setColumnWidth(fullCol, 256 * 20); sheet.setColumnWidth(fullCol - 1, 256); for (; startRow <= endRow; startRow++) { Cell cell = getOrCreateCell(sheet, fullCol - 1, startRow); if (cell != null) { cell.setCellStyle(style2); } } } } } /** * 获取或创建 Cell * * @param sheet 工作表 * @param x 列 * @param y 行 * @return Cell */ private static Cell getOrCreateCell(Sheet sheet, int x, int y) { Row row = sheet.getRow(y); if (row == null) { row = sheet.createRow(y); } Cell cell = row.getCell(x); if (cell == null) { cell = row.createCell(x); } return cell; } /** * 获取Cell样式 * * @param workbook 工作簿 * @param indexedColors 颜色 * @return 样式 */ private static CellStyle getCellStyle(Workbook workbook, IndexedColors indexedColors) { CellStyle style = workbook.createCellStyle(); style.setFillForegroundColor(indexedColors.getIndex()); style.setFillPattern(FillPatternType.SOLID_FOREGROUND); return style; } /** * 转整型 * * @param val 值 * @return 整型值 */ private static int toInt(Object val) { try { return Integer.parseInt(String.valueOf(val)); } catch (NumberFormatException ignored) { } return 0; } /** * 转字符串 * * @param obj 值 * @return 字符串值 */ public static String toStringOrNull(Object obj) { return null == obj ? null : obj.toString(); } /** * 字符串若空则默认 * * @param str 字符串 * @param defaultStr 默认值 * @return 字符串 */ public static String emptyToDefault(CharSequence str, String defaultStr) { return str == null || str.length() == 0 ? defaultStr : str.toString(); } /** * 集合是否为空 * * @param collection 集合 * @return 是否为空 */ private static boolean isCollNotEmpty(Collection<?> collection) { return !(collection == null || collection.isEmpty()); } /** * 实体类转Map * * @param bean 实体类 * @return Map值 */ public static Map<String, Object> convertBeanToMap(Object bean) { if (bean instanceof List || bean instanceof Set) { throw new Tree2ExcelException("传递的元素值不符合要求"); } if (bean instanceof Map) { return (Map<String, Object>) bean; } Map<String, Object> map = new HashMap<>(); try { Class<?> clazz = bean.getClass(); Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); map.put(field.getName(), field.get(bean)); } } catch (IllegalAccessException ignored) { } return map; } private static final Map<Type, String> TYPE_KEY_MAP = new HashMap<>(); static { TYPE_KEY_MAP.put(Type.TOP, S_ROW); TYPE_KEY_MAP.put(Type.MIDDLE, C_ROW); TYPE_KEY_MAP.put(Type.BOTTOM, E_ROW); } public static enum Type { /** * 上对齐 */ TOP, /** * 中对齐 */ MIDDLE, /** * 下对齐 */ BOTTOM; } @SuppressWarnings("unused") public static class Tree2ExcelException extends RuntimeException { public Tree2ExcelException() { super(); } public Tree2ExcelException(String message) { super(message); } public Tree2ExcelException(String message, Throwable cause) { super(message, cause); } public Tree2ExcelException(Throwable cause) { super(cause); } } }

你可能感兴趣的:(java,java,excel,开发语言)