Đọc Danh sách từ tệp thuộc tính và tải với chú thích mùa xuân @Value


244

Tôi muốn có một danh sách các giá trị trong tệp .properations, tức là:

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

Và để tải nó trực tiếp trong lớp của tôi, tức là:

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

Theo tôi hiểu, một cách khác để làm điều này là có nó trong tệp cấu hình mùa xuân và tải nó dưới dạng tham chiếu bean (sửa tôi nếu tôi sai), tức là

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

Nhưng có cách nào để làm điều này? sử dụng tập tin .properations? ps: Tôi muốn làm điều này với bất kỳ mã tùy chỉnh nào nếu có thể.

Câu trả lời:


453

Sử dụng EL mùa xuân:

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

Giả sử tệp thuộc tính của bạn được tải chính xác với các mục sau:

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

1
Tôi đã kiểm tra lại bằng cách sử dụng cùng một phiên bản bạn đang sử dụng. Sao chép Spring EL chính xác như trong bài và nó hoạt động. Điều khác biệt là nếu tôi mắc lỗi trong EL của tôi, tôi có org.springframework.expression.spel.SpelEvaluationExceptionngoại lệ và không javax.el.ELException. Là đối tượng của bạn được tạo ra bởi Spring?
Wilhelm Kleu

1
Hoạt động hoàn hảo với Spring 3.2.
ehsanullahjan

17
Làm thế nào về tài sản trống my.list.of.strings=? Tôi mong đợi chức năng như vậy lấy lại danh sách trống, ở đây nó sẽ là một mục (chuỗi trống), phải không?
Jan Zyka

5
Cũng lưu ý rằng giải pháp được đề xuất không thực hiện cắt xén để các giá trị như item1, item2, item3có thể mang lại cho bạn kết quả mà bạn không thực sự mong đợi (gợi ý: dấu cách).
Jan Zyka

4
Nếu bạn cần cắt bớt các khoảng trống, hãy sử dụng regex cho đối số phân tách .. đại loại như@Value("#{'${my.list.of.strings}'.split(',\\s*')}")
Stackee007

88

Kể từ mùa xuân 3.0, bạn có thể thêm một dòng như

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

đến của bạn applicationContext.xml(hoặc nơi bạn định cấu hình mọi thứ). Như Dmitry Chornyi chỉ ra trong một nhận xét, cấu hình dựa trên Java trông giống như:

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

Điều này kích hoạt dịch vụ cấu hình mới hỗ trợ chuyển đổi Stringthành Collectioncác loại. Nếu bạn không kích hoạt dịch vụ cấu hình này, Spring sẽ quay lại các trình soạn thảo thuộc tính kế thừa của nó dưới dạng dịch vụ cấu hình, không hỗ trợ loại chuyển đổi này.

Chuyển đổi sang bộ sưu tập các loại khác cũng hoạt động:

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

sẽ làm việc với một dòng như

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

Không có vấn đề với khoảng trắng ở đó, ConversionServiceFactoryBeanchăm sóc nó.

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

Trong một ứng dụng Spring, bạn thường định cấu hình một phiên bản Dịch vụ chuyển đổi cho mỗi bộ chứa Spring (hoặc ApplicationContext). Dịch vụ chuyển đổi đó sẽ được Spring chọn và sau đó được sử dụng bất cứ khi nào một chuyển đổi loại cần được thực hiện bởi khung. [...] Nếu không có Dịch vụ chuyển đổi nào được đăng ký với Spring, hệ thống dựa trên PropertyEditor ban đầu sẽ được sử dụng.


6
Cấu hình Java: @Bean công khai ConvertService convertService () {trả về DefaultConversionService (); }
Dmitry Chornyi

2
Bên ngoài tránh lặp lại chính mình split()trong mọi biểu hiện, nó cũng xử lý đúng một danh sách trống thay vì đưa cho bạn[null]
Didier L

