การกำหนดค่า yaml ของ Spring Boot สำหรับรายการสตริง


149

ฉันพยายามโหลดอาร์เรย์ของสตริงจากไฟล์ application.yml นี่คือการกำหนดค่า:

ignore:
    filenames:
        - .DS_Store
        - .hg

นี่คือคลาส:

@Value("${ignore.filenames}")
private List<String> igonoredFileNames = new ArrayList<>();

มีการกำหนดค่าอื่น ๆ ในคลาสเดียวกันที่โหลดได้ดี ไม่มีแท็บในไฟล์ yaml ของฉัน ฉันยังได้รับข้อยกเว้นต่อไปนี้:

Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'ignore.filenames' in string value "${ignore.filenames}"

คำตอบ:


71

ฉันเดาว่าที่@Valueไม่สามารถรับมือกับ "ซับซ้อน" ประเภท คุณสามารถไปกับคลาส prop ได้ดังนี้:

@Component
@ConfigurationProperties('ignore')
class IgnoreSettings {
    List<String> filenames
}

หมายเหตุ:รหัสนี้เป็นGroovy - ไม่ Java - เพื่อให้สั้นตัวอย่าง! ดูความคิดเห็นสำหรับเคล็ดลับวิธีการนำไปใช้

ดูตัวอย่างที่สมบูรณ์https://github.com/christoph-frick/so-springboot-yaml-string-list


1
คุณสามารถผูกคั่นด้วยเครื่องหมายจุลภาคด้วย@Value(ตราบใดที่มีการลงทะเบียนตัวแปลงซึ่งจะอยู่ใน Spring Boot ฉันคิดว่า)
Dave Syer

2
มันคือการยกการตั้งค่าสตริง แต่ไม่ใช่รายการการตั้งค่า <String>
BahadırYağan

1
ฉันไม่สามารถทำให้มันทำงานได้@Configurationแต่ใช้@Componentกลอุบายแทนได้
Stijn Van Bael

1
@ cfrick ใช่มันเป็นเพียงการเปลี่ยนแปลงที่ฉันทำ ดูที่วัตถุประสงค์ของการเพิ่มความคิดเห็นทั้งสองฉันจะบอกว่า@Componentเหมาะสมกว่า: stackoverflow.com/questions/12229282/ …
Stijn Van Bael

2
ดูเหมือนว่าเป็นข้อ จำกัด ของกระบวนการบู๊ตสปริงที่มีคำอธิบายประกอบ - github.com/spring-projects/spring-boot/issues/501
wontondon

134

ใช้ค่าที่คั่นด้วยเครื่องหมายจุลภาคใน application.yml

ignoreFilenames: .DS_Store, .hg

รหัส java สำหรับการเข้าถึง

@Value("${ignoreFilenames}")    
String[] ignoreFilenames

มันใช้งานได้;)


ฉันหวังว่ามันจะทำงานใน Dropwizard ด้วย: '(ขอบคุณนะ!
RST

1
นั่นควรเป็นคำตอบที่ดีที่สุด
Mohamed Elsayed

3
ในการทดสอบของฉันเองนี่เทียบเท่ากับ ".DS_Store, .hg" แต่ไม่ใช่ ".DS_Store", ".hg" - อันหลังล้มเหลวด้วย "org.yaml.snakeyaml.parser.ParserException: ขณะที่แยกการแมปบล็อก" ดังนั้นสิ่งที่คุณกำลังทำอยู่ที่นี่คือการนำเสนอคุณสมบัติเป็นสตริงที่คั่นด้วยเครื่องหมายจุลภาค (ซึ่ง Spring จะแบ่งออกเป็นอาร์เรย์หรือรายการ) แทนที่จะเป็นอาร์เรย์ YAML "ใช้งานได้" แต่ไม่ตอบคำถามเดิม ฉันยังไม่พบวิธีในการแยกอาร์เรย์ YAML ในคุณสมบัติถั่ว @Value
Zirzirikos

38

จาก doc boot ฤดูใบไม้ผลิ https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html

รายการ YAML จะแสดงเป็นคีย์คุณสมบัติที่มี [ดัชนี] dereferencers เช่น YAML นี้:

my:
   servers:
       - dev.bar.com
       - foo.bar.com

จะถูกเปลี่ยนเป็นคุณสมบัติเหล่านี้:

my.servers[0]=dev.bar.com
my.servers[1]=foo.bar.com

หากต้องการเชื่อมโยงกับคุณสมบัติเช่นนั้นโดยใช้ยูทิลิตี Spring DataBinder (ซึ่งเป็นสิ่งที่@ConfigurationPropertiesทำ) คุณต้องมีคุณสมบัติในถั่วประเภทเป้าหมายjava.util.Listและคุณต้องจัดเตรียม setter หรือกำหนดค่าเริ่มต้นด้วยค่าที่ไม่แน่นอนเช่นจะเป็นการผูก กับคุณสมบัติข้างต้น นี่คือลักษณะของคำถามของคำถาม

