You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

导出UserProfile到Excel时报LinkedHashMap转String错误如何解决

问题根因

你使用ObjectMapper.convertValue()将UserProfile对象转为Map<String, Object>时,对象内的非基础类型不会自动序列化为字符串:

  • 自定义类(如Role、RoleGroup)会被转为LinkedHashMap类型
  • 枚举、Date、List类型也不会直接返回字符串值
    这些非字符串类型直接强转为String就会抛出类型转换异常。

另外你现有代码还有一处逻辑错误:创建单元格后先写入了字段名key,后续又写入字段值value,会把字段名直接覆盖,这段冗余代码可以删掉。


解决方案

1. 优化工具类代码

首先将ObjectMapper提到静态变量位置(线程安全,避免重复创建消耗性能),然后修改单元格赋值逻辑,对所有非基础类型做通用序列化处理:

// 工具类内定义全局ObjectMapper
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
// 可选:定义不需要导出的字段列表
private static final Set<String> EXCLUDE_FIELDS = Set.of("roles", "roleIds", "transactionPin", "hasPin");

public static InputStream writeToExcel(Stream<UserProfile> data) throws Exception {
    try (XSSFWorkbook workbook = new XSSFWorkbook()) {
        XSSFSheet sheet = workbook.createSheet("transaction report");
        AtomicInteger rowNum = new AtomicInteger(1);
        AtomicBoolean isHeaderSet = new AtomicBoolean(false);
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        data.forEach(userProfile -> {
            if (!isHeaderSet.get()){
                createHeader(userProfile, sheet);
                isHeaderSet.set(true);
            }
            XSSFRow row = sheet.createRow(rowNum.getAndIncrement());
            Map<String, Object> mapObj = OBJECT_MAPPER.convertValue(userProfile, Map.class);
            AtomicInteger cellNum = new AtomicInteger();

            mapObj.forEach((key, value) -> {
                // 跳过不需要导出的字段
                if (EXCLUDE_FIELDS.contains(key)) {
                    return;
                }
                XSSFCell cell = row.createCell(cellNum.getAndIncrement());
                // 空值直接填空字符串
                if (value == null) {
                    cell.setCellValue("");
                    return;
                }
                // 分类型处理单元格值
                if (value instanceof Integer) {
                    cell.setCellValue((Integer) value);
                } else if (value instanceof BigDecimal) {
                    cell.setCellValue(((BigDecimal) value).doubleValue());
                } else if (value instanceof Long) {
                    cell.setCellValue((Long) value);
                } else if (value instanceof Double) {
                    cell.setCellValue((Double) value);
                } else if (value instanceof Boolean) {
                    cell.setCellValue((Boolean) value);
                } else if (value instanceof Date) {
                    cell.setCellValue(dateFormat.format((Date) value));
                } else {
                    // 其他类型统一序列化为JSON字符串,序列化失败用toString兜底
                    try {
                        cell.setCellValue(OBJECT_MAPPER.writeValueAsString(value));
                    } catch (JsonProcessingException e) {
                        cell.setCellValue(value.toString());
                    }
                }
            });
        });
        // 原有后续输出流逻辑保持不变
        // ...
    }
}

2. 可选优化

如果不需要导出roles这类复合字段,直接在EXCLUDE_FIELDS里加对应的字段名即可,不需要做额外序列化处理。


内容的提问来源于stack exchange,提问作者Curious

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 11:45:06