【java】通过配置导出excel

这篇博客介绍了如何使用Java通过配置表来高效地导出Excel。博主分享了一个满意的方法,涉及配置表结构、Util类关键代码以及值表达式的配置。代码示例展示了如何从JSON数据中按配置读取值并生成Excel行数据,支持处理数组和复杂对象。
摘要由CSDN通过智能技术生成

【java】通过配置导出excel


不定时更新一些自己写的代码


前言

写了挺多excel导出的代码了,这个算是自己比较满意的,记录下


一、配置表

T_EXPORT_EXCEL

ID导出excel模板ID
EXCEL_NAME导出excel的文件名

T_EXPORT_SHEET

IDsheet页的ID
SHEET_NAMEsheet页的名称
EXCEL_IDEXCEL表ID
SORTSHEET页在模板中的顺序

T_EXPORT_TAB

ID唯一主键
HEAD表头
VALUE_EXPRESS取值表达式
VALUE_PARSER对取到的值进行封装
SHEET_ID关联的SHEET
SORT单元格在表格中的顺序

二、Util类关键代码

导出接口:


    /**
     * excel导出
     *
     * @return
     */
    public static HSSFWorkbook exportExcel(List<ExportTab> tabsCfg, List data, HSSFWorkbook wb, String sheetName) {

        List<String[]> result = new ArrayList<>();
        String[] heads = tabsCfg.stream().map(AntigenExportTab::getHead).collect(Collectors.toList()).toArray(new String[tabsCfg.size()]);
        List<String> valueConfigs = tabsCfg.stream().map(AntigenExportTab::getValueExpress).collect(Collectors.toList());
        List<String> valueParsers = tabsCfg.stream().map(AntigenExportTab::getValueParser).collect(Collectors.toList());

        JSONArray array = JSONArray.parseArray(JSONArray.toJSONString(data));
        for (int i = 0; i < array.size(); i++) {

            // 单行数据最大拆分行数
            int rowSpan = 1;
            // 数据解析
            Map<String, Object> valueMap = new HashMap<>();
            for (String valueCfg : valueConfigs) {
                if (valueCfg.startsWith("$")) {
                    Object val = getVal(array.getJSONObject(i), valueCfg.substring(1));
                    valueMap.put(valueCfg, val);
                    if (val instanceof List) {
                        int size = ((List) val).size();
                        rowSpan = rowSpan < size ? size : rowSpan;
                    }
                }
            }

            // 数据生成
            for (int row = 0; row < rowSpan; row++) {
                String[] rowData = generateRowData(valueConfigs, row, valueMap, valueParsers);
                if (rowData != null) {
                    if ("ROWNUM".equals(valueConfigs.get(0))) {
                        rowData[0] = String.valueOf(result.size() + 1);
                    }
                    result.add(rowData);
                }
            }
        }
		// 此处封装了调用POI将生成的sheet页插入到wb中,别人写的现成的,我就没贴上来
        return ExportExcelUtil.getHSSFWorkbook(sheetName, heads, result.toArray(new String[result.size()][]), wb);
    }

单行数据生成:

   /**
     * 生成一行数据
     *
     * @param valueConfigs
     * @param row
     * @param valueMap
     * @param valueParsers
     * @return
     */
    private static String[] generateRowData(List<String> valueConfigs, int row, Map<String, Object> valueMap, List<String> valueParsers) {
        String[] rowData = new String[valueConfigs.size()];
        for (int cell = 0; cell < valueConfigs.size(); cell++) {
            String valueKey = valueConfigs.get(cell);
            String valueParser = valueParsers.get(cell);
            Object value = valueMap.get(valueKey);
            if (value instanceof List) {
                List<String> vals = (List<String>) value;
                if (vals.size() == 0) {
                    // 子集合为空时保证有一条信息
                    rowData[cell] = "";
                } else if (vals.size() - 1 >= row) {
                    // 正常赋值
                    rowData[cell] = parsedExcelValue(vals.get(row), valueParser);
                } else {
                    // 越界
                    return null;
                }
            } else {
                rowData[cell] = parsedExcelValue((String) value, valueParser);
            }
        }
        return rowData;
    }

对取到的值进行封装:

 private static String parsedExcelValue(String value, String parser) {

        if (StringUtils.isEmpty(value) || StringUtils.isEmpty(parser)) {
            return value;
        }


        try {

            if (parser.startsWith("ArrayJSON_")) {
                return arrayJsonParser(value, parser);
            }
            if (parser.startsWith("ArrayJSON0_")) {
                return arrayJsonParser0(value, parser);
            }
            if (parser.startsWith("ArrayJSONS_")) {
                return arrayJsonParserS(value, parser);
            }

            switch (parser) {
                // 此处有一些一些业务上的特殊字段的处理,我删掉了
                default:
                    return value;
            }
        } catch (Exception e) {
            return value;
        }
    }

取数组的第N个字符串:

    private static String arrayJsonParser(String value, String parser) {
        Integer index = Integer.valueOf(parser.replace("ArrayJSON_", "")) - 1;
        JSONArray array = JSONArray.parseArray(value);
        return index >= 0 && array.size() > index ? array.getString(index) : "";
    }

