Чтение списка из файла свойств и загрузка с весенней аннотацией @Value


244

Я хочу иметь список значений в файле .properties, а именно:

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

И загрузить это в моем классе непосредственно, то есть:

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

Как я понимаю, альтернативой для этого является включение его в конфигурационный файл Spring и загрузка его в качестве ссылки на компонент (поправьте меня, если я ошибаюсь), т.е.

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

Но есть ли способ сделать это? используя файл .properties? PS: Я хотел бы сделать это без любого пользовательского кода, если это возможно.

Ответы:


454

Используя Spring EL:

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

Предполагая, что ваш файл свойств загружен правильно со следующим:

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

1
Я проверил это снова, используя ту же версию, которую вы используете. Скопировал Spring EL точно так же как в посте и все работает. Что отличается, хотя, если я делаю ошибку в моем EL, я получаю org.springframework.expression.spel.SpelEvaluationExceptionисключение и нет javax.el.ELException. Ваш возражение создано весной?
Вильгельм Клеу

1
Отлично работает с Spring 3.2.
ehsanullahjan

17
Как насчет пустой собственности my.list.of.strings=? Я ожидаю, что такая функциональность перезапускает пустой список, где здесь будет один элемент (пустая строка), не так ли?
Ян Зыка

5
Также обратите внимание, что предлагаемое решение не выполняет обрезку, поэтому такие значения item1, item2, item3могут дать результат, которого вы не ожидаете (подсказка: пробелы).
Ян Зыка

4
Если вам нужно обрезать пустые места, используйте регулярное выражение для разделения аргумента .. что-то вроде@Value("#{'${my.list.of.strings}'.split(',\\s*')}")
Stackee007

89

Начиная с Spring 3.0, вы можете добавить строку вроде

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

на ваш applicationContext.xml(или где вы настраиваете вещи). Как отмечает Дмитрий Чорный в комментарии, конфигурация на основе Java выглядит следующим образом:

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

Это активирует новую службу конфигурации, которая поддерживает преобразование Stringв Collectionтипы. Если вы не активируете эту службу конфигурации, Spring вернется к своим прежним редакторам свойств в качестве служб конфигурации, которые не поддерживают этот вид преобразования.

Преобразование в коллекции других типов работ тоже:

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

будет работать с такой строкой

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

Никаких проблем с пробелами нет, об этом ConversionServiceFactoryBeanпозаботятся.

См. Http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#core-convert-Spring-config

В приложении Spring вы обычно настраиваете экземпляр ConversionService для каждого контейнера Spring (или ApplicationContext). Этот ConversionService будет выбран Spring и затем использован всякий раз, когда преобразование типа должно быть выполнено платформой. [...] Если в Spring не зарегистрировано ConversionService, используется исходная система на основе PropertyEditor.


6
Конфигурация Java: @Bean public ConversionService converService () {вернуть новый DefaultConversionService (); }
Дмитрий Черный

2
Помимо того, чтобы избегать повторения split()в каждом выражении, он также правильно обрабатывает пустой список вместо того, чтобы давать вам[null]
Didier L

Это не работает, если свойство переопределено (существует в нескольких источниках собственности.)
Даниэль Хари

47

Если вы читаете это и используете Spring Boot , у вас есть еще 1 опция для этой функции

Обычно разделенные запятыми списки очень неуклюжи для реального случая использования (и иногда даже неосуществимы, если вы хотите использовать запятые в вашей конфигурации):

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

С помощью Spring Boot вы можете написать это так (индекс начинается с 0):

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

И используйте это так:

@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

У меня есть проблема, когда другие решения, описанные здесь, не работают из-за того, что экранированные запятые не распознаются. Есть ли способ сделать это решение с помощью Spring 4?
Сандрозбинден

34

Указав my.list.of.strings=ABC,CDE,EFGв файле .properties и используя

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

Вы можете получить массивы строк. И используя CollectionUtils.addAll(myList, myString), вы можете получить список строк.


Я получаю только первую строку "ABC"
Усама Абдулсаттар

19

Рассматривали ли вы @Autowiredконструктор или сеттер и String.split()тело?

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

Я предпочитаю выполнять автопроводку одним из этих способов, чтобы улучшить тестируемость моего кода.


14

Если вы используете Spring Boot 2, он работает как есть, без какой-либо дополнительной настройки.

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

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

не работает для меня, я должен использовать Spring EL, как показано выше.
Бильбо Бэггинс

или дажеprivate List<String> myList;
Halayem Anis