@ConfigurationProperties(prefix="ignore")
public class Filenames {

    private List<String> ignoredFilenames = new ArrayList<String>();

    public List<String> getFilenames() {
        return this.ignoredFilenames;
    }
}

2
นี้ควรจะทำงาน BTW getXxx()เป็นสิ่งที่จำเป็นเพื่อให้การทำงานและต้องใช้ไม่ได้List Set
Eric Wang Wang

ใน yaml รายการค่าสำหรับ ArrayList สามารถเป็นรายการที่คั่นด้วยเครื่องหมายจุลภาค ในกรณีของฉันฉันมีค่ามากมายดังนั้นรายการขนาดกะทัดรัดจึงสะอาดกว่ารายการต่อบรรทัด ดังนั้นในตัวอย่างคุณสามารถใช้เซิร์ฟเวอร์: dev.bar.com, foo.bar.com
Violaman

25

นอกจากคำตอบของ Ahmetคุณสามารถเพิ่มตัวแบ่งบรรทัดในสตริงที่คั่นด้วยอาการโคม่าโดยใช้>สัญลักษณ์

application.yml :

ignoreFilenames: >
  .DS_Store, 
  .hg

รหัส Java :

@Value("${ignoreFilenames}")    
String[] ignoreFilenames;

สิ่งนี้ใช้ได้ดีตราบใดที่คุณไม่มีเครื่องหมายจุลภาค (,) ในสตริงของคุณอีกต่อไป
Valentin Despa

สิ่งนี้ใช้ไม่ได้ในการอ่านคุณสมบัติเป็นรายการอาร์เรย์ มันอ่านพวกเขาเป็นสตริงเดียว
Sree Lakshmi

6

คำตอบของ Ahmetให้วิธีการกำหนดค่าที่คั่นด้วยเครื่องหมายจุลภาคให้กับอาร์เรย์สตริง

หากต้องการใช้การกำหนดค่าข้างต้นในคลาสที่แตกต่างกันคุณอาจต้องสร้าง getters / setters สำหรับสิ่งนี้ .. แต่ถ้าคุณต้องการโหลดการกำหนดค่านี้เพียงครั้งเดียวและใช้สิ่งนี้เป็นถั่วที่มีคำอธิบายประกอบแบบอัตโนมัตินี่คือวิธีที่ฉันทำได้:

ใน ConfigProvider.java

@Bean (name = "ignoreFileNames")
@ConfigurationProperties ( prefix = "ignore.filenames" )
public List<String> ignoreFileNames(){
    return new ArrayList<String>();
}

ในชั้นเรียนภายนอก:

@Autowired
@Qualifier("ignoreFileNames")
private List<String> ignoreFileNames;

คุณสามารถใช้รายการเดียวกันทุกที่อื่นโดยการลงทะเบียนอัตโนมัติ


ที่ได้ผล ในกรณีของฉัน แต่สมัครไม่เว้นแต่ฉันจะเพิ่มที่จุดเริ่มต้นของการเรียนใน@Configuration ConfigProvider.javaมิฉะนั้นฉันได้รับแหล่งที่มาต้องใช้ถั่วชนิด 'java.util.List' ที่ไม่สามารถพบได้
ไดอาน่า


2

มีเพียงสิ่งเดียวที่ฉันสามารถทำให้มันทำงานได้:

servers: >
    dev.example.com,
    another.example.com

@Value("${servers}")
private String[] array;

และอย่าลืม @Configuration เหนือชั้นเรียนของคุณ ....

หากไม่มีการแยก "," ก็ไม่มีโชค ...

ทำงานด้วย (บูต 1.5.8 รุ่น)

servers: 
       dev.example.com,
       another.example.com

-1

ในกรณีของฉันนี่เป็นปัญหาไวยากรณ์ในไฟล์ .yml ฉันมี:

@Value("${spring.kafka.bootstrap-servers}")
public List<String> BOOTSTRAP_SERVERS_LIST;

และรายการในไฟล์ .yml ของฉัน:

bootstrap-servers:
  - s1.company.com:9092
  - s2.company.com:9092
  - s3.company.com:9092

ไม่ได้อ่านในช่อง @ Value-annotated เมื่อฉันเปลี่ยนไวยากรณ์ในไฟล์ .yml เป็น:

bootstrap-servers >
  s1.company.com:9092
  s2.company.com:9092
  s3.company.com:9092

มันทำงานได้ดี


การลองสิ่งนี้ใน spring-boot 1.5 มันไม่สามารถใช้งานได้ คุณต้องการโคลอนหลังจาก bootstrap-servers
Taugenichts

-2
@Value("${your.elements}")    
private String[] elements;

ไฟล์ yml:

your:
 elements: element1, element2, element3

1
คำตอบของ Ahmet ในรูปแบบนี้แตกต่างกันอย่างไร stackoverflow.com/a/41462567/2065796
Sasha Shpota

1
ตอบแล้ว การตอบเพียงเพื่อประโยชน์ของคะแนนไม่ได้เพิ่มคุณค่า
Deepak
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.