Membaca Daftar dari file properti dan memuat dengan pegas penjelasan @ Nilai


244

Saya ingin memiliki daftar nilai dalam file .properties, yaitu:

my.list.of.strings=ABC,CDE,EFG

Dan untuk memuatnya di kelas saya secara langsung, yaitu:

@Value("${my.list.of.strings}")
private List<String> myList;

Seperti yang saya mengerti, alternatif melakukan ini adalah untuk memilikinya di file konfigurasi musim semi, dan memuatnya sebagai referensi kacang (koreksi saya jika saya salah), yaitu

<bean name="list">
 <list>
  <value>ABC</value>
  <value>CDE</value>
  <value>EFG</value>
 </list>
</bean>

Tetapi apakah ada cara untuk melakukan ini? menggunakan file .properties? ps: Saya ingin melakukan ini tanpa kode khusus jika memungkinkan.

Jawaban:


454

Menggunakan Spring EL:

@Value("#{'${my.list.of.strings}'.split(',')}") 
private List<String> myList;

Dengan asumsi file properti Anda dimuat dengan benar dengan yang berikut:

my.list.of.strings=ABC,CDE,EFG

1
Saya memeriksanya lagi menggunakan versi yang sama yang Anda gunakan. Menyalin EL Musim Semi persis seperti pada pos dan berfungsi. Yang berbeda adalah jika saya membuat kesalahan pada EL saya, saya mendapatkan org.springframework.expression.spel.SpelEvaluationExceptionpengecualian dan tidak javax.el.ELException. Apakah keberatan Anda dibuat oleh Spring?
Wilhelm Kleu

1
Berfungsi sempurna dengan Spring 3.2.
ehsanullahjan

17
Bagaimana dengan properti kosong my.list.of.strings=? Saya harapkan fungsi seperti itu menyusun kembali daftar kosong di mana ini akan menjadi satu item (string kosong), bukan?
Jan Zyka

5
Perhatikan juga bahwa solusi yang disarankan tidak melakukan pemangkasan sehingga nilai seperti item1, item2, item3dapat memberi Anda hasil yang tidak Anda harapkan (petunjuk: spasi).
Jan Zyka

4
Jika Anda perlu memangkas ruang kosong gunakan regex untuk argumen split .. sesuatu seperti@Value("#{'${my.list.of.strings}'.split(',\\s*')}")
Stackee007

88

Sejak Spring 3.0, Anda dapat menambahkan garis seperti

<bean id="conversionService" 
    class="org.springframework.context.support.ConversionServiceFactoryBean" />

ke applicationContext.xml(atau di mana Anda mengkonfigurasi hal-hal). Seperti yang ditunjukkan Dmitry Chornyi dalam komentar, konfigurasi berbasis Java terlihat seperti:

@Bean public ConversionService conversionService() {
    return new DefaultConversionService();
}

Ini mengaktifkan layanan konfigurasi baru yang mendukung konversi Stringke Collectiontipe. Jika Anda tidak mengaktifkan layanan konfigurasi ini, Spring mengandalkan editor properti lawasnya sebagai layanan konfigurasi, yang tidak mendukung konversi semacam ini.

Konversi ke koleksi jenis lain juga berfungsi:

@Value("${my.list.of.ints}")
private List<Integer> myList

akan bekerja dengan garis seperti

 my.list.of.ints= 1, 2, 3, 4

Tidak ada masalah dengan spasi putih di sana, ConversionServiceFactoryBeanmengurusnya.

Lihat http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#core-convert-Spring-config

Dalam aplikasi Musim Semi, Anda biasanya mengonfigurasi instance ConversionService per wadah Spring (atau ApplicationContext). ConversionService itu akan diambil oleh Spring dan kemudian digunakan setiap kali konversi tipe perlu dilakukan oleh framework. [...] Jika tidak ada ConversionService terdaftar dengan Spring, sistem berbasis PropertyEditor asli digunakan.


6
Konfigurasi Java: @Bean Public ConversionService ConversionService () {mengembalikan DefaultConversionService (); }
Dmitry Chornyi

2
Di luar menghindari untuk mengulangi diri Anda dengan split()dalam setiap ekspresi, itu juga benar menangani daftar kosong bukannya memberi Anda[null]
Didier L

Ini tidak berfungsi jika properti
diganti

47

Jika Anda membaca ini dan Anda menggunakan Spring Boot , Anda memiliki 1 opsi lagi untuk fitur ini

Biasanya daftar yang dipisahkan koma sangat canggung untuk kasus penggunaan dunia nyata (Dan kadang-kadang bahkan tidak layak, jika Anda ingin menggunakan koma di konfigurasi Anda):

email.sendTo=somebody@example.com,somebody2@example.com,somebody3@example.com,.....

Dengan Spring Boot , Anda dapat menulis seperti ini (Indeks mulai dari 0):

email.sendTo[0]=somebody@example.com
email.sendTo[1]=somebody2@example.com
email.sendTo[2]=somebody3@example.com