取数组的第1个元素中的对应value:

    private static String arrayJsonParser0(String value, String parser) {
        JSONArray array = JSONArray.parseArray(value);
        return array.size() > 0 ? array.getJSONObject(0).getString(parser.replace("ArrayJSON0_", "")) : "";
    }

取数组的中元素的parser对应value:

JSONArray array = JSONArray.parseArray(value);
        if (array.isEmpty()) {
            return "";
        }
        String format = parser.replace("ArrayJSONS_", "");
        List<String> placeHolders = parses(format);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < array.size(); i++) {
            JSONObject o = array.getJSONObject(i);
            String str = format;
            for (int j = 0; j < placeHolders.size(); j++) {
                String placeHolder = placeHolders.get(j);
                str = str.replace(placeHolder, o.getString(placeHolder.substring(1, placeHolder.length() - 1)));
            }
            if (sb.length() > 0) {
                sb.append("\n");
            }
            sb.append(str);
        }
        return sb.toString();

上面调用到的子方法,做了个小缓存:

    private static List<String> parses(String str) {
        if (parsesMap.containsKey(str)) {
            return parsesMap.get(str);
        }

        String pattern = "(\\{[\\s\\S]+?\\})";
        Pattern r = Pattern.compile(pattern);
        // 现在创建 matcher 对象
        Matcher m = r.matcher(str);
        List<String> placeHolder = new ArrayList<>();
        while (m.find()) {
            placeHolder.add(m.group(0));
        }
        parsesMap.put(str, placeHolder);
        return placeHolder;
    }

    private static Map<String, List<String>> parsesMap = new ConcurrentHashMap<>();

按表达式读取值:

    private static Object getVal(JSONObject obj, String keyExpression) {

        if (obj == null) {
            return "";
        }

        int mapInd = keyExpression.indexOf('.');
        int listInd = keyExpression.indexOf('-');

        String temp = keyExpression.substring(1);
        int mSub = temp.indexOf('.');
        int lSub = temp.indexOf('-');
        if (mSub == -1 && lSub == -1) {
            if (obj.containsKey(temp)) {
                return keyExpression.startsWith("-") ? obj.getJSONArray(temp).toJSONString()
                        : StringUtils.defaultIfBlank(obj.getString(temp), "");
            } else {
                return "";
            }
        }
        int ind = getNextSplitInd(mSub, lSub);
        String key = temp.substring(0, ind);
        String expression = temp.substring(ind);

        if (mapInd == 0) {
            // map
            JSONObject o = obj.getJSONObject(key);
            return getVal(o, expression);
        }

        if (listInd == 0) {
            // list
            JSONArray array = obj.getJSONArray(key);
            List<String> result = new ArrayList<>();
            if (array == null) {
                return result;
            }
            for (int i = 0; i < array.size(); i++) {
                JSONObject o = array.getJSONObject(i);
                Object val = getVal(o, expression);
                if (val instanceof String) {
                    result.add((String) val);
                }
            }
            return result;
        }

        return "";
    }

下一个分隔符的位置:

    private static int getNextSplitInd(int a, int b) {
        if (a < 0 && b < 0) {
            throw new BusinessException("数据异常");
        } else if (a >= 0 && b >= 0) {
            return a > b ? b : a;
        } else {
            return a > 0 ? a : b;
        }
    }

三、值表达式的配置

JSON如下(示例):

[
    {
        "className":"三年一班",
        "chargeTeacher":{
            "name":"孙老师",
            "age":55,
            "sampling":[
                {
                    "site":"校门口",
                    "time":"202204014 12:00:00"
                },
                {
                    "site":"校门口",
                    "time":"202204013 12:00:00"
                }
            ]
        },
        "students":[
            {
                "name":"张三",
                "strongPoint":"[{\"point\":\"篮球\",\"awards\":\"市一等奖\"},{\"point\":\"乒乓球\",\"awards\":null}\"]",
                "voluntary":"[\"清华\",\"北大\"]",
                "sampling":[
                    {
                        "site":"校门口",
                        "time":"202204014 12:00:00"
                    },
                    {
                        "site":"校门口",
                        "time":"202204013 12:00:00"
                    }
                ]
            },
            {
                "name":"李四"
            }
        ]
    },
    {
        "className":"三年二班",
        "chargeTeacher":{
            "name":"李老师",
            "age":50
        },
        "students":[
            {
                "name":"王五"
            }
        ]
    }
]

配置如下(示例):

T_EXPORT_EXCEL

IDEXCEL_NAME
1班级信息导出

T_EXPORT_SHEET

IDSHEET_NAMEEXCEL_IDSORT
1班主任信息11
2学生信息12

T_EXPORT_TAB

IDHEADVALUE_EXPRESSVALUE_PARSERSHEET_IDSORT
11班级$.className11
12班主任$.chargeTeacher.name12
13最新核酸采样时间$.chargeTeacher.samplingArrayJSON0_time13
21班级$.className21
22姓名$-students.name22
23最新核酸采样时间$-students.samplingArrayJSON0_time23
24第一志愿$-students.voluntaryArrayJSON_124
25第二志愿$-students.voluntaryArrayJSON_225
26特长$-students.strongPointArrayJSONS_{point}:奖项{awards}26

总结

差不多了,记录下来万一哪天用得上过来ctrl+cv一下。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值