Чтение списка из файла свойств и загрузка с весенней аннотацией @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: Я хотел бы сделать это без любого пользовательского кода, если это возможно.

JackDev
источник

Ответы:

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

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

nicholas.hauschild
источник
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 и т. Д. (Проверьте реализацию, если хотите хотел бы узнать больше об этом)

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

wonhee
источник
Добавление этой конфигурации работает, но происходит нечто странное: я не могу использовать @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".
DAMungra
источник
Метод 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;

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

Sampisa
источник
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> 
cgull
источник
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();
    }

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

Анкит
источник