Dan gunakan seperti ini:

@Component
@ConfigurationProperties("email")
public class EmailProperties {

    private List<String> sendTo;

    public List<String> getSendTo() {
        return sendTo;
    }

    public void setSendTo(List<String> sendTo) {
        this.sendTo = sendTo;
    }

}


@Component
public class EmailModel {

  @Autowired
  private EmailProperties emailProperties;

  //Use the sendTo List by 
  //emailProperties.getSendTo()

}



@Configuration
public class YourConfiguration {
    @Bean
  public EmailProperties emailProperties(){
        return new EmailProperties();
  }

}


#Put this in src/main/resource/META-INF/spring.factories
  org.springframework.boot.autoconfigure.EnableAutoConfiguration=example.compackage.YourConfiguration

Saya memiliki masalah ketika solusi lain yang dijelaskan di sini tidak berfungsi karena koma yang lolos tidak dapat dikenali. Apakah ada cara untuk melakukan solusi ini dengan Spring 4?
sandrozbinden

34

Dengan menentukan my.list.of.strings=ABC,CDE,EFGfile in .properties dan menggunakan

@Value("${my.list.of.strings}") private String[] myString;

Anda bisa mendapatkan array string. Dan menggunakan CollectionUtils.addAll(myList, myString), Anda bisa mendapatkan daftar string.


Saya hanya mendapatkan String pertama "ABC"
Osama Abdulsattar

19

Sudahkah Anda mempertimbangkan @Autowiredkonstruktor atau setter dan String.split()ing dalam tubuh?

class MyClass {
    private List<String> myList;

    @Autowired
    public MyClass(@Value("${my.list.of.strings}") final String strs) {
        myList = Arrays.asList(strs.split(","));
    }

    //or

    @Autowired
    public void setMyList(@Value("${my.list.of.strings}") final String strs) {
        myList = Arrays.asList(strs.split(","));
    }
}

Saya cenderung lebih suka melakukan autowiring saya dalam salah satu cara ini untuk meningkatkan testabilitas kode saya.


14

Jika Anda menggunakan Spring Boot 2, itu berfungsi apa adanya, tanpa konfigurasi tambahan.

my.list.of.strings=ABC,CDE,EFG

@Value("${my.list.of.strings}")
private List<String> myList;

tidak bekerja untuk saya, saya harus menggunakan Spring EL seperti yang ditunjukkan di atas.
Bilbo Baggins

atau bahkanprivate List<String> myList;
Halayem Anis

Ya itu bekerja untuk saya juga: Saya menggunakan Spring Boot 2.2.6
Ankit

8

Semua jawaban di atas benar. Tetapi Anda dapat mencapai ini hanya dalam satu baris. Silakan coba deklarasi berikut ini dan Anda akan mendapatkan semua nilai yang dipisahkan koma dalam daftar String.

private @Value("#{T(java.util.Arrays).asList(projectProperties['my.list.of.strings'])}") List<String> myList;

Dan juga Anda harus memiliki baris berikut yang ditentukan dalam konfigurasi xml Anda.

<util:properties id="projectProperties" location="/project.properties"/>

cukup ganti jalur dan nama file dari file properti Anda. Dan Anda baik untuk pergi. :)

Semoga ini bisa membantu Anda. Bersulang.


1
Ini berhasil untuk saya, tetapi saya harus mengucapkan anotasi seperti ini:@Value("#{T(java.util.Arrays).asList('${my.list.of.strings}')}")
Steven

6

Jika Anda menggunakan versi Spring framework terbaru (Spring 3.1+ saya percaya), Anda tidak perlu hal-hal string split di SpringEL,

Cukup tambahkan PropertySourcesPlaceholderConfigurer dan DefaultConversionService di kelas Konfigurasi Spring Anda (yang dengan penjelasan dengan Konfigurasi) misalnya,

@Configuration
public class AppConfiguration {

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }

    @Bean public ConversionService conversionService() {
        return new DefaultConversionService();
    }
}

dan di kelasmu

@Value("${list}")
private List<String> list;

dan di file properti

list=A,B,C,D,E

Tanpa DefaultConversionService, Anda hanya dapat mengambil String yang dipisahkan koma ke dalam array String ketika Anda menyuntikkan nilai ke bidang Anda, tetapi DefaultConversionService melakukan beberapa keajaiban yang mudah bagi Anda dan akan menambahkannya ke dalam Collection, Array, dll. (Periksa implementasinya jika Anda ingin ingin tahu lebih banyak tentang itu)

Dengan keduanya, ini bahkan menangani semua spasi putih berlebihan termasuk baris baru, jadi Anda tidak perlu menambahkan logika tambahan untuk memotongnya.


Penambahan konfigurasi ini berfungsi tetapi sesuatu yang aneh terjadi: Saya tidak dapat menggunakan @ Nilai untuk tipe File, saya harus mengubah File dengan Sumber Daya.
ad3luc

2

