Spring Boot 从 YAML(属性)文件中读取数组

Posted

技术标签:

【中文标题】Spring Boot 从 YAML(属性)文件中读取数组【英文标题】:Spring boot read array from YAML (properties) file 【发布时间】:2018-10-27 23:45:31 【问题描述】:

这是我的项目结构

- src
    - main
        - java
            - mypackage
            - resources
                - config
                    application.yml

我在 application.yml 中有这个

document:
    templates:
        filetypes:
            - elem1
            - elem2
            - elem3
            - elem4
    hello:
        test: "hello"

在我的端点中,我有以下内容

@Value("$document.templates.filetypes")
List<String> templatesFileTypes;

@Value("$document.hello.test")
String hello;

在任何功能中,我都可以访问System.out.println(hello) 之类的东西,而且它工作得很好 但对于文件类型,它甚至没有编译,我收到这个错误:

创建名为“configurationEndPoint”的 bean 时出错:注入 自动装配依赖失败;嵌套异常是 java.lang.IllegalArgumentException:无法解析占位符 'document.templates.filetypes' 的值 "$document.templates.filetypes"

搜索了很多,我能找到的每个解决方案都是指向写入 application.yml/application.xml 文件,这在我的情况下是无效的,因为我可以读取其他测试字符串但不能读取数组;

我试过String[] 我试过ArrayList&lt;String&gt; 但我无法让它工作

【问题讨论】:

看到这个问题:***.com/questions/26699385/… @JoshSullivan 不 【参考方案1】:

一种方法是将元素作为分隔列表传递。通常我们使用逗号,它适用于字符串数组。要使用列表,则需要使用 Spring SPEL 格式设置分隔符...参见下面的示例。

document:
    templates:
        filetypes:elem1,elem2,elem3

-

@Value("$document.templates.filetypes:")
private String[] array;


@Value("#'$document.templates.filetypes'.split(',')")
private List<String> list;

@PostConstruct
void testList()
    list.stream().forEach(System.out::println);
    for (String a : array) 
        System.out.println(a);
    

【讨论】:

我一秒钟前才找到它xD,因为它的正确答案仍然会接受它 我知道这适用于 String[] 而不是 List 上的 100% 经过几个小时的测试,这将在我的数组中返回一个简单的字符串! 这可行,但它不是一个“干净”的解决方案,我将添加我的解决方案作为更清洁方式的第二个答案【参考方案2】:

@Jose Martinez 提供的另一个解决方案可以工作,但并不像需要的那样清晰,因为它将document.templates.filetypes 读取为字符串,然后将其拆分为字符串数组;因此我正在为此添加我的解决方案,

1- 创建新类 FileTypesProperties

@Configuration
@ConfigurationProperties(prefix = "document.templates")
public class FileTypesConfig 

    private List<String> fileTypes;

    public List<String> getFileTypes() 
        return fileTypes;
    

    public void setFileTypes(List<String> fileTypes) 
        this.fileTypes = fileTypes;
    

2- 创建服务并注入上一个类

@Service
public class FileTypeService 
    private final List<String> fileTypes;

    @Autowired
    public FileTypeService(FileTypesConfig fileTypesConfig)
        this.fileTypes = fileTypesConfig.getFileTypes();
    

    public List<String> getFileTypes()
        return this.fileTypes;
    


3- 在您的终点,只需自动连接并调用之前的服务

@RestController
public class ConfigurationEndPoint 

    @Autowired
    FileTypeService fileTypeService;
    @GetMapping("/api/filetypes")
    @ResponseBody
    public ResponseEntity<List<String>> getDocumentTemplatesFileTypes()
        return ResponseEntity.ok(fileTypeService.getFileTypes());
    

然后你的 yaml 文件就可以是一个真正的数组了

document:
    templates:
        file-types:
            - elem1
            - elem2
            - elem3
            - elem4

我相信这比将字符串拆分成更小的字符串到数组更干净,希望这对某人有所帮助。

【讨论】:

谢谢分享。我担心我讨厌这是必要的,但我真的很感激知道它。谢谢!【参考方案3】:

我觉得这也是一种有效的方式:

@Service
public class FileTypeService 
    private final List<String> fileTypes;

    public FileTypeService(Environment environment) 
        this.fileTypes = Binder.get(environment).bind("document.templates.filetypes", Bindable.listOf(String.class)).get();
    

Bindable.setOf 如果需要 Set 而不是 List,则可以使用。

【讨论】:

【参考方案4】:

继续上面 Jose Martinez 的回答,如果您有一长串值以增加可读性,您可以按如下方式格式化 yaml 请参阅下面的示例。

document:
    templates:
        filetypes: |-
          elem1,
          elem2,
          elem3,
          elem4
@Value("$document.templates.filetypes")
private String[] array;


@Value("#'$document.templates.filetypes'.split(',')")
private List<String> list;

@PostConstruct
void testList()
    list.stream().forEach(System.out::println);
    for (String a : array) 
        System.out.println(a);
    

【讨论】:

以上是关于Spring Boot 从 YAML(属性)文件中读取数组的主要内容,如果未能解决你的问题,请参考以下文章

Spring Boot:使用 yaml 中配置的 Maven 属性

从 json 文件加载 spring-boot 属性

Spring Boot 无法从配置文件特定的 yaml 文件中读取

Spring Boot - 从 YAML 文件中注入地图

spring boot 配置多个yaml文件并根据env参数加载

Spring Boot YAML 绑定:绑定属性失败