Nó không hoạt động nếu tài sản bị ghi đè (Tồn tại nhiều nguồn tài sản.)
Daniel Hári

47

Nếu bạn đang đọc cái này và bạn đang sử dụng Spring Boot , bạn có thêm 1 tùy chọn cho tính năng này

Thông thường danh sách được phân tách bằng dấu phẩy rất vụng về cho trường hợp sử dụng trong thế giới thực (Và đôi khi thậm chí không khả thi, nếu bạn muốn sử dụng dấu phẩy trong cấu hình của mình):

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

Với Spring Boot , bạn có thể viết nó như thế này (Chỉ số bắt đầu từ 0):

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

Và sử dụng nó như thế này:

@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

Tôi có một vấn đề trong đó các giải pháp khác được mô tả ở đây không hoạt động do dấu phẩy thoát không được ghi nhận. Có cách nào để thực hiện giải pháp này với Spring 4 không?
sandrozbinden

34

Bằng cách chỉ định my.list.of.strings=ABC,CDE,EFGtệp trong .properations và sử dụng

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

Bạn có thể nhận được các chuỗi của chuỗi. Và bằng cách sử dụng CollectionUtils.addAll(myList, myString), bạn có thể nhận được danh sách các chuỗi.


Tôi chỉ nhận được Chuỗi "ABC" đầu tiên
Osama Abdulsattar

19

Bạn đã xem xét @Autowireding constructor hoặc setter và String.split()ing trong cơ thể?

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(","));
    }
}

Tôi có xu hướng thích thực hiện tự động theo một trong những cách sau để tăng cường khả năng kiểm tra mã của tôi.


14

Nếu bạn đang sử dụng Spring Boot 2, nó hoạt động như bình thường, không có bất kỳ cấu hình bổ sung nào.

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

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

không làm việc cho tôi, tôi phải sử dụng Spring EL như hình trên.
Bilbo Baggins

hoặc thậm chíprivate List<String> myList;
Halayem Anis

Có, nó cũng hoạt động với tôi: Tôi đang sử dụng Spring Boot 2.2.6
Ankit

8

Tất cả các câu trả lời trên là chính xác. Nhưng bạn có thể đạt được điều này chỉ trong một dòng. Vui lòng thử khai báo sau và bạn sẽ nhận được tất cả các giá trị được phân tách bằng dấu phẩy trong danh sách Chuỗi.

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

Và bạn cũng cần phải có dòng sau được định nghĩa trong cấu hình xml của bạn.

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

chỉ cần thay thế đường dẫn và tên tệp của tệp thuộc tính của bạn. Và bạn tốt để đi. :)

Hy vọng điều này sẽ giúp bạn. Chúc mừng.


1
Điều này làm việc cho tôi, nhưng tôi phải diễn đạt chú thích như thế này:@Value("#{T(java.util.Arrays).asList('${my.list.of.strings}')}")
Steven

6

Nếu bạn đang sử dụng phiên bản khung công tác Spring mới nhất (Spring 3.1+ tôi tin), bạn không cần phải sử dụng các công cụ phân tách chuỗi trong SpringEL,

Chỉ cần thêm PropertySourcePlaceholderConfigker và DefaultConversionService trong lớp Cấu hình của Spring (lớp có chú thích với Cấu hình), vd