Anda dapat melakukan ini dengan anotasi seperti ini

 @Value("#{T(java.util.Arrays).asList('${my.list.of.strings:a,b,c}')}") 
    private List<String> mylist;

di sini my.list.of.strings akan diambil dari file properti, jika tidak ada, maka default a, b, c akan digunakan

dan di file properti Anda, Anda dapat memiliki sesuatu seperti ini

my.list.of.strings = d, e, f


2

Waspadalah terhadap spasi dalam nilai. Saya bisa saja salah, tapi saya pikir spasi di daftar yang dipisahkan koma tidak terpotong menggunakan @Value dan Spel. Daftar

foobar=a, b, c

akan dibaca sebagai daftar string

"a", " b", " c"

Dalam kebanyakan kasus, Anda mungkin tidak ingin spasi!

Ekspresi

@Value("#{'${foobar}'.trim().replaceAll(\"\\s*(?=,)|(?<=,)\\s*\", \"\").split(',')}")
private List<String> foobarList;

akan memberi Anda daftar string:

"a", "b", "c".

Ekspresi reguler menghapus semua spasi sebelum dan sesudah koma. Spasi di dalam nilai tidak dihapus. Begitu

foobar = AA, B B, CCC

harus menghasilkan nilai

"AA", "B B", "CCC".

Metode split () menggunakan regex internal sebagai pembatas, sehingga contoh Anda dapat disederhanakan: <br/>@Value("#{'${foobar}'.trim().split( *, *)}")
Karlik_B

2

Saya pikir ini lebih mudah untuk meraih array dan stripping space:

@Value("#{'${my.array}'.replace(' ', '').split(',')}")
private List<String> array;

2

Dalam kasus saya daftar bilangan bulat berfungsi sebagai berikut:

@Value("#{${my.list.of.integers}}")
private List<Integer> listOfIntegers;

File properti:

my.list.of.integers={100,200,300,400,999}

atau @Value ("# {$ {my.set.of.integers}}") set pribadi <Integer> setOfIntegers;
Alexey Simonov

1

Pertimbangkan untuk menggunakan Konfigurasi Commons. Ini memiliki fitur bawaan untuk memecah entri dalam file properti ke array / daftar. Menyisir dengan SpEL dan @Value akan memberikan apa yang Anda inginkan


Seperti yang diminta, inilah yang Anda butuhkan (Belum benar-benar mencoba kode, mungkin mendapat beberapa kesalahan ketik, mohon ikut saya):

Di Konfigurasi Apache Commons, ada PropertiesConfiguration. Ini mendukung fitur konversi string terbatas ke array / daftar.

Misalnya, jika Anda memiliki file properti

#Foo.properties
foo=bar1, bar2, bar3

Dengan kode di bawah ini:

PropertiesConfiguration config = new PropertiesConfiguration("Foo.properties");
String[] values = config.getStringArray("foo");

akan memberi Anda array string ["bar1", "bar2", "bar3"]

Untuk digunakan dengan Spring, dapatkan ini dalam konteks aplikasi Anda xml:

<bean id="fooConfig" class="org.apache.commons.configuration.PropertiesConfiguration">
    <constructor-arg type="java.lang.String" value="classpath:/Foo.properties"/>
</bean>

dan memilikinya di kacang musim semi Anda:

public class SomeBean {

    @Value("fooConfig.getStringArray('foo')")
    private String[] fooArray;
}

Saya percaya ini harus berhasil: P


dapatkah Anda lebih spesifik tentang metode dan kelas yang akan digunakan, dan sniplet kode sampel aktual akan lebih bagus.
JackDev

1

Cara pilihan saya (untuk string, khususnya), adalah yang berikut:

admin.user={'Doe, John','Headroom, Max','Mouse, Micky'}

dan gunakan

@Value("#{${admin.user}}")
private List<String> userList;

Dengan cara ini, Anda dapat memasukkan juga koma di parameter Anda. Ini juga berfungsi untuk Set.


0

jika menggunakan placeholder properti maka contoh ser1702544 akan menjadi

@Value("#{myConfigProperties['myproperty'].trim().replaceAll(\"\\s*(?=,)|(?<=,)\\s*\", \"\").split(',')}") 

Dengan placeholder xml:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">   
    <property name="properties" ref="myConfigProperties" />
    <property name="placeholderPrefix"><value>$myConfigProperties{</value></property>
</bean>    

<bean id="myConfigProperties" class="org.springframework.beans.factory.config.PropertiesFactoryBean">
     <property name="locations">
         <list>
                <value>classpath:myprops.properties</value>
         </list>
     </property>
</bean> 

0

Saya menggunakan Spring Boot 2.2.6

File properti saya:

usa.big.banks= JP Morgan, Wells Fargo, Citigroup, Morgan Stanley, Goldman Sachs

Kode saya:

@Value("${usa.big.banks}")
    private List<String> bigBanks;

@RequestMapping("/bigbanks")
    public String getBanks() {
        System.out.println("bigBanks = " + bigBanks);
        return bigBanks.toString();
    }

Ini bekerja dengan baik

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.