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

Spring Boot中如何通过Environment动态获取Map类型配置?

解决Spring Boot动态获取Map类型配置的问题

问题本质

通过@Value("#{${app.sftp.basic.defaultFields}}")结合SpEL能正常加载Map,是因为SpEL会自动解析配置字符串为Map结构;但调用Environment.getProperty(defaultFieldsKey, Map.class)时,Spring默认并未注册String到Map的类型转换器,因此抛出ConverterNotFoundException。

可行解决方案

方案1:自定义类型转换器(推荐)

实现Spring的Converter<String, Map<String, String>>接口,将配置文件中的字符串格式(如k1=v1,k2=v2或{k1=v1,k2=v2})转换为Map,再注册到Spring的ConversionService中即可全局生效。

示例转换器代码:

import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Arrays;
import java.util.stream.Collectors;

@Component
public class StringToMapConverter implements Converter<String, Map<String, String>> {
    @Override
    public Map<String, String> convert(String source) {
        if (source == null || source.trim().isEmpty()) {
            return new LinkedHashMap<>();
        }
        // 兼容配置文件中带{}的格式,先清理符号再拆分
        String cleanedContent = source.replaceAll("[{}]", "").trim();
        return Arrays.stream(cleanedContent.split(","))
                .map(entry -> entry.split("=", 2))
                .collect(Collectors.toMap(
                        parts -> parts[0].trim(),
                        parts -> parts.length > 1 ? parts[1].trim() : "",
                        (oldVal, newVal) -> newVal, // 处理重复键,保留新值
                        LinkedHashMap::new
                ));
    }
}

注册转换器(Spring Boot 2.x+会自动扫描并注册Converter Bean,若需手动配置可添加以下类):

import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {
    private final StringToMapConverter stringToMapConverter;

    public WebConfig(StringToMapConverter stringToMapConverter) {
        this.stringToMapConverter = stringToMapConverter;
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(stringToMapConverter);
    }
}

完成后,调用Environment.getProperty(defaultFieldsKey, Map.class)即可正常转换。

方案2:手动解析字符串(临时场景)

若不想自定义转换器,可直接获取配置字符串后手动解析,适合简单临时场景:

String configStr = environment.getProperty(defaultFieldsKey);
Map<String, String> resultMap = new LinkedHashMap<>();
if (configStr != null && !configStr.isEmpty()) {
    String cleaned = configStr.replaceAll("[{}]", "").trim();
    for (String entry : cleaned.split(",")) {
        String[] keyValuePair = entry.split("=", 2);
        if (keyValuePair.length == 2) {
            resultMap.put(keyValuePair[0].trim(), keyValuePair[1].trim());
        }
    }
}

这种方式复用性差,仅适合快速解决单一场景问题。

方案3:使用@ConfigurationProperties(固定配置结构场景)

如果配置键是提前确定的,可通过@ConfigurationProperties绑定配置类,直接注入获取Map:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Map;

@Component
@ConfigurationProperties(prefix = "app.sftp.basic")
public class SftpConfigProperties {
    private Map<String, String> defaultFields;

    // Getter & Setter
    public Map<String, String> getDefaultFields() {
        return defaultFields;
    }

    public void setDefaultFields(Map<String, String> defaultFields) {
        this.defaultFields = defaultFields;
    }
}

注入该类后直接调用getDefaultFields()即可获取Map,但此方案不支持完全动态的配置键(键名需提前定义)。

总结

  • 若需要动态指定配置键获取Map,自定义Converter是最规范、可复用的方案;
  • 临时场景可手动解析字符串;
  • 配置结构固定时,@ConfigurationProperties更简洁高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 07:47:09