@Configuration
public class AppConfiguration {

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

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

và trong lớp học của bạn

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

và trong tệp thuộc tính

list=A,B,C,D,E

Nếu không có DefaultConversionService, bạn chỉ có thể lấy Chuỗi được phân tách bằng dấu phẩy thành mảng Chuỗi khi bạn đưa giá trị vào trường của mình, nhưng DefaultConversionService thực hiện một số phép thuật thuận tiện cho bạn và sẽ thêm chúng vào Bộ sưu tập, Mảng, v.v. (kiểm tra việc triển khai nếu bạn muốn biết thêm về nó)

Với hai cái này, nó thậm chí còn xử lý tất cả các khoảng trắng thừa bao gồm cả dòng mới, vì vậy bạn không cần thêm logic để cắt chúng.


Việc thêm cấu hình này đang hoạt động nhưng có một điều kỳ lạ xảy ra: Tôi không thể sử dụng @Value cho loại Tệp, tôi phải thay đổi Tệp bằng Tài nguyên.
ad3luc

2

bạn có thể làm điều này với các chú thích như thế này

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

ở đây my.list.of.strings sẽ được chọn từ tệp thuộc tính, nếu nó không ở đó, thì mặc định a, b, c sẽ được sử dụng

và trong tệp thuộc tính của bạn, bạn có thể có một cái gì đó như thế này

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


2

Coi chừng không gian trong các giá trị. Tôi có thể sai, nhưng tôi nghĩ các khoảng trắng trong danh sách được phân tách bằng dấu phẩy không được cắt bớt bằng cách sử dụng @Value và Spel. Danh sách

foobar=a, b, c

sẽ được đọc trong một danh sách các chuỗi

"a", " b", " c"

Trong hầu hết các trường hợp, bạn có thể sẽ không muốn không gian!

Cách diễn đạt

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

sẽ cung cấp cho bạn một danh sách các chuỗi:

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

Biểu thức chính quy sẽ loại bỏ tất cả các khoảng trắng ngay trước và ngay sau dấu phẩy. Không gian bên trong các giá trị không bị xóa. Vì thế

foobar = AA, B B, CCC

nên dẫn đến giá trị

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

Phương thức split () sử dụng regex bên trong làm dấu phân cách, vì vậy ví dụ của bạn có thể được đơn giản hóa: <br/>@Value("#{'${foobar}'.trim().split( *, *)}")
Karlik_B

2

Tôi nghĩ rằng điều này là đơn giản hơn để lấy mảng và tước không gian:

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

2

Trong trường hợp của tôi một danh sách các số nguyên hoạt động này:

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

Hồ sơ tài sản:

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

hoặc @Value ("# {$ {my.set.of.integers}}") Đặt riêng tư <Integer> setOfIntegers;
Alexey Simonov

1

Xem xét sử dụng Cấu hình Commons. Nó có tính năng tích hợp để ngắt một mục trong tệp thuộc tính thành mảng / danh sách. Kết hợp với SpEL và @Value sẽ cung cấp những gì bạn muốn


Theo yêu cầu, đây là những gì bạn cần (Không thực sự đã thử mã, có thể có một số lỗi đánh máy, xin vui lòng chịu đựng với tôi):

Trong Cấu hình Apache Commons, có PropertiesConfiguration. Nó hỗ trợ tính năng chuyển đổi chuỗi phân tách thành mảng / danh sách.

Ví dụ: nếu bạn có tệp thuộc tính

#Foo.properties
foo=bar1, bar2, bar3

Với mã dưới đây:

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

sẽ cung cấp cho bạn một chuỗi chuỗi ["bar1", "bar2", "bar3"]

Để sử dụng với Spring, có cái này trong ngữ cảnh ứng dụng của bạn xml:

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

và có cái này trong đậu mùa xuân của bạn:

public class SomeBean {

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

Tôi tin rằng điều này sẽ làm việc: P


bạn có thể cụ thể hơn về phương thức và lớp để sử dụng không, và sniplet mã mẫu thực tế sẽ rất tuyệt.
JackDev

1

Cách ưa thích của tôi (cụ thể là các chuỗi), là cách sau:

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

Và sử dụng

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

Theo cách này, bạn cũng có thể bao gồm dấu phẩy trong tham số của mình. Nó cũng hoạt động cho Bộ.


0

nếu sử dụng trình giữ chỗ tài sản thì ví dụ ser1702544 sẽ trở thành

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

Với giữ chỗ 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

Tôi đang sử dụng Spring Boot 2.2.6

Hồ sơ tài sản của tôi:

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

Mã của tôi:

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

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

Nó hoạt động tốt

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.