Да, это сработало и для меня: я использую Spring Boot 2.2.6
Ankit

8

Все приведенные выше ответы верны. Но вы можете достичь этого только в одной строке. Пожалуйста, попробуйте следующее объявление, и вы получите все значения через запятую в списке строк.

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

А также вам нужно иметь следующую строку, определенную в вашей конфигурации xml.

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

просто замените путь и имя вашего файла свойств. И тебе хорошо идти. :)

Надеюсь, это поможет вам. Приветствия.


1
Это сработало для меня, но мне пришлось сформулировать аннотацию следующим образом:@Value("#{T(java.util.Arrays).asList('${my.list.of.strings}')}")
Стивен

6

Если вы используете последнюю версию Spring Framework (Spring 3.1+, я полагаю), вам не нужны эти разделенные строки в SpringEL,

Просто добавьте PropertySourcesPlaceholderConfigurer и DefaultConversionService в свой класс конфигурации Spring (класс с пометкой «Конфигурация»), например,

@Configuration
public class AppConfiguration {

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

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

и в вашем классе

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

и в файле свойств

list=A,B,C,D,E

Без DefaultConversionService вы можете использовать String в массиве String только в том случае, если вы вводите значение в свое поле, но DefaultConversionService выполняет несколько удобных для вас действий и добавляет их в Collection, Array и т. Д. (Проверьте реализацию, если хотите хотел бы узнать больше об этом)

С этими двумя он даже обрабатывает все лишние пробелы, включая символ новой строки, поэтому вам не нужно добавлять дополнительную логику, чтобы обрезать их.


Добавление этой конфигурации работает, но происходит нечто странное: я не могу использовать @Value для Типа файла, я должен изменить Файл с Ресурсом.
ad3luc

2

Вы можете сделать это с помощью аннотаций, как это

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

здесь my.list.of.strings будут выбраны из файла свойств, если его там нет, то будут использоваться значения по умолчанию a, b, c

и в вашем файле свойств, вы можете иметь что-то вроде этого

my.list.of.strings = д, д, е


2

Остерегайтесь пробелов в значениях. Я могу ошибаться, но я думаю, что пробелы в списке через запятую не усекаются с помощью @Value и Spel. Список

foobar=a, b, c

будет читаться как список строк

"a", " b", " c"

В большинстве случаев вы, вероятно, не хотели бы места!

Выражение

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

даст вам список строк:

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

Регулярное выражение удаляет все пробелы непосредственно перед и сразу после запятой. Пробелы внутри значений не удаляются. Так

foobar = AA, B B, CCC

должен привести к значениям

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

Метод split () использует внутреннее регулярное выражение в качестве разделителя, поэтому ваш пример может быть упрощен: <br/>@Value("#{'${foobar}'.trim().split( *, *)}")
Karlik_B

2

Я думаю, что это проще для захвата массива и удаления пробелов:

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

2

В моем случае список целых чисел работает так:

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

Файл свойств:

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

или @Value ("# {$ {my.set.of.integers}}") private Set <Integer> setOfIntegers;
Алексей Симонов

1

Рассмотрите возможность использования Commons Configuration. Он имеет встроенную функцию, чтобы разбить запись в файле свойств в массив / список. Объединение со SpEL и @Value должно дать то, что вы хотите


В соответствии с просьбой, вот что вам нужно (на самом деле не пробовал код, возможно, есть некоторые опечатки, пожалуйста, потерпите меня):

В конфигурации Apache Commons есть PropertiesConfiguration. Он поддерживает функцию преобразования строки с разделителями в массив / список.

Например, если у вас есть файл свойств

#Foo.properties
foo=bar1, bar2, bar3

С кодом ниже:

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

даст вам массив строк ["bar1", "bar2", "bar3"]

Для использования с Spring, имейте это в вашем приложении xml:

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

и имейте это в своем весеннем бобе:

public class SomeBean {

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

Я считаю, что это должно работать: P


Не могли бы вы более подробно рассказать о методе и классе, который вы хотите использовать, и пример фрагмента кода был бы отличным.
JackDev

1

Мой предпочтительный способ (в частности, для строк) следующий:

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

и использовать

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

Таким образом, вы также можете включить запятые в ваш параметр. Это работает также для наборов.


0

если использовать заполнители свойств, то пример ser1702544 станет

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

С заполнителем 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

Я использую Spring Boot 2.2.6

Мой файл свойств:

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

Мой код:

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

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

Работает нормально

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.