Читання списку з файлу властивостей та завантаження весняної анотації @Value


244

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

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

І завантажувати його безпосередньо в мій клас, тобто:

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

Як я розумію, альтернатива цього - це мати його у весняному конфігураційному файлі та завантажити його як посилання на бін (виправте мене, якщо я помиляюся), тобто

<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
Чудово працює з весною 3.2.
ehsanullahjan

17
Як щодо порожнього майна my.list.of.strings=? Я б очікував, що така функціональність відновлює порожній список, де тут буде один елемент (порожній рядок), чи не так?
Jan Zyka

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

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

88

З весни 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 буде взята весною, а потім використана всякий раз, коли конверсію типу потрібно виконати в рамках. [...] Якщо жодна програма ConversionService не зареєстрована у Spring, використовується оригінальна система на базі PropertyEditor.


6
Конфігурація Java: @Bean public ConversionService convertService () {повернути новий 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?
sandrozbinden

34

Вказавши my.list.of.strings=ABC,CDE,EFGфайл in .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

Якщо ви використовуєте останню версію весняної рамки (я вважаю, весна 3.1+), вам не потрібно буде використовувати ці розділові елементи в SpringEL,

Просто додайте PropertySourcesPlaceholderConfigurer та DefaultConversionService у свій клас Конфігурація весни (той, на якому зазначено конфігурацію), наприклад,

@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 = d, e, f


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}}") приватний набір <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.