Java解析取值表达式,生成导出Excel

Java解析取值表达式

1. 背景

导出的需求有时候会碰到一些复杂的excel模板,通过代码构建模板有时是非常麻烦的且难以修改的。所以我想了一个法子:将没有规律性的模板通过自己手动制作,在模板中填入插值表达式比如说:{order.no} ,有规律的内容模板通过代码复制+差值表达式进行渲染;模板内容如下:

在这里插入图片描述

通过在模板中插入表达式,通过解析表达式后进行数据填充,效果如下

在这里插入图片描述

如何复制模板行,在我前面的文章已经讲过了,还缺失的就是对表达式的处理,以及如何处理列表内容?

1,表达式解析获取值

Class ExpressionUtils

public class ExpressionUtils {

    /**
     * 解析表达表达式获取值
     * 例如:
     * placeholder: methodUserName 将会获得数据中methodUserName属性值,
     * 如果是 detail.methodUserName 将会获得数据中detail属性下的methodUserName属性值
     * @param placeholder 表达式
     * @param data Map<String, Object> 数据源
     * @param func Function<List<Map<String, Object>>, String> 碰到list的处理函数,处理list时如何返回
     * @return 表达式的数据
     */
    public static String getValueForPlaceholder(String placeholder, Map<String, Object> data, Function<List<Map<String, Object>>, String> func) {
        // 在这里你可以根据占位符的不同,从合适的地方获取对应的值
        if (!placeholder.contains(".")) {
            if (data.containsKey(placeholder)) {
                return ObjectUtil.isNotNull(data.get(placeholder)) ? data.get(placeholder).toString() : "";
            }
        } else {
            String[] split = placeholder.split("\\.");
            if (data.containsKey(split[0])) {
                Object o = data.get(split[0]);
                if(ObjectUtil.isNull(o)) {
                    return "";
                }
                if (o instanceof List<?>) { {
                    // 如果是列表
                    List<Map<String, Object>> mapList = ((List<?>) o).stream().map(BeanUtil::beanToMap).collect(Collectors.toList());
                    mapList.forEach(map -> {
                        map.put("split", split);
                    });
                    return func.apply(mapList);
                }}
                String[] newPlaceHolder = new String[split.length - 1];
                System.arraycopy(split, 1, newPlaceHolder, 0, newPlaceHolder.length);
                StringJoiner joiner = new StringJoiner(".");
                Arrays.stream(newPlaceHolder).forEach(joiner::add);
                return getValueForPlaceholder(joiner.toString(), BeanUtil.beanToMap(o), func);
            }
        }
        return "";
    }
}

getValueForPlaceholder的作用就是获取表达式的值func的作用是碰到列表List的情况的处理,getValueForPlaceholder会提供func一个匹配到的列表数据List<Map<String, Object>>。

在遍历sheet中单元格的时候进行匹配单元格中的表达式,如果是单个值则直接返回值然后通过cell.setCellValue();设置值,如果表达式是列表则需要传递func 处理程序,例如:

for (Row row : sheet) {
            for (Cell cell : row) {
                if (cell.getCellType() == Cell.CELL_TYPE_STRING) {
                    String regex = "\\{([^}]+)\\}";
                    // 编译正则表达式
                    Pattern pattern = Pattern.compile(regex);
                    // 创建 Matcher 对象,用于匹配字符串
                    String stringCellValue = cell.getStringCellValue();
                    Matcher matcher = pattern.matcher(stringCellValue);
                    StringBuffer result = new StringBuffer();
                    while (matcher.find()) {
                        // 获取花括号内的内容
                        String match = matcher.group(1); // group(1) 表示第一个捕获组的内容
                        // 替换逻辑
                        String replacement = ExpressionUtils.getValueForPlaceholder(match, detailMap, listMap -> {
                            int columnIndex = cell.getColumnIndex();
                            int rowIndex = cell.getRowIndex();
                            String returnRes = "";
                            for (int index = 0; index < listMap.size(); index++) {
                                Map<String, Object> localDataMap = listMap.get(index);
																// 加入序号
                                localDataMap.put("#", index + 1);
                                String[] split = (String[]) localDataMap.get("split");
                                // 设置值
                                cell.getSheet().getRow(rowIndex + index).getCell(columnIndex).setCellStyle(cell.getCellStyle());
                                cell.getSheet().getRow(rowIndex + index).getCell(columnIndex).setCellValue(localDataMap.get(split[1]).toString());
                                if (index == 0) {
                                    returnRes = localDataMap.get(split[1]).toString();
                                }
                            }
                            return returnRes;
                        });
                        // 替换匹配的字符串,并去掉花括号 {}
                        matcher.appendReplacement(result, replacement);
                    }
                    matcher.appendTail(result);
                    // 设置值
                    cell.setCellValue(result.toString());
                }
            }
        }

在碰到列表数据的时候是按照列进行渲染还是按照行进行渲染就通过func来